Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -1,112 +1,116 @@
Makefile$
Makefile\.in$
\.deps$
\.libs$
\.l[ao]$
\.so$
\.so\.
\.o$
~$
\.pyc$
\.codereplace$
\.orig$
\.tar\.(gz|bz2)$
^autom4te.cache$
^config.herwig$
^config.log$
^config.status$
^configure$
^include/Herwig$
^Config/config.guess$
^Config/config.h$
^Config/config.h.in$
^Config/config.sub$
^Config/depcomp$
^Config/compile$
^Config/install-sh$
^Config/missing$
^Config/stamp-h1$
^Config/ar-lib$
^Contrib/make_makefiles.sh$
^Contrib/.*/.*\.(log|out|tex|run)$
^Utilities/hgstamp.inc$
^Doc/HerwigDefaults.in$
^Doc/refman-html$
^Doc/fixinterfaces.pl$
^Doc/refman.conf$
^Doc/refman.h$
^Doc/AllInterfaces.h$
^Doc/HerwigDefaults.rpo$
^Doc/Herwig-refman.tag$
^Doc/tagfileThePEG.tag$
^Doc/.*\.log$
^INSTALL$
^aclocal.m4$
^confdefs.h$
^conftest.c$
^conftest.err$
^include/done-all-links$
^libtool$
\.dirstamp$
^src/hgstamp.inc$
^src/herwigopts.h$
^src/herwigopts.c$
^src/defaults/Analysis.in$
^src/defaults/Decays.in$
^src/defaults/decayers.in$
^src/herwig-config$
^src/.*\.(run|tex|out|log|rpo|spc|top|dump|dot|aux|pdf|ps|png|svg|hepmc|dvi)$
^src/Makefile-UserModules$
^lib/done-all-links$
^lib/apple-fixes$
^src/defaults/PDF.in$
^src/defaults/done-all-links$
^src/tune$
^src/Herwig$
^src/Herwig-cache$
^src/tests/.*\.(time|mult|Bmult|chisq)$
^src/Merging/test/*yoda
^src/Merging/test/Herwig*
^src/Merging/test/L*
^src/Merging/test/done-all-links
^src/Merging/done-all-links
^Tests/.*/.*\.(top|ps|pyc|info|dat|pdf|png)$
^Tests/.*\.(top|ps|pyc|info|dat|pdf|png|log|out)$
^Tests/.*\.(top|run|tex|mult|Bmult|aida|yoda)$
^Tests/Rivet-.*$
^Tests/.cache$
^Tests/Rivet/(LEP|DIS|LHC|TVT|Star|BFactory|ISR|SppS)-.*\.in$
^Tests/plots$
^Tests/Herwig$
^Tests/.*index.html$
+PDF/SaSPhotonPDF.cc
^Herwig\-
^Models/Feynrules/python/Makefile-FR$
^MatrixElement/Matchbox/External/MadGraph/mg2herwig$
^MatrixElement/Matchbox/Scales/MatchboxScale.cc$
^Utilities/Statistics/herwig-combinedistributions$
^Utilities/Statistics/herwig-combineruns$
^Utilities/Statistics/herwig-makedistributions$
^src/defaults/MatchboxDefaults.in$
^src/defaults/setup.gosam.in$
^src/Matchbox/LO-DefaultShower.in$
^src/Matchbox/LO-DipoleShower.in$
^src/Matchbox/LO-NoShower.in$
^src/Matchbox/MCatLO-DefaultShower.in$
^src/Matchbox/MCatLO-DipoleShower.in$
^src/Matchbox/MCatNLO-DefaultShower.in$
^src/Matchbox/MCatNLO-DipoleShower.in$
^src/Matchbox/NLO-NoShower.in$
^src/Matchbox/Powheg-DefaultShower.in$
^src/Matchbox/Powheg-DipoleShower.in$
^src/defaults/MatchboxMergingDefaults.in
^src/Matchbox/done-all-links$
^src/snippets/done-all-links$
^Utilities/XML/xml_test$
^Utilities/utilities_test$
^Utilities/versionstring.h$
+^MatrixElement/Matchbox/External/MadGraph/mg2herwig.py$
test\.(log|trs)$
test-suite\.log$
^Config/test-driver$
param_card\.dat$
__all.cc$
.ccR$
+^tmp/*
+PDF/stamp-h2
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -1,26 +1,27 @@
168ae2110e964d62fbc1331a1c2e095952a67748 release-2-5-2
3abb4fa42e20e332796c2572334c2d77204cd0e0 release-2-4-2
4796ca080aafd5daa3b7349b015cb1df944428a2 release-2-5-0
76da042f056eb153981b4d005d5474ffb90a5e88 release-2-4-1
81a684a558413c69df314365eabf09893ffd43d8 release-2-6-0
bd75cd00d99f4bdbaed992daf98f0a73c0f91e9b release-2-4-0
ff6ecc8d49ce10299303b050394bd5cb5837f1c3 release-2-5-1
d0389f5453b2c210923e1adc7b872b18269de668 release-2-6-1
f8998033021185942533b824607285feb3fbd2dc release-2-6-1a
cead23e428b9aacaf2d709e722624e54f844498b release-2-6-1b
191db4655439045f912cb21bd905e729d59ec7bc release-2-6-2
edb538156e9c3d64bb842934b4cebf0126aeb9ea release-2-6-3
eb4a104591859ecac18746b1ad54d6aa0c2a5d1a release-2-7-0
568971ac5b3c1d044c9259f2280a8304fc5a62e9 trunk-before-QED
6e3edb6cfeb4ee48687eb4eb3d016026fc59d602 trunk-after-QED
633abb80b571aa23088957df60e9b0000bbb8a22 release-2-7-1
1bdde095d2346c15ee548e5406a96f0fc6d6e0f1 beforeHQ
a0f9fb821396092bdbeee532bcb0bd624f58335b before_MB_merge
270c1e6b34aa7f758f1d9868c4d3e1ec4bf4e709 herwig-7-0-0
6e0f198c1c2603ecd1a0b6cfe40105cda4bd58c5 herwig-7-0-1
566c1de845a8070559cda45b1bdb40afa18cb2cc herwig-7-0-2
f5c4aa956880f2def763ebd57de7b5bfa55cb1db herwig-7-0-3
65282dedfc2e4bec184e68678dbf4c553c968f38 herwig-7-0-4
541e7790b65ed423c86780bf66ec30e6b99b5a18 herwig-7-1-0
dd35a1c12d57c047169e8c5fb18644972d49c6ac herwig-7-1-1
0d651b079756b63713e32a1341d81e4dfc7eeb7b herwig-7-1-2
+4b97934bc41c861c4be04f563ffa68a94a982560 herwig-7-1-3
diff --git a/AUTHORS b/AUTHORS
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,56 +1,56 @@
================================================================================
-Herwig 7.1.2
+Herwig 7.1.3
================================================================================
Please contact <herwig@projects.hepforge.org> for any queries.
--------------------------------------------------------------------------------
Herwig is actively developed by:
--------------------------------------------------------------------------------
Johannes Bellm
Stefan Gieseke
David Grellscheid
Patrick Kirchgaeßer
-Frashër Loshaj
Graeme Nail
Andreas Papaefstathiou
Simon Plätzer
Radek Podskubka
Michael Rauch
Christian Reuschle
Peter Richardson
-Peter Schichtel
Mike Seymour
Andrzej Siödmok
Stephen Webster
--------------------------------------------------------------------------------
Former authors are:
--------------------------------------------------------------------------------
Ken Arnold
Manuel Bähr
Luca d'Errico
Martyn Gigg
Nadine Fischer
Keith Hamilton
Marco A. Harrendorf
Seyi Latunde-Dada
+Frashër Loshaj
Daniel Rauch
Alberto Ribon
Christian Röhr
Pavel Růžička
+Peter Schichtel
Alex Schofield
Thomas Schuh
Alexander Sherstnev
Philip Stephens
Martin Stoll
Louise Suter
Jon Tully
Bryan Webber
Alix Wilcock
David Winn
Benedikt Zimmermann
diff --git a/Decay/DecayPhaseSpaceChannel.cc b/Decay/DecayPhaseSpaceChannel.cc
--- a/Decay/DecayPhaseSpaceChannel.cc
+++ b/Decay/DecayPhaseSpaceChannel.cc
@@ -1,603 +1,603 @@
// -*- C++ -*-
//
// DecayPhaseSpaceChannel.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DecayPhaseSpaceChannel class.
//
// Author: Peter Richardson
//
#include "DecayPhaseSpaceChannel.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "DecayPhaseSpaceMode.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ParVector.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Switch.h"
#include <ThePEG/Repository/CurrentGenerator.h>
using namespace Herwig;
DecayPhaseSpaceChannel::DecayPhaseSpaceChannel(tcDecayPhaseSpaceModePtr in)
: _mode(in) {}
void DecayPhaseSpaceChannel::persistentOutput(PersistentOStream & os) const {
os << _intpart << _jactype << ounit(_intmass,GeV) << ounit(_intwidth,GeV)
<< ounit(_intmass2,GeV2) << ounit(_intmwidth,GeV2) << _intpower
<< _intdau1 << _intdau2 << _intext << _mode;
}
void DecayPhaseSpaceChannel::persistentInput(PersistentIStream & is, int) {
is >> _intpart >> _jactype >> iunit(_intmass,GeV) >> iunit(_intwidth,GeV)
>> iunit(_intmass2,GeV2) >> iunit(_intmwidth,GeV2) >> _intpower
>> _intdau1 >> _intdau2 >> _intext >> _mode;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<DecayPhaseSpaceChannel,Interfaced>
describeHerwigDecayPhaseSpaceChannel("Herwig::DecayPhaseSpaceChannel", "Herwig.so");
void DecayPhaseSpaceChannel::Init() {
static RefVector<DecayPhaseSpaceChannel,ParticleData> interfaceIntermediateParticles
("IntermediateParticles",
"The intermediate particles in the decay chain.",
&DecayPhaseSpaceChannel::_intpart, 0, false, false, true, false);
static ParVector<DecayPhaseSpaceChannel,int> interfacejactype
("Jacobian",
"The type of Jacobian to use for the intermediate particle",
&DecayPhaseSpaceChannel::_jactype,
0, 0, 0, 0, 1, false, false, true);
static ParVector<DecayPhaseSpaceChannel,double> interfaceIntermediatePower
("IntermediatePower",
"The power to use in the Jacobian",
&DecayPhaseSpaceChannel::_intpower,
0, 0, 0, -10, 10, false, false, true);
static ParVector<DecayPhaseSpaceChannel,int> interfaceIntermediateDau1
("IntermediateDaughter1",
"First Daughter of the intermediate",
&DecayPhaseSpaceChannel::_intdau1,
0, 0, 0, -10, 10, false, false, true);
static ParVector<DecayPhaseSpaceChannel,int> interfaceIntermediateDau2
("IntermediateDaughter2",
"Second Daughter of the intermediate",
&DecayPhaseSpaceChannel::_intdau2,
0, 0, 0, -10, 10, false, false, true);
static ClassDocumentation<DecayPhaseSpaceChannel> documentation
("The DecayPhaseSpaceChannel class defines a channel"
" for the multichannel integration of the phase space for a decay.");
}
// generate the momenta of the external particles
vector<Lorentz5Momentum>
DecayPhaseSpaceChannel::generateMomenta(const Lorentz5Momentum & pin,
const vector<Energy> & massext) {
// integers for loops
unsigned int ix,iy,idau[2],iz;
// storage of the momenta of the external particles
vector<Lorentz5Momentum> pexternal;
// and the internal particles
vector<Lorentz5Momentum> pinter;
// copy the momentum of the incoming particle
pexternal.push_back(pin); pinter.push_back(pin);
pexternal.resize(_mode->numberofParticles());
pinter.resize(_intpart.size());
// masses of the intermediate particles
vector<Energy> massint(_intpart.size());
massint[0]=pin.mass();
// generate all the decays in the chain
Energy lower,upper,lowerb[2];
for(ix=0;ix<_intpart.size();++ix) {
idau[0] = abs(_intdau1[ix]);
idau[1] = abs(_intdau2[ix]);
// if both decay products off-shell
if(_intdau1[ix]<0&&_intdau2[ix]<0) {
// lower limits on the masses of the two resonances
for(iy=0;iy<2;++iy) {
lowerb[iy]=ZERO;
for(iz=0;iz<_intext[idau[iy]].size();++iz) {
lowerb[iy]+=massext[_intext[idau[iy]][iz]];
}
}
// randomize the order
if(UseRandom::rnd()<0.5) {
// mass of the first resonance
upper = massint[ix]-lowerb[1];
lower = lowerb[0];
massint[idau[0]]=generateMass(idau[0],lower,upper);
// mass of the second resonance
upper = massint[ix]-massint[idau[0]];
lower = lowerb[1];
massint[idau[1]]=generateMass(idau[1],lower,upper);
}
else {
// mass of the second resonance
upper = massint[ix]-lowerb[0];
lower = lowerb[1];
massint[idau[1]]=generateMass(idau[1],lower,upper);
// mass of the first resonance
upper = massint[ix]-massint[idau[1]];
lower = lowerb[0];
massint[idau[0]]=generateMass(idau[0],lower,upper);
}
// generate the momenta of the decay products
twoBodyDecay(pinter[ix],massint[idau[0]],massint[idau[1]],
pinter[idau[0]],pinter[idau[1]]);
}
// only first off-shell
else if(_intdau1[ix]<0) {
// compute the limits of integration
upper = massint[ix]-massext[idau[1]];
lower = ZERO;
for(iy=0;iy<_intext[idau[0]].size();++iy) {
lower+=massext[_intext[idau[0]][iy]];
}
massint[idau[0]]=generateMass(idau[0],lower,upper);
// generate the momenta of the decay products
twoBodyDecay(pinter[ix],massint[idau[0]],massext[idau[1]],
pinter[idau[0]],pexternal[idau[1]]);
}
// only second off-shell
else if(_intdau2[ix]<0) {
// compute the limits of integration
upper = massint[ix]-massext[idau[0]];
lower = ZERO;
for(iy=0;iy<_intext[idau[1]].size();++iy) {
lower+=massext[_intext[idau[1]][iy]];
}
massint[idau[1]]=generateMass(idau[1],lower,upper);
// generate the momenta of the decay products
twoBodyDecay(pinter[ix],massext[idau[0]],massint[idau[1]],
pexternal[idau[0]],pinter[idau[1]]);
}
// both on-shell
else {
// generate the momenta of the decay products
twoBodyDecay(pinter[ix],massext[idau[0]],massext[idau[1]],
pexternal[idau[0]],pexternal[idau[1]]);
}
}
// return the external momenta
return pexternal;
}
// generate the weight for this channel given a phase space configuration
double DecayPhaseSpaceChannel::generateWeight(const vector<Lorentz5Momentum> & output) {
using Constants::pi;
// integers for loops
unsigned int ix,iy,idau[2],iz;
// include the prefactor due to the weight of the channel
double wgt=1.;
// work out the masses of the intermediate particles
static vector<Energy> intmass;
intmass.clear();
Lorentz5Momentum pinter;
for(ix=0;ix<_intpart.size();++ix) {
pinter=output[_intext[ix][0]];
for(iz=1;iz<_intext[ix].size();++iz) pinter+=output[_intext[ix][iz]];
pinter.rescaleMass();
intmass.push_back( pinter.mass() );
}
Energy2 scale(sqr(intmass[0]));
// calculate the terms for each of the decays
Energy lower,upper,lowerb[2];
for(ix=0;ix<_intpart.size();++ix) {
idau[0] = abs(_intdau1[ix]);
idau[1] = abs(_intdau2[ix]);
// if both decay products off-shell
Energy pcm;
if(_intdau1[ix]<0&&_intdau2[ix]<0) {
// lower limits on the masses of the two resonances
for(iy=0;iy<2;++iy) {
lowerb[iy]=ZERO;
for(iz=0;iz<_intext[idau[iy]].size();++iz)
lowerb[iy]+=output[_intext[idau[iy]][iz]].mass();
}
// undo effect of randomising
// weight for the first order
// contribution of first resonance
upper = intmass[ix]-lowerb[1];
lower = lowerb[0];
InvEnergy2 wgta=massWeight(idau[0],intmass[idau[0]],lower,upper);
// contribution of second resonance
upper = intmass[ix]-intmass[idau[0]];
lower = lowerb[1];
InvEnergy4 wgta2 = wgta*massWeight(idau[1],intmass[idau[1]],lower,upper);
// weight for the second order
upper = intmass[ix]-lowerb[0];
lower = lowerb[1];
InvEnergy2 wgtb=massWeight(idau[1],intmass[idau[1]],lower,upper);
upper = intmass[ix]-intmass[idau[1]];
lower = lowerb[0];
InvEnergy4 wgtb2=wgtb*massWeight(idau[0],intmass[idau[0]],lower,upper);
// weight factor
wgt *=0.5*sqr(scale)*(wgta2+wgtb2);
// factor for the kinematics
pcm = Kinematics::pstarTwoBodyDecay(intmass[ix],intmass[idau[0]],
intmass[idau[1]]);
- if(pcm!=ZERO)
+ if(pcm>ZERO)
wgt *= intmass[ix]*8.*pi*pi/pcm;
else
wgt = 0.;
}
// only first off-shell
else if(_intdau1[ix]<0) {
// compute the limits of integration
upper = intmass[ix]-output[idau[1]].mass();
lower = ZERO;
for(iy=0;iy<_intext[idau[0]].size();++iy)
lower+=output[_intext[idau[0]][iy]].mass();
wgt *=scale*massWeight(idau[0],intmass[idau[0]],lower,upper);
pcm = Kinematics::pstarTwoBodyDecay(intmass[ix],intmass[idau[0]],
- output[idau[1]].mass());
- if(pcm!=ZERO)
+ output[idau[1]].mass());
+ if(pcm>ZERO)
wgt *= intmass[ix]*8.*pi*pi/pcm;
else
wgt = 0.;
}
// only second off-shell
else if(_intdau2[ix]<0) {
// compute the limits of integration
upper = intmass[ix]-output[idau[0]].mass();
lower = ZERO;
for(iy=0;iy<_intext[idau[1]].size();++iy)
lower+=output[_intext[idau[1]][iy]].mass();
wgt *=scale*massWeight(idau[1],intmass[idau[1]],lower,upper);
pcm = Kinematics::pstarTwoBodyDecay(intmass[ix],intmass[idau[1]],
- output[idau[0]].mass());
- if(pcm!=ZERO)
+ output[idau[0]].mass());
+ if(pcm>ZERO)
wgt *=intmass[ix]*8.*pi*pi/pcm;
else
- wgt = 0.;
+ wgt=0.;
}
// both on-shell
else {
pcm = Kinematics::pstarTwoBodyDecay(intmass[ix],output[idau[1]].mass(),
output[idau[0]].mass());
- if(pcm!=ZERO)
+ if(pcm>ZERO)
wgt *=intmass[ix]*8.*pi*pi/pcm;
else
wgt = 0.;
}
}
// finally the overall factor
wgt /= pi;
// return the answer
return wgt;
}
// output the information to a stream
ostream & Herwig::operator<<(ostream & os, const DecayPhaseSpaceChannel & channel) {
// output of the external particles
os << "Channel for the decay of " << channel._mode->externalParticles(0)->PDGName()
<< " -> ";
for(unsigned int ix=1;ix<channel._mode->numberofParticles();++ix)
os << channel._mode->externalParticles(ix)->PDGName() << " ";
os << endl;
os << "Decay proceeds in following steps ";
for(unsigned int ix=0;ix<channel._intpart.size();++ix) {
os << channel._intpart[ix]->PDGName() << " -> ";
if(channel._intdau1[ix]>0) {
os << channel._mode->externalParticles(channel._intdau1[ix])->PDGName()
<< "(" << channel._intdau1[ix]<< ") ";
}
else {
os << channel._intpart[-channel._intdau1[ix]]->PDGName()
<< "(" << channel._intdau1[ix]<< ") ";
}
if(channel._intdau2[ix]>0) {
os << channel._mode->externalParticles(channel._intdau2[ix])->PDGName()
<< "(" <<channel._intdau2[ix] << ") ";
}
else{
os << channel._intpart[-channel._intdau2[ix]]->PDGName()
<< "(" <<channel._intdau2[ix] << ") ";
}
os << endl;
}
return os;
}
// doinit method
void DecayPhaseSpaceChannel::doinit() {
Interfaced::doinit();
// check if the mode pointer exists
if(!_mode){throw InitException() << "DecayPhaseSpaceChannel::doinit() the "
<< "channel must have a pointer to a decay mode "
<< Exception::abortnow;}
// masses and widths of the intermediate particles
for(unsigned int ix=0;ix<_intpart.size();++ix) {
_intmass.push_back(_intpart[ix]->mass());
_intwidth.push_back(_intpart[ix]->width());
_intmass2.push_back(_intpart[ix]->mass()*_intpart[ix]->mass());
_intmwidth.push_back(_intpart[ix]->mass()*_intpart[ix]->width());
}
// external particles for each intermediate particle
vector<int> temp;
_intext.resize(_intpart.size());
// loop over the intermediate particles
for(int ix=_intpart.size()-1;ix>=0;--ix) {
temp.clear();
// add the first daughter
if(_intdau1[ix]>=0) {
temp.push_back(_intdau1[ix]);
}
else {
int iy = -_intdau1[ix];
vector<int>::iterator istart=_intext[iy].begin();
vector<int>::iterator iend=_intext[iy].end();
for(;istart!=iend;++istart) temp.push_back(*istart);
}
// add the second daughter
if(_intdau2[ix]>=0) {
temp.push_back(_intdau2[ix]);
}
else {
int iy = -_intdau2[ix];
vector<int>::iterator istart=_intext[iy].begin();
vector<int>::iterator iend=_intext[iy].end();
for(;istart!=iend;++istart) temp.push_back(*istart);
}
_intext[ix]=temp;
}
// ensure intermediates either have the width set, or
// can't possibly be on-shell
Energy massmax;
if(_mode->testOnShell()) {
massmax = _mode->externalParticles(0)->mass();
for(unsigned int ix=1;ix<_mode->numberofParticles();++ix)
massmax -= _mode->externalParticles(ix)->mass();
}
else {
massmax = _mode->externalParticles(0)->massMax();
for(unsigned int ix=1;ix<_mode->numberofParticles();++ix)
massmax -= _mode->externalParticles(ix)->massMin();
}
for(unsigned int ix=0;ix<_intpart.size();++ix) {
if(_intwidth[ix]==ZERO && ix>0 && _jactype[ix]==0 ) {
Energy massmin(ZERO);
for(unsigned int iy=0;iy<_intext[ix].size();++iy)
massmin += _mode->testOnShell() ?
_mode->externalParticles(_intext[ix][iy])->mass() :
_mode->externalParticles(_intext[ix][iy])->massMin();
// check if can be on-shell
if(_intmass[ix]>=massmin&&_intmass[ix]<=massmax+massmin) {
string modeout;
for(unsigned int iy=0;iy<_mode->numberofParticles();++iy) {
modeout += _mode->externalParticles(iy)->PDGName() + " ";
}
throw InitException() << "Width zero for " << _intpart[ix]->PDGName()
<< " in DecayPhaseSpaceChannel::doinit() "
<< modeout
<< Exception::runerror;
}
}
}
}
void DecayPhaseSpaceChannel::doinitrun() {
Interfaced::doinitrun();
if(!_mode->testOnShell()) return;
_intmass.clear();
_intwidth.clear();
_intmass2.clear();
_intmwidth.clear();
// masses and widths of the intermediate particles
for(unsigned int ix=0;ix<_intpart.size();++ix) {
_intmass.push_back(_intpart[ix]->mass());
_intwidth.push_back(_intpart[ix]->width());
_intmass2.push_back(_intpart[ix]->mass()*_intpart[ix]->mass());
_intmwidth.push_back(_intpart[ix]->mass()*_intpart[ix]->width());
}
// ensure intermediates either have the width set, or
// can't possibly be on-shell
Energy massmax = _mode->externalParticles(0)->massMax();
for(unsigned int ix=1;ix<_mode->numberofParticles();++ix)
massmax -= _mode->externalParticles(ix)->massMin();
for(unsigned int ix=0;ix<_intpart.size();++ix) {
if(_intwidth[ix]==0.*MeV && ix>0 && _jactype[ix]==0 ) {
Energy massmin(0.*GeV);
for(unsigned int iy=0;iy<_intext[ix].size();++iy)
massmin += _mode->externalParticles(_intext[ix][iy])->massMin();
// check if can be on-shell
if(_intmass[ix]>=massmin&&_intmass[ix]<=massmax+massmin) {
string modeout;
for(unsigned int iy=0;iy<_mode->numberofParticles();++iy) {
modeout += _mode->externalParticles(iy)->PDGName() + " ";
}
throw Exception() << "Width zero for " << _intpart[ix]->PDGName()
<< " in DecayPhaseSpaceChannel::doinitrun() "
<< modeout
<< Exception::runerror;
}
}
}
}
// generate the final-state particles including the intermediate resonances
void DecayPhaseSpaceChannel::generateIntermediates(bool cc, const Particle & in,
ParticleVector & out) {
// integers for the loops
unsigned int ix,iz;
// create the particles
// incoming particle
ParticleVector external;
external.push_back(const_ptr_cast<tPPtr>(&in));
// outgoing
for(ix=0;ix<out.size();++ix) external.push_back(out[ix]);
out.clear();
// now create the intermediates
ParticleVector resonance;
resonance.push_back(external[0]);
PPtr respart;
tcPDPtr parttemp;
Lorentz5Momentum pinter;
for(ix=1;ix<_intpart.size();++ix) {
pinter=external[_intext[ix][0]]->momentum();
for(iz=1;iz<_intext[ix].size();++iz)
pinter+=external[_intext[ix][iz]]->momentum();
pinter.rescaleMass();
respart = (cc&&_intpart[ix]->CC()) ?
_intpart[ix]->CC()->produceParticle(pinter) :
_intpart[ix] ->produceParticle(pinter);
resonance.push_back(respart);
}
// set up the mother daughter relations
for(ix=1;ix<_intpart.size();++ix) {
resonance[ix]->addChild( _intdau1[ix]<0 ?
resonance[-_intdau1[ix]] : external[_intdau1[ix]]);
resonance[ix]->addChild( _intdau2[ix]<0 ?
resonance[-_intdau2[ix]] : external[_intdau2[ix]]);
if(resonance[ix]->dataPtr()->stable())
resonance[ix]->setLifeLength(Lorentz5Distance());
}
// construct the output with the particles in the first step
out.push_back( _intdau1[0]>0 ? external[_intdau1[0]] : resonance[-_intdau1[0]]);
out.push_back( _intdau2[0]>0 ? external[_intdau2[0]] : resonance[-_intdau2[0]]);
}
double DecayPhaseSpaceChannel::atanhelper_(int ires, Energy limit) {
return atan2( limit*limit-_intmass2[ires], _intmwidth[ires] );
}
// return the weight for a given resonance
InvEnergy2 DecayPhaseSpaceChannel::massWeight(int ires, Energy moff,
Energy lower,Energy upper) {
InvEnergy2 wgt = ZERO;
if(lower>upper) {
throw DecayPhaseSpaceError() << "DecayPhaseSpaceChannel::massWeight not allowed "
<< ires << " " << _intpart[ires]->id() << " "
<< moff/GeV << " " << lower/GeV << " " << upper/GeV << Exception::eventerror;
}
// use a Breit-Wigner
if ( _jactype[ires] == 0 ) {
double rhomin = atanhelper_(ires,lower);
double rhomax = atanhelper_(ires,upper) - rhomin;
if ( rhomax != 0.0 ) {
Energy2 moff2=moff*moff-_intmass2[ires];
wgt = _intmwidth[ires]/rhomax/(moff2*moff2+_intmwidth[ires]*_intmwidth[ires]);
}
else {
wgt = 1./((sqr(upper)-sqr(lower))*sqr(sqr(moff)-_intmass2[ires])/
(sqr(lower)-_intmass2[ires])/(sqr(upper)-_intmass2[ires]));
}
}
// power law
else if(_jactype[ires]==1) {
double rhomin = pow(sqr(lower/MeV),_intpower[ires]+1.);
double rhomax = pow(sqr(upper/MeV),_intpower[ires]+1.)-rhomin;
wgt = (_intpower[ires]+1.)/rhomax*pow(sqr(moff/MeV),_intpower[ires])
/MeV/MeV;
}
else if(_jactype[ires]==2) {
wgt = 1./Constants::pi/_intmwidth[ires];
}
else {
throw DecayPhaseSpaceError() << "Unknown type of Jacobian in "
<< "DecayPhaseSpaceChannel::massWeight"
<< Exception::eventerror;
}
return wgt;
}
Energy DecayPhaseSpaceChannel::generateMass(int ires,Energy lower,Energy upper) {
static const Energy eps=1e-9*MeV;
if(lower<eps) lower=eps;
Energy mass=ZERO;
if(lower>upper) throw DecayPhaseSpaceError() << "DecayPhaseSpaceChannel::generateMass"
<< " not allowed"
<< Exception::eventerror;
if(abs(lower-upper)/(lower+upper)>2e-10) {
lower +=1e-10*(lower+upper);
upper -=1e-10*(lower+upper);
}
else
return 0.5*(lower+upper);
// use a Breit-Wigner
if(_jactype[ires]==0) {
if(_intmwidth[ires]!=ZERO) {
Energy2 lower2 = sqr(lower);
Energy2 upper2 = sqr(upper);
double rhomin = atan2((lower2 - _intmass2[ires]),_intmwidth[ires]);
double rhomax = atan2((upper2 - _intmass2[ires]),_intmwidth[ires])-rhomin;
double rho = rhomin+rhomax*UseRandom::rnd();
Energy2 mass2 = max(lower2,min(upper2,_intmass2[ires]+_intmwidth[ires]*tan(rho)));
if(mass2<ZERO) mass2 = ZERO;
mass = sqrt(mass2);
}
else {
mass = sqrt(_intmass2[ires]+
(sqr(lower)-_intmass2[ires])*(sqr(upper)-_intmass2[ires])/
(sqr(lower)-_intmass2[ires]-UseRandom::rnd()*(sqr(lower)-sqr(upper))));
}
}
// use a power-law
else if(_jactype[ires]==1) {
double rhomin = pow(sqr(lower/MeV),_intpower[ires]+1.);
double rhomax = pow(sqr(upper/MeV),_intpower[ires]+1.)-rhomin;
double rho = rhomin+rhomax*UseRandom::rnd();
mass = pow(rho,0.5/(_intpower[ires]+1.))*MeV;
}
else if(_jactype[ires]==2) {
mass = _intmass[ires];
}
else {
throw DecayPhaseSpaceError() << "Unknown type of Jacobian in "
<< "DecayPhaseSpaceChannel::generateMass"
<< Exception::eventerror;
}
if(mass<lower+1e-10*(lower+upper)) mass=lower+1e-10*(lower+upper);
else if(mass>upper-1e-10*(lower+upper)) mass=upper-1e-10*(lower+upper);
return mass;
}
void DecayPhaseSpaceChannel::twoBodyDecay(const Lorentz5Momentum & p,
const Energy m1, const Energy m2,
Lorentz5Momentum & p1,
Lorentz5Momentum & p2 ) {
static const double eps=1e-6;
double ctheta,phi;
Kinematics::generateAngles(ctheta,phi);
Axis unitDir1=Kinematics::unitDirection(ctheta,phi);
Momentum3 pstarVector;
Energy min=p.mass();
if ( min >= m1 + m2 && m1 >= ZERO && m2 >= ZERO ) {
pstarVector = unitDir1 * Kinematics::pstarTwoBodyDecay(min,m1,m2);
}
else if( m1 >= ZERO && m2 >= ZERO && (m1+m2-min)/(min+m1+m2)<eps) {
pstarVector = Momentum3();
}
else {
throw DecayPhaseSpaceError() << "Two body decay cannot proceed "
<< "p = " << p / GeV
<< " p.m() = " << min / GeV
<< " -> " << m1/GeV
<< ' ' << m2/GeV << Exception::eventerror;
}
p1 = Lorentz5Momentum(m1, pstarVector);
p2 = Lorentz5Momentum(m2,-pstarVector);
// boost from CM to LAB
Boost bv = p.boostVector();
double gammarest = p.e()/p.mass();
p1.boost( bv , gammarest );
p2.boost( bv , gammarest );
}
diff --git a/Decay/General/FFSDecayer.cc b/Decay/General/FFSDecayer.cc
--- a/Decay/General/FFSDecayer.cc
+++ b/Decay/General/FFSDecayer.cc
@@ -1,444 +1,463 @@
// -*- C++ -*-
//
// FFSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFSDecayer class.
//
#include "FFSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr FFSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FFSDecayer::fullclone() const {
return new_ptr(*this);
}
void FFSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> ) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractFFSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<FFSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractFFSVertexPtr>(vert));
+ perturbativeVertex_ .push_back(dynamic_ptr_cast<FFSVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(inV.at(inter));
outgoingVertexF_[inter] = AbstractFFVVertexPtr();
outgoingVertexS_[inter] = AbstractVSSVertexPtr();
if(outV[0].at(inter)) {
if (outV[0].at(inter)->getName()==VertexType::FFV)
outgoingVertexF_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[0].at(inter));
else
outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
}
if(outV[1].at(inter)) {
if (outV[1].at(inter)->getName()==VertexType::FFV)
outgoingVertexF_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[1].at(inter));
else
outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
}
}
}
void FFSDecayer::persistentOutput(PersistentOStream & os) const {
os << perturbativeVertex_ << vertex_
<< incomingVertex_ << outgoingVertexF_
<< outgoingVertexS_;
}
void FFSDecayer::persistentInput(PersistentIStream & is, int) {
is >> perturbativeVertex_ >> vertex_
>> incomingVertex_ >> outgoingVertexF_
>> outgoingVertexS_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FFSDecayer,GeneralTwoBodyDecayer>
describeHerwigFFSDecayer("Herwig::FFSDecayer", "Herwig.so");
void FFSDecayer::Init() {
static ClassDocumentation<FFSDecayer> documentation
("The FFSDecayer class implements the decay of a fermion to "
"a fermion and a scalar.");
}
double FFSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0)));
//Need to use different barred or unbarred spinors depending on
//whether particle is cc or not.
int itype[2];
if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0? 0:1;
else itype[0] = 2;
if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0? 0:1;
else itype[1] = 2;
bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2));
if(meopt==Initialize) {
// spinors and rho
if(ferm) {
SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate();
}
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true);
}
ScalarWaveFunction::constructSpinInfo(decay[1],outgoing,true);
}
if(ferm)
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[0],outgoing);
else
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[0],outgoing);
ScalarWaveFunction scal(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 2; ++if2) {
- if(ferm) (*ME())(if1, if2, 0) =
- vertex_->evaluate(scale,wave_[if1],wavebar_[if2],scal);
- else (*ME())(if2, if1, 0) =
- vertex_->evaluate(scale,wave_[if1],wavebar_[if2],scal);
+ if(ferm) (*ME())(if1, if2, 0) = 0.;
+ else (*ME())(if2, if1, 0) = 0.;
+ for(auto vert : vertex_) {
+ if(ferm) (*ME())(if1, if2, 0) +=
+ vert->evaluate(scale,wave_[if1],wavebar_[if2],scal);
+ else (*ME())(if2, if1, 0) +=
+ vert->evaluate(scale,wave_[if1],wavebar_[if2],scal);
+ }
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy FFSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
double mu1(0.),mu2(0.);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if(outa.first->iSpin() == PDT::Spin1Half) {
mu1 = outa.second/inpart.second;
mu2 = outb.second/inpart.second;
- perturbativeVertex_->setCoupling(sqr(inpart.second), in, outa.first, outb.first);
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first);
}
else {
mu1 = outb.second/inpart.second;
mu2 = outa.second/inpart.second;
- perturbativeVertex_->setCoupling(sqr(inpart.second), in, outb.first, outa.first);
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outb.first, outa.first);
}
- double c2 = norm(perturbativeVertex_->norm());
- Complex cl = perturbativeVertex_->left();
- Complex cr = perturbativeVertex_->right();
+ double c2 = norm(perturbativeVertex_[0]->norm());
+ Complex cl = perturbativeVertex_[0]->left();
+ Complex cr = perturbativeVertex_[0]->right();
double me2 = c2*( (norm(cl) + norm(cr))*(1. + sqr(mu1) - sqr(mu2))
+ 2.*mu1*(conj(cl)*cr + conj(cr)*cl).real() );
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
Energy output = me2*pcm/16./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double FFSDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
int iscal (0), iferm (1), iglu (2);
// get location of outgoing fermion/scalar
if(decay[1]->dataPtr()->iSpin()==PDT::Spin0) swap(iscal,iferm);
// work out whether inpart is a fermion or antifermion
int itype[2];
if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1;
else itype[0] = 2;
if(decay[iferm]->dataPtr()->CC()) itype[1] = decay[iferm]->id() > 0 ? 0 : 1;
else itype[1] = 2;
bool ferm(false);
if(itype[0] == itype[1] ) {
ferm = itype[0]==0 || (itype[0]==2 && decay[iscal]->id() < 0);
}
else if(itype[0] == 2) {
ferm = itype[1]==0;
}
else if(itype[1] == 2) {
ferm = itype[0]==0;
}
else if((itype[0] == 1 && itype[1] == 0) ||
(itype[0] == 0 && itype[1] == 1)) {
if(abs(inpart.id())<=16) {
ferm = itype[0]==0;
}
else if(abs(decay[iferm]->id())<=16) {
ferm = itype[1]==0;
}
else {
ferm = true;
}
}
else
assert(false);
if(meopt==Initialize) {
// create spinor (bar) for decaying particle
if(ferm) {
SpinorWaveFunction::calculateWaveFunctions(wave3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave3_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave3_[ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_,rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar3_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar3_[ix].conjugate();
}
}
// setup spin information when needed
if(meopt==Terminate) {
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave3_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(wavebar3_,decay[iferm],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(wave3_,decay[iferm],outgoing,true);
}
ScalarWaveFunction::constructSpinInfo( decay[iscal],outgoing,true);
VectorWaveFunction::constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false);
return 0.;
}
// calulate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, PDT::Spin0,
PDT::Spin1Half, PDT::Spin1)));
// create wavefunctions
if (ferm) SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
else SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[iferm],outgoing);
ScalarWaveFunction swave3_(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true);
// gauge invariance test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
if (! ((incomingVertex_[inter] && (outgoingVertexF_[inter] || outgoingVertexS_[inter])) ||
(outgoingVertexF_[inter] && outgoingVertexS_[inter])))
throw Exception()
<< "Invalid vertices for radiation in FFS decay in FFSDecayer::threeBodyME"
<< Exception::runerror;
// sort out colour flows
int F(1), S(2);
if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour8)
swap(F,S);
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour8)
swap(F,S);
Complex diag;
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int ifi = 0; ifi < 2; ++ifi) {
for(unsigned int ifo = 0; ifo < 2; ++ifo) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming fermion
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
if (ferm) {
SpinorWaveFunction spinorInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi],
gluon_[2*ig],inpart.mass());
assert(wave3_[ifi].particle()->id()==spinorInter.particle()->id());
- diag = vertex_->evaluate(scale,spinorInter,wavebar3_[ifo],swave3_);
+ diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifo],swave3_);
}
else {
SpinorBarWaveFunction spinorBarInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi],
gluon_[2*ig],inpart.mass());
assert(wavebar3_[ifi].particle()->id()==spinorBarInter.particle()->id());
- diag = vertex_->evaluate(scale,wave3_[ifo], spinorBarInter,swave3_);
+ diag = 0.;
+ for(auto vertex :vertex_)
+ diag+= vertex->evaluate(scale,wave3_[ifo], spinorBarInter,swave3_);
}
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(ifi, 0, ifo, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing fermion
if((decay[iferm]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexF_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
if (ferm) {
SpinorBarWaveFunction spinorBarInter =
outgoingVertexF_[inter]->evaluate(scale,3,off,wavebar3_[ifo],
gluon_[2*ig],decay[iferm]->mass());
assert(wavebar3_[ifo].particle()->id()==spinorBarInter.particle()->id());
- diag = vertex_->evaluate(scale,wave3_[ifi],spinorBarInter,swave3_);
+ diag = 0.;
+ for(auto vertex :vertex_)
+ diag+= vertex->evaluate(scale,wave3_[ifi],spinorBarInter,swave3_);
}
else {
SpinorWaveFunction spinorInter =
outgoingVertexF_[inter]->evaluate(scale,3,off,wave3_[ifo],
gluon_[2*ig],decay[iferm]->mass());
assert(wave3_[ifo].particle()->id()==spinorInter.particle()->id());
- diag = vertex_->evaluate(scale,spinorInter,wavebar3_[ifi],swave3_);
+ diag = 0.;
+ for(auto vertex :vertex_)
+ diag+= vertex->evaluate(scale,spinorInter,wavebar3_[ifi],swave3_);
}
if(!couplingSet) {
gs = abs(outgoingVertexF_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[F].size();++ix) {
(*ME[colourFlow[F][ix].first])(ifi, 0, ifo, ig) +=
colourFlow[F][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing scalar
if((decay[iscal]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexS_[inter]);
// ensure you get correct ougoing particle from first vertex
tcPDPtr off = decay[iscal]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],
swave3_,decay[iscal]->mass());
assert(swave3_.particle()->id()==scalarInter.particle()->id());
if (ferm){
- diag = vertex_->evaluate(scale,wave3_[ifi],wavebar3_[ifo],scalarInter);
+ diag = 0.;
+ for(auto vertex :vertex_)
+ diag += vertex->evaluate(scale,wave3_[ifi],wavebar3_[ifo],scalarInter);
}
else {
- diag = vertex_->evaluate(scale,wave3_[ifo],wavebar3_[ifi],scalarInter);
+ diag = 0.;
+ for(auto vertex :vertex_)
+ diag += vertex->evaluate(scale,wave3_[ifo],wavebar3_[ifi],scalarInter);
}
if(!couplingSet) {
gs = abs(outgoingVertexS_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[S].size();++ix) {
(*ME[colourFlow[S][ix].first])(ifi, 0, ifo, ig) +=
colourFlow[S][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha(S,EM)
output*=(4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
diff --git a/Decay/General/FFSDecayer.h b/Decay/General/FFSDecayer.h
--- a/Decay/General/FFSDecayer.h
+++ b/Decay/General/FFSDecayer.h
@@ -1,210 +1,218 @@
// -*- C++ -*-
//
// FFSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FFSDecayer_H
#define HERWIG_FFSDecayer_H
//
// This is the declaration of the FFSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/FFSVertex.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFSVertexPtr;
/** \ingroup Decay
* The FFSDecayer class implements the decay of a fermion
* to a fermion and a vector in a general model. It holds an FFVVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class FFSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
FFSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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);
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
FFSDecayer & operator=(const FFSDecayer &);
private:
/**
* Abstract pointer to AbstractFFSVertex
*/
- AbstractFFSVertexPtr vertex_;
+ vector<AbstractFFSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- FFSVertexPtr perturbativeVertex_;
+ vector<FFSVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from incoming (anti)fermion
*/
map<ShowerInteraction,AbstractFFVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertexF_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from outgoing scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertexS_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunctions
*/
mutable vector<SpinorWaveFunction> wave_ ;
/**
* Barred spinor wavefunctions
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable ScalarWaveFunction swave3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_FFSDecayer_H */
diff --git a/Decay/General/FFVDecayer.cc b/Decay/General/FFVDecayer.cc
--- a/Decay/General/FFVDecayer.cc
+++ b/Decay/General/FFVDecayer.cc
@@ -1,433 +1,456 @@
// -*- C++ -*-
//
// FFVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFVDecayer class.
//
#include "FFVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr FFVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FFVDecayer::fullclone() const {
return new_ptr(*this);
}
void FFVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> ) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<FFVVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractFFVVertexPtr>(vert));
+ perturbativeVertex_ .push_back(dynamic_ptr_cast<FFVVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(inV.at(inter));
if(outV[0].at(inter)) {
if (outV[0].at(inter)->getName()==VertexType::FFV)
outgoingVertexF_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[0].at(inter));
else
outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[0].at(inter));
}
if(outV[1].at(inter)) {
if (outV[1].at(inter)->getName()==VertexType::FFV)
outgoingVertexF_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[1].at(inter));
else
outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[1].at(inter));
}
}
}
void FFVDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertexF_
<< outgoingVertexV_;
}
void FFVDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertexF_
>> outgoingVertexV_;
}
double FFVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin1)));
// type of process
int itype[2];
if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1;
else itype[0] = 2;
if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0 ? 0 : 1;
else itype[1] = 2;
//Need to use different barred or unbarred spinors depending on
//whether particle is cc or not.
bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2));
if(meopt==Initialize) {
// spinors and rho
if(ferm) {
SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate();
}
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true);
}
VectorWaveFunction::
constructSpinInfo(vector_,decay[1],outgoing,true,false);
}
Energy2 scale(sqr(inpart.mass()));
if(ferm)
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[0],outgoing);
else
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[0],outgoing);
bool massless = decay[1]->dataPtr()->mass()==ZERO;
VectorWaveFunction::
calculateWaveFunctions(vector_,decay[1],outgoing,massless);
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 2; ++if2) {
for(unsigned int vhel = 0; vhel < 3; ++vhel) {
if(massless && vhel == 1) ++vhel;
if(ferm)
- (*ME())(if1, if2,vhel) =
- vertex_->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]);
+ (*ME())(if1, if2,vhel) = 0.;
else
- (*ME())(if2, if1, vhel) =
- vertex_->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]);
+ (*ME())(if2, if1, vhel) = 0.;
+ for(auto vertex : vertex_) {
+ if(ferm)
+ (*ME())(if1, if2,vhel) +=
+ vertex->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]);
+ else
+ (*ME())(if2, if1, vhel) +=
+ vertex->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]);
+ }
}
}
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),decay[1]->dataPtr());
// return the answer
return output;
}
Energy FFVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
double mu1(outa.second/inpart.second),mu2(outb.second/inpart.second);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if( outa.first->iSpin() == PDT::Spin1Half)
- perturbativeVertex_->setCoupling(sqr(inpart.second), in,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in,
outa.first, outb.first);
else {
swap(mu1,mu2);
- perturbativeVertex_->setCoupling(sqr(inpart.second),in,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second),in,
outb.first,outa.first);
}
- Complex cl(perturbativeVertex_->left()),cr(perturbativeVertex_->right());
+ Complex cl(perturbativeVertex_[0]->left()),cr(perturbativeVertex_[0]->right());
double me2(0.);
if( mu2 > 0. ) {
me2 = (norm(cl) + norm(cr))*(1. + sqr(mu1*mu2) + sqr(mu2)
- 2.*sqr(mu1) - 2.*sqr(mu2*mu2)
+ sqr(mu1*mu1))
- 6.*mu1*sqr(mu2)*(conj(cl)*cr + conj(cr)*cl).real();
me2 /= sqr(mu2);
}
else
me2 = 2.*( (norm(cl) + norm(cr))*(sqr(mu1) + 1.)
- 4.*mu1*(conj(cl)*cr + conj(cr)*cl).real() );
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
- Energy output = norm(perturbativeVertex_->norm())*me2*pcm/16./Constants::pi;
+ Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/16./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FFVDecayer,GeneralTwoBodyDecayer>
describeHerwigFFVDecayer("Herwig::FFVDecayer", "Herwig.so");
void FFVDecayer::Init() {
static ClassDocumentation<FFVDecayer> documentation
("The FFVDecayer class implements the decay of a fermion to a fermion and a vector boson");
}
double FFVDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
int iferm (0), ivect (1), iglu (2);
// get location of outgoing lepton/vector
if(decay[1]->dataPtr()->iSpin()==PDT::Spin1Half) swap(iferm,ivect);
// work out whether inpart is a fermion or antifermion
int itype[2];
if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1;
else itype[0] = 2;
if(decay[iferm]->dataPtr()->CC()) itype[1] = decay[iferm]->id() > 0 ? 0 : 1;
else itype[1] = 2;
bool ferm(itype[0] == 0 || itype[1] == 0 ||
(itype[0] == 2 && itype[1] == 2 && decay[ivect]->id() < 0));
// no emissions from massive vectors
bool massless = decay[ivect]->dataPtr()->mass()==ZERO;
if(meopt==Initialize) {
// create spinor (bar) for decaying particle
if(ferm) {
SpinorWaveFunction::calculateWaveFunctions(wave3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave3_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave3_[ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_,rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar3_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar3_[ix].conjugate();
}
}
// setup spin information when needed
if(meopt==Terminate) {
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave3_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::constructSpinInfo(wavebar3_,decay[iferm],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorWaveFunction::constructSpinInfo(wave3_,decay[iferm],outgoing,true);
}
VectorWaveFunction::constructSpinInfo(vector3_, decay[ivect],outgoing,true,massless);
VectorWaveFunction::constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false);
return 0.;
}
// calulate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, PDT::Spin1Half,
PDT::Spin1, PDT::Spin1)));
// create wavefunctions
if (ferm) SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
else SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[iferm],outgoing);
VectorWaveFunction::calculateWaveFunctions(vector3_, decay[ivect],outgoing,massless);
VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true );
// gauge invariance test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
if (! ((incomingVertex_[inter] && (outgoingVertexF_[inter] || outgoingVertexV_[inter])) ||
(outgoingVertexF_[inter] && outgoingVertexV_[inter])))
throw Exception()
<< "Invalid vertices for QCD radiation in FFV decay in FFVDecayer::threeBodyME"
<< Exception::runerror;
// sort out colour flows
int F(1), V(2);
if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[ivect]->dataPtr()->iColour()==PDT::Colour8)
swap(F,V);
else if (decay[ivect]->dataPtr()->iColour()==PDT::Colour3 &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour8)
swap(F,V);
Complex diag;
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int ifi = 0; ifi < 2; ++ifi) {
for(unsigned int ifo = 0; ifo < 2; ++ifo) {
for(unsigned int iv = 0; iv < 3; ++iv) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming fermion
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
if (ferm){
SpinorWaveFunction spinorInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi],
gluon_[2*ig],inpart.mass());
assert(wave3_[ifi].particle()->id()==spinorInter.particle()->id());
- diag = vertex_->evaluate(scale,spinorInter,wavebar3_[ifo],vector3_[iv]);
+ diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifo],vector3_[iv]);
}
else {
SpinorBarWaveFunction spinorBarInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi],
gluon_[2*ig],inpart.mass());
assert(wavebar3_[ifi].particle()->id()==spinorBarInter.particle()->id());
- diag = vertex_->evaluate(scale,wave3_[ifo], spinorBarInter,vector3_[iv]);
+ diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ifo], spinorBarInter,vector3_[iv]);
}
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(ifi, ifo, iv, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing fermion
if((decay[iferm]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexF_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
if (ferm) {
SpinorBarWaveFunction spinorBarInter =
outgoingVertexF_[inter]->evaluate(scale,3,off,wavebar3_[ifo],
gluon_[2*ig],decay[iferm]->mass());
assert(wavebar3_[ifo].particle()->id()==spinorBarInter.particle()->id());
- diag = vertex_->evaluate(scale,wave3_[ifi],spinorBarInter,vector3_[iv]);
+ diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ifi],spinorBarInter,vector3_[iv]);
}
else {
SpinorWaveFunction spinorInter =
outgoingVertexF_[inter]->evaluate(scale,3,off,wave3_[ifo],
gluon_[2*ig],decay[iferm]->mass());
assert(wave3_[ifo].particle()->id()==spinorInter.particle()->id());
- diag = vertex_->evaluate(scale,spinorInter,wavebar3_[ifi],vector3_[iv]);
+ diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifi],vector3_[iv]);
}
if(!couplingSet) {
gs = abs(outgoingVertexF_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[F].size();++ix) {
(*ME[colourFlow[F][ix].first])(ifi, ifo, iv, ig) +=
colourFlow[F][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing vector
if((decay[ivect]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[ivect]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexV_[inter]);
// ensure you get correct ougoing particle from first vertex
tcPDPtr off = decay[ivect]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectorInter =
outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig],
vector3_[iv],decay[ivect]->mass());
- assert(vector3_[iv].particle()->id()==vectorInter.particle()->id());
- if (ferm)
- diag = vertex_->evaluate(scale,wave3_[ifi],wavebar3_[ifo],vectorInter);
- else
- diag = vertex_->evaluate(scale,wave3_[ifo],wavebar3_[ifi],vectorInter);
+ assert(vector3_[iv].particle()->id()==vectorInter.particle()->id());
+ if (ferm) {
+ diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ifi],wavebar3_[ifo],vectorInter);
+ }
+ else {
+ diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ifo],wavebar3_[ifi],vectorInter);
+ }
if(!couplingSet) {
gs = abs(outgoingVertexV_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[V].size();++ix) {
(*ME[colourFlow[V][ix].first])(ifi, ifo, iv, ig) +=
colourFlow[V][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
if(massless) ++iv;
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha(S,eM)
output *= (4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
diff --git a/Decay/General/FFVDecayer.h b/Decay/General/FFVDecayer.h
--- a/Decay/General/FFVDecayer.h
+++ b/Decay/General/FFVDecayer.h
@@ -1,216 +1,223 @@
// -*- C++ -*-
//
// FFVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FFVDecayer_H
#define HERWIG_FFVDecayer_H
//
// This is the declaration of the FFVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFVVertexPtr;
/** \ingroup Decay
* The FFVDecayer class implements the decay of a fermion
* to a fermion and a vector in a general model. It holds an FFVVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class FFVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
FFVDecayer() {}
public:
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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);
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
FFVDecayer & operator=(const FFVDecayer &);
private:
/**
* Abstract pointer to AbstractFFVVertex
*/
- AbstractFFVVertexPtr vertex_;
+ vector<AbstractFFVVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- FFVVertexPtr perturbativeVertex_;
+ vector<FFVVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from incoming (anti)fermion
*/
map<ShowerInteraction,AbstractFFVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing (anti)fermion
*/
map<ShowerInteraction,AbstractFFVVertexPtr> outgoingVertexF_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertexV_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunction
*/
mutable vector<SpinorWaveFunction> wave_ ;
/**
* Barred spinor wavefunction
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Polarization vectors
*/
mutable vector<VectorWaveFunction> vector_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> vector3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for gluon in 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_FFVDecayer_H */
diff --git a/Decay/General/FRSDecayer.cc b/Decay/General/FRSDecayer.cc
--- a/Decay/General/FRSDecayer.cc
+++ b/Decay/General/FRSDecayer.cc
@@ -1,183 +1,189 @@
// -*- C++ -*-
//
// FRSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FRSDecayer class.
//
#include "FRSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr FRSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FRSDecayer::fullclone() const {
return new_ptr(*this);
}
void FRSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > &,
map<ShowerInteraction,VertexBasePtr>) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractRFSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<RFSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractRFSVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<RFSVertexPtr> (vert));
+ }
}
void FRSDecayer::persistentOutput(PersistentOStream & os) const {
os << perturbativeVertex_ << vertex_;
}
void FRSDecayer::persistentInput(PersistentIStream & is, int) {
is >> perturbativeVertex_ >> vertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FRSDecayer,GeneralTwoBodyDecayer>
describeHerwigFRSDecayer("Herwig::FRSDecayer", "Herwig.so");
void FRSDecayer::Init() {
static ClassDocumentation<FRSDecayer> documentation
("The FRSDecayer class implements the decay of a fermion to "
"a spin-3/2 fermion and a scalar.");
}
double FRSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
bool ferm = inpart.id() > 0;
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin3Half,PDT::Spin0)));
if(meopt==Initialize) {
// spinors and rho
if(ferm) {
SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate();
}
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
RSSpinorBarWaveFunction::constructSpinInfo(RSwavebar_,decay[0],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
RSSpinorWaveFunction::constructSpinInfo(RSwave_,decay[0],outgoing,true);
}
ScalarWaveFunction::constructSpinInfo(decay[1],outgoing,true);
}
if(ferm)
RSSpinorBarWaveFunction::
calculateWaveFunctions(RSwavebar_,decay[0],outgoing);
else
RSSpinorWaveFunction::
calculateWaveFunctions(RSwave_ ,decay[0],outgoing);
ScalarWaveFunction scal(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 4; ++if2) {
- if(ferm) (*ME())(if1, if2, 0) =
- vertex_->evaluate(scale,wave_[if1],RSwavebar_[if2],scal);
- else (*ME())(if1, if2, 0) =
- vertex_->evaluate(scale,RSwave_[if2],wavebar_[if1],scal);
+ (*ME())(if1, if2, 0) = 0.;
+ for(auto vert : vertex_) {
+ if(ferm) (*ME())(if1, if2, 0) +=
+ vert->evaluate(scale,wave_[if1],RSwavebar_[if2],scal);
+ else (*ME())(if1, if2, 0) +=
+ vert->evaluate(scale,RSwave_[if2],wavebar_[if1],scal);
+ }
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// test code
// Energy q = inpart.mass();
// Energy m1 = decay[0]->mass();
// Energy m2 = decay[1]->mass();
// Energy2 q2(q*q),m12(m1*m1),m22(m2*m2);
// Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2);
// Energy pcm(sqrt(pcm2));
// Energy Qp(sqrt((q+m1)*(q+m1)-m22)),Qm(sqrt((q-m1)*(q-m1)-m22));
// double r23(sqrt(2./3.));
// // couplings
// Complex left = perturbativeVertex_-> left()*perturbativeVertex_-> norm();
// Complex right = perturbativeVertex_->right()*perturbativeVertex_-> norm();
// complex<InvEnergy> A1 = 0.5*(left+right)*UnitRemoval::InvE;
// complex<InvEnergy> B1 = 0.5*(right-left)*UnitRemoval::InvE;
// complex<Energy> h1(-2.*r23*pcm*q/m1*Qm*B1);
// complex<Energy> h2( 2.*r23*pcm*q/m1*Qp*A1);
// cout << "testing 1/2->3/2 0 "
// << output*scale/GeV2 << " "
// << real(h1*conj(h1)+h2*conj(h2))/4./GeV2 << " "
// << real(h1*conj(h1)+h2*conj(h2))/4./(output*scale) << endl;
// return the answer
return output;
}
Energy FRSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
Energy q = inpart.second;
Energy m1 = outa.second;
Energy m2 = outb.second;
Energy2 q2(q*q),m12(m1*m1),m22(m2*m2);
Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2);
Energy pcm(sqrt(pcm2));
Energy Qp(sqrt((q+m1)*(q+m1)-m22)),Qm(sqrt((q-m1)*(q-m1)-m22));
double r23(sqrt(2./3.));
// couplings
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(sqr(inpart.second), outa.first,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first,
in, outb.first);
- Complex left = perturbativeVertex_-> left()*perturbativeVertex_-> norm();
- Complex right = perturbativeVertex_->right()*perturbativeVertex_-> norm();
+ Complex left = perturbativeVertex_[0]-> left()*perturbativeVertex_[0]-> norm();
+ Complex right = perturbativeVertex_[0]->right()*perturbativeVertex_[0]-> norm();
complex<InvEnergy> A1 = 0.5*(left+right)*UnitRemoval::InvE;
complex<InvEnergy> B1 = 0.5*(right-left)*UnitRemoval::InvE;
complex<Energy> h1(-2.*r23*pcm*q/m1*Qm*B1);
complex<Energy> h2( 2.*r23*pcm*q/m1*Qp*A1);
double me2 = real(h1*conj(h1)+h2*conj(h2))/4./sqr(inpart.second);
Energy output = me2*pcm/8./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/FRSDecayer.h b/Decay/General/FRSDecayer.h
--- a/Decay/General/FRSDecayer.h
+++ b/Decay/General/FRSDecayer.h
@@ -1,163 +1,164 @@
// -*- C++ -*-
//
// FRSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FRSDecayer_H
#define HERWIG_FRSDecayer_H
//
// This is the declaration of the FRSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/RFSVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::RFSVertexPtr;
/** \ingroup Decay
* The FRSDecayer class implements the decay of a fermion
* to a spin-3/2 fermion and a vector in a general model. It holds an RFVVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class FRSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
FRSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
FRSDecayer & operator=(const FRSDecayer &);
private:
/**
* Abstract pointer to AbstractFRSVertex
*/
- AbstractRFSVertexPtr vertex_;
+ vector<AbstractRFSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- RFSVertexPtr perturbativeVertex_;
+ vector<RFSVertexPtr> perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunctions
*/
mutable vector<SpinorWaveFunction> wave_ ;
/**
* Barred spinor wavefunctions
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* RS Spinor wavefunctions
*/
mutable vector<RSSpinorWaveFunction> RSwave_ ;
/**
* Barred RS spinor wavefunctions
*/
mutable vector<RSSpinorBarWaveFunction> RSwavebar_;
};
}
#endif /* HERWIG_FRSDecayer_H */
diff --git a/Decay/General/FRVDecayer.cc b/Decay/General/FRVDecayer.cc
--- a/Decay/General/FRVDecayer.cc
+++ b/Decay/General/FRVDecayer.cc
@@ -1,213 +1,219 @@
// -*- C++ -*-
//
// FRVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FRVDecayer class.
//
#include "FRVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr FRVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr FRVDecayer::fullclone() const {
return new_ptr(*this);
}
void FRVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > &,
map<ShowerInteraction,VertexBasePtr>) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractRFVVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<RFVVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractRFVVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<RFVVertexPtr> (vert));
+ }
}
void FRVDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_;
}
void FRVDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_;
}
double FRVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin3Half,PDT::Spin1)));
// decaying fermion or antifermion
bool ferm = inpart.id() > 0;
// initialize
if(meopt==Initialize) {
// spinors and rho
if(ferm) {
SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wave_[0].wave().Type() != SpinorType::u)
for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate();
}
else {
SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming);
if(wavebar_[0].wave().Type() != SpinorType::v)
for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate();
}
}
// setup spin info when needed
if(meopt==Terminate) {
// for the decaying particle
if(ferm) {
SpinorWaveFunction::
constructSpinInfo(wave_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
RSSpinorBarWaveFunction::constructSpinInfo(RSwavebar_,decay[0],outgoing,true);
}
else {
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,const_ptr_cast<tPPtr>(&inpart),incoming,true);
RSSpinorWaveFunction::constructSpinInfo(RSwave_,decay[0],outgoing,true);
}
VectorWaveFunction::
constructSpinInfo(vector_,decay[1],outgoing,true,false);
}
Energy2 scale(sqr(inpart.mass()));
if(ferm)
RSSpinorBarWaveFunction::
calculateWaveFunctions(RSwavebar_,decay[0],outgoing);
else
RSSpinorWaveFunction::
calculateWaveFunctions(RSwave_ ,decay[0],outgoing);
bool massless = decay[1]->dataPtr()->mass()==ZERO;
VectorWaveFunction::
calculateWaveFunctions(vector_,decay[1],outgoing,massless);
// loop over helicities
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 4; ++if2) {
for(unsigned int vhel = 0; vhel < 3; ++vhel) {
if(massless && vhel == 1) ++vhel;
- if(ferm)
- (*ME())(if1, if2,vhel) =
- vertex_->evaluate(scale,wave_[if1],
- RSwavebar_[if2],vector_[vhel]);
- else
- (*ME())(if1, if2, vhel) =
- vertex_->evaluate(scale,RSwave_[if2],
- wavebar_[if1],vector_[vhel]);
+ (*ME())(if1, if2,vhel) = 0.;
+ for(auto vert : vertex_) {
+ if(ferm)
+ (*ME())(if1, if2,vhel) +=
+ vert->evaluate(scale,wave_[if1],
+ RSwavebar_[if2],vector_[vhel]);
+ else
+ (*ME())(if1, if2, vhel) +=
+ vert->evaluate(scale,RSwave_[if2],
+ wavebar_[if1],vector_[vhel]);
+ }
}
}
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// test
// Energy m1(inpart.mass()),m2(decay[0]->mass()),m3(decay[1]->mass());
// Energy2 m12(m1*m1),m22(m2*m2),m32(m3*m3);
// Energy Qp(sqrt(sqr(m1+m2)-sqr(m3))),Qm(sqrt(sqr(m1-m2)-sqr(m3)));
// double r2(sqrt(2.)),r3(sqrt(3.));
// Energy pcm(Kinematics::pstarTwoBodyDecay(m1,m2,m3));
// vector<Complex> left = perturbativeVertex_-> left();
// vector<Complex> right = perturbativeVertex_->right();
// Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_-> norm();
// Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_-> norm();
// complex<InvEnergy> A2 = 0.5*(left [1]+right[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE;
// complex<InvEnergy> B2 = 0.5*(right[1]- left[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE;
// complex<InvEnergy2> A3 = 0.5*(left [2]+right[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2;
// complex<InvEnergy2> B3 = 0.5*(right[2]- left[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2;
// complex<Energy> h1(-2.*Qp*A1),h2(2.*Qm*B1);
// complex<Energy> h3(-2./r3*Qp*(A1-Qm*Qm/m2*A2));
// complex<Energy> h4( 2./r3*Qm*(B1-Qp*Qp/m2*B2));
// complex<Energy> h5(ZERO),h6(ZERO);
// if(decay[1]->mass()>ZERO) {
// h5 = -2.*r2/r3/m2/m3*Qp*(0.5*(m12-m22-m32)*A1+0.5*Qm*Qm*(m1+m2)*A2
// +m12*pcm*pcm*A3);
// h6 = 2.*r2/r3/m2/m3*Qm*(0.5*(m12-m22-m32)*B1-0.5*Qp*Qp*(m1-m2)*B2
// +m12*pcm*pcm*B3);
// }
// cout << "testing 1/2->3/2 1 " << inpart.id() << " "
// << output << " "
// << 0.25*(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+
// h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.mass()) << " "
// << 0.25*(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+
// h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.mass())/output << endl;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),decay[1]->dataPtr());
// return the answer
return output;
}
Energy FRVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
Energy m1(inpart.second),m2(outa.second),m3(outb.second);
Energy2 m12(m1*m1),m22(m2*m2),m32(m3*m3);
Energy Qp(sqrt(sqr(m1+m2)-sqr(m3))),Qm(sqrt(sqr(m1-m2)-sqr(m3)));
double r2(sqrt(2.)),r3(sqrt(3.));
Energy pcm(Kinematics::pstarTwoBodyDecay(m1,m2,m3));
// couplings
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(sqr(inpart.second), outa.first,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first,
in, outb.first);
- vector<Complex> left = perturbativeVertex_-> left();
- vector<Complex> right = perturbativeVertex_->right();
- Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_-> norm();
- Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_-> norm();
- complex<InvEnergy> A2 = 0.5*(left [1]+right[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE;
- complex<InvEnergy> B2 = 0.5*(right[1]- left[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE;
- complex<InvEnergy2> A3 = 0.5*(left [2]+right[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2;
- complex<InvEnergy2> B3 = 0.5*(right[2]- left[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2;
+ vector<Complex> left = perturbativeVertex_[0]-> left();
+ vector<Complex> right = perturbativeVertex_[0]->right();
+ Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_[0]-> norm();
+ Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_[0]-> norm();
+ complex<InvEnergy> A2 = 0.5*(left [1]+right[1])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE;
+ complex<InvEnergy> B2 = 0.5*(right[1]- left[1])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE;
+ complex<InvEnergy2> A3 = 0.5*(left [2]+right[2])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE2;
+ complex<InvEnergy2> B3 = 0.5*(right[2]- left[2])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE2;
complex<Energy> h1(-2.*Qp*A1),h2(2.*Qm*B1);
complex<Energy> h3(-2./r3*Qp*(A1-Qm*Qm/m2*A2));
complex<Energy> h4( 2./r3*Qm*(B1-Qp*Qp/m2*B2));
complex<Energy> h5(ZERO),h6(ZERO);
if(outb.second>ZERO) {
h5 = -2.*r2/r3/m2/m3*Qp*(0.5*(m12-m22-m32)*A1+0.5*Qm*Qm*(m1+m2)*A2
+m12*pcm*pcm*A3);
h6 = 2.*r2/r3/m2/m3*Qm*(0.5*(m12-m22-m32)*B1-0.5*Qp*Qp*(m1-m2)*B2
+m12*pcm*pcm*B3);
}
double me2 = 0.25*real(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+
h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.second);
Energy output = me2*pcm/8./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<FRVDecayer,GeneralTwoBodyDecayer>
describeHerwigFRVDecayer("Herwig::FRVDecayer", "Herwig.so");
void FRVDecayer::Init() {
static ClassDocumentation<FRVDecayer> documentation
("The FRVDecayer class handles the decay of a fermion to "
"a spin-3/2 particle and a vector boson.");
}
diff --git a/Decay/General/FRVDecayer.h b/Decay/General/FRVDecayer.h
--- a/Decay/General/FRVDecayer.h
+++ b/Decay/General/FRVDecayer.h
@@ -1,170 +1,171 @@
// -*- C++ -*-
//
// FRVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FRVDecayer_H
#define HERWIG_FRVDecayer_H
//
// This is the declaration of the FRVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/RFVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::RFVVertexPtr;
/** \ingroup Decay
* The FRVDecayer class implements the decay of a fermion
* to a spin-3/2 fermion and a vector in a general model. It holds an RFVVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class FRVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
FRVDecayer() {}
public:
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
FRVDecayer & operator=(const FRVDecayer &);
private:
/**
* Abstract pointer to AbstractFRVVertex
*/
- AbstractRFVVertexPtr vertex_;
+ vector<AbstractRFVVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- RFVVertexPtr perturbativeVertex_;
+ vector<RFVVertexPtr> perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Spinor wavefunction
*/
mutable vector<SpinorWaveFunction> wave_ ;
/**
* Barred spinor wavefunction
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* RS Spinor wavefunction
*/
mutable vector<RSSpinorWaveFunction> RSwave_ ;
/**
* Barred RS spinor wavefunction
*/
mutable vector<RSSpinorBarWaveFunction> RSwavebar_;
/**
* Polarization vectors
*/
mutable vector<VectorWaveFunction> vector_;
};
}
#endif /* HERWIG_FRVDecayer_H */
diff --git a/Decay/General/FtoFFFDecayer.cc b/Decay/General/FtoFFFDecayer.cc
--- a/Decay/General/FtoFFFDecayer.cc
+++ b/Decay/General/FtoFFFDecayer.cc
@@ -1,308 +1,309 @@
// -*- 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,
MEOption meopt) const {
// particle or CC of particle
bool cc = (*getProcessInfo().begin()).incoming != inpart.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()));
if(meopt==Initialize) {
SpinorWaveFunction::
calculateWaveFunctions(inwave_.first,rho_,const_ptr_cast<tPPtr>(&inpart),
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();
}
}
}
// 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);
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;
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) {
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/FtoFVVDecayer.cc b/Decay/General/FtoFVVDecayer.cc
--- a/Decay/General/FtoFVVDecayer.cc
+++ b/Decay/General/FtoFVVDecayer.cc
@@ -1,400 +1,401 @@
// -*- 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);
}
}
}
double FtoFVVDecayer::me2(const int ichan, const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
// particle or CC of particle
bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
// special handling or first/last call
//Set up wave-functions
bool ferm( inpart.id() > 0 );
if(meopt==Initialize) {
if( ferm ) {
SpinorWaveFunction::
calculateWaveFunctions(fwave_,rho_,const_ptr_cast<tPPtr>(&inpart),
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),
Helicity::incoming);
if( fbwave_[0].wave().Type() != SpinorType::v )
fbwave_[0].conjugate();
if( fbwave_[1].wave().Type() != SpinorType::v )
fbwave_[1].conjugate();
}
}
// 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 ) {
isp = ix;
if( ferm ) {
SpinorBarWaveFunction::
calculateWaveFunctions(fbwave_, p, 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);
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;
if( ivec < 0 ) {
ivec = ix;
VectorWaveFunction::
calculateWaveFunctions(vwave_.first , p, Helicity::outgoing, massless);
mass.first = massless;
}
else {
VectorWaveFunction::
calculateWaveFunctions(vwave_.second, p, Helicity::outgoing, massless);
mass.second = massless;
}
}
}
assert(isp >= 0 && ivec >= 0);
Energy2 scale(sqr(inpart.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/GeneralThreeBodyDecayer.cc b/Decay/General/GeneralThreeBodyDecayer.cc
--- a/Decay/General/GeneralThreeBodyDecayer.cc
+++ b/Decay/General/GeneralThreeBodyDecayer.cc
@@ -1,1033 +1,1028 @@
// -*- 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 "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>
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;
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
- return setColourFactors(symfac);
+ if(setColourFactors(symfac)) return true;
+ incoming_= PDPtr();
+ outgoing_.clear();
+ return false;
}
void GeneralThreeBodyDecayer::doinit() {
DecayIntegrator::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;
// 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));
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);
}
diagmap_.push_back(ix);
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() + " ";
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);
}
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]=
{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)->
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);
}
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();
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) {
- 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(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/GeneralTwoBodyDecayer.h b/Decay/General/GeneralTwoBodyDecayer.h
--- a/Decay/General/GeneralTwoBodyDecayer.h
+++ b/Decay/General/GeneralTwoBodyDecayer.h
@@ -1,305 +1,306 @@
// -*- C++ -*-
//
// GeneralTwoBodyDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_GeneralTwoBodyDecayer_H
#define HERWIG_GeneralTwoBodyDecayer_H
//
// This is the declaration of the GeneralTwoBodyDecayer class.
//
#include "Herwig/Decay/PerturbativeDecayer.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "ThePEG/Helicity/Vertex/VertexBase.h"
#include "GeneralTwoBodyDecayer.fh"
namespace Herwig {
using namespace ThePEG;
using Helicity::VertexBasePtr;
/** \ingroup Decay
* The GeneralTwoBodyDecayer class is designed to be the base class
* for 2 body decays for some general model. It inherits from
* PerturbativeDecayer and implements the modeNumber() virtual function
* that is the same for all of the decays. A decayer for
* a specific spin configuration should inherit from this and implement
* the me2() and partialWidth() member functions. The colourConnections()
* member should be called from inside me2() in the inheriting decayer
* to set up the colour lines.
*
* @see \ref GeneralTwoBodyDecayerInterfaces "The interfaces"
* defined for GeneralTwoBodyDecayer.
* @see PerturbativeDecayer
*/
class GeneralTwoBodyDecayer: public PerturbativeDecayer {
public:
/** A ParticleData ptr and (possible) mass pair.*/
typedef pair<tcPDPtr, Energy> PMPair;
public:
/**
* The default constructor.
*/
GeneralTwoBodyDecayer() : maxWeight_(1.), colour_(1,DVector(1,1.))
{}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* For a given decay mode and a given particle instance, perform the
* decay and return the decay products. As this is the base class this
* is not implemented.
* @return The vector of particles produced in the decay.
*/
virtual ParticleVector decay(const Particle & parent,
const tPDVector & children) const;
/**
* Which of the possible decays is required
* @param cc Is this mode the charge conjugate
* @param parent The decaying particle
* @param children The decay products
*/
virtual int modeNumber(bool & cc, tcPDPtr parent,const tPDVector & children) const;
/**
* Return the matrix element squared for a given mode and phase-space channel
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int , const Particle & part,
const ParticleVector & decay, MEOption meopt) const = 0;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Specify the \f$1\to2\f$ matrix element to be used in the running width
* calculation.
* @param dm The DecayMode
* @param mecode The code for the matrix element as described
* in the GenericWidthGenerator class.
* @param coupling The coupling for the matrix element.
* @return True if the the order of the particles in the
* decayer is the same as the DecayMode tag.
*/
virtual bool twoBodyMEcode(const DecayMode & dm, int & mecode,
double & coupling) const;
/**
* An overidden member to calculate a branching ratio for a certain
* particle instance.
* @param dm The DecayMode of the particle
* @param p The particle object
* @param oldbrat The branching fraction given in the DecayMode object
*/
virtual double brat(const DecayMode & dm, const Particle & p,
double oldbrat) const;
//@}
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing,
+ vector<VertexBasePtr>,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > &,
map<ShowerInteraction,VertexBasePtr>) =0;
protected:
/** @name Functions used by inheriting decayers. */
//@{
/**
* Set integration weight
* @param wgt Maximum integration weight
*/
void setWeight(double wgt) { maxWeight_ = wgt; }
/**
* Set colour connections
* @param parent Parent particle
* @param out Particle vector containing particles to
* connect colour lines
*/
void colourConnections(const Particle & parent,
const ParticleVector & out) const;
/**
* Compute the spin and colour factor
*/
double colourFactor(tcPDPtr in, tcPDPtr out1, tcPDPtr out2) const;
/**
* Calculate matrix element ratio R/B
*/
double matrixElementRatio(const Particle & inpart, const ParticleVector & decay2,
const ParticleVector & decay3, MEOption meopt,
ShowerInteraction inter);
/**
* Set the information on the decay
*/
void decayInfo(PDPtr incoming, PDPair outgoing);
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
//@}
protected:
/**
* Member for the generation of additional hard radiation
*/
//@{
/**
* Return the matrix of colour factors
*/
typedef vector<pair<int,double > > CFlowPairVec;
typedef vector<CFlowPairVec> CFlow;
const vector<DVector> & getColourFactors(const Particle & inpart,
const ParticleVector & decay,
unsigned int & nflow);
const CFlow & colourFlows(const Particle & inpart,
const ParticleVector & decay);
/**
* Three-body matrix element including additional QCD radiation
*/
virtual double threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt);
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
GeneralTwoBodyDecayer & operator=(const GeneralTwoBodyDecayer &);
private:
/**
* Store the incoming particle
*/
PDPtr incoming_;
/**
* Outgoing particles
*/
vector<PDPtr> outgoing_;
/**
* Maximum weight for integration
*/
double maxWeight_;
/**
* Store colour factors for ME calc.
*/
vector<DVector> colour_;
};
/**
* Write a map with ShowerInteraction as the key
*/
template<typename T, typename Cmp, typename A>
inline PersistentOStream & operator<<(PersistentOStream & os,
const map<ShowerInteraction,T,Cmp,A> & m) {
os << m.size();
if(m.find(ShowerInteraction::QCD)!=m.end()) {
os << 0 << m.at(ShowerInteraction::QCD);
}
if(m.find(ShowerInteraction::QED)!=m.end()) {
os << 1 << m.at(ShowerInteraction::QED);
}
return os;
}
/**
* Read a map with ShowerInteraction as the key
*/
template <typename T, typename Cmp, typename A>
inline PersistentIStream & operator>>(PersistentIStream & is, map<ShowerInteraction,T,Cmp,A> & m) {
m.clear();
long size;
int k;
is >> size;
while ( size-- && is ) {
is >> k;
if(k==0)
is >> m[ShowerInteraction::QCD];
else if(k==1)
is >> m[ShowerInteraction::QED];
else
assert(false);
}
return is;
}
}
#endif /* HERWIG_GeneralTwoBodyDecayer_H */
diff --git a/Decay/General/SFFDecayer.cc b/Decay/General/SFFDecayer.cc
--- a/Decay/General/SFFDecayer.cc
+++ b/Decay/General/SFFDecayer.cc
@@ -1,478 +1,491 @@
// -*- C++ -*-
//
// SFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SFFDecayer class.
//
#include "SFFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SFFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SFFDecayer::fullclone() const {
return new_ptr(*this);
}
void SFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> ) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractFFSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<FFSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractFFSVertexPtr>(vert));
+ perturbativeVertex_ .push_back(dynamic_ptr_cast<FFSVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(inV.at(inter));
outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[0].at(inter));
outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[1].at(inter));
}
}
void SFFDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertex1_
<< outgoingVertex2_;
}
void SFFDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertex1_
>> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SFFDecayer,GeneralTwoBodyDecayer>
describeHerwigSFFDecayer("Herwig::SFFDecayer", "Herwig.so");
void SFFDecayer::Init() {
static ClassDocumentation<SFFDecayer> documentation
("This class implements to decay of a scalar to 2 fermions");
}
double SFFDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin1Half)));
// work out which is the fermion and antifermion
int iferm(1),ianti(0);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0||itype[1]==1||(itype[0]==2&&itype[1]==2)) swap(iferm,ianti);
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave_ ,decay[ianti],outgoing,true);
return 0.;
}
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[ianti],outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int ifm = 0; ifm < 2; ++ifm){
for(unsigned int ia = 0; ia < 2; ++ia) {
- if(iferm > ianti){
- (*ME())(0, ia, ifm) = vertex_->evaluate(scale,wave_[ia],
- wavebar_[ifm],swave_);
- }
- else {
- (*ME())(0, ifm, ia) = vertex_->evaluate(scale,wave_[ia],
- wavebar_[ifm],swave_);
+ if(iferm > ianti) (*ME())(0, ia, ifm) = 0.;
+ else (*ME())(0, ifm, ia) = 0.;
+ for(auto vert : vertex_) {
+ if(iferm > ianti){
+ (*ME())(0, ia, ifm) += vert->evaluate(scale,wave_[ia],
+ wavebar_[ifm],swave_);
+ }
+ else {
+ (*ME())(0, ifm, ia) += vert->evaluate(scale,wave_[ia],
+ wavebar_[ifm],swave_);
+ }
}
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy SFFDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(sqr(inpart.second), outb.first, outa.first,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outb.first, outa.first,
in);
double mu1(outa.second/inpart.second),mu2(outb.second/inpart.second);
- double c2 = norm(perturbativeVertex_->norm());
- Complex al(perturbativeVertex_->left()), ar(perturbativeVertex_->right());
+ double c2 = norm(perturbativeVertex_[0]->norm());
+ Complex al(perturbativeVertex_[0]->left()), ar(perturbativeVertex_[0]->right());
double me2 = -c2*( (norm(al) + norm(ar))*( sqr(mu1) + sqr(mu2) - 1.)
+ 2.*(ar*conj(al) + al*conj(ar)).real()*mu1*mu2 );
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
Energy output = me2*pcm/(8*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double SFFDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
// work out which is the fermion and antifermion
int ianti(0), iferm(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti);
if(itype[0]==2 && itype[1]==1) swap(iferm, ianti);
if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(meopt==Initialize) {
// create scalar wavefunction for decaying particle
ScalarWaveFunction::
calculateWaveFunctions(rho3_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
// setup spin information when needed
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_ ,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave3_ ,decay[ianti],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1Half,
PDT::Spin1Half, PDT::Spin1)));
// create wavefunctions
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave3_ , decay[ianti],outgoing);
VectorWaveFunction::
calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true);
// gauge invariance test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
// identify fermion and/or anti-fermion vertex
AbstractFFVVertexPtr outgoingVertexF;
AbstractFFVVertexPtr outgoingVertexA;
identifyVertices(iferm, ianti, inpart, decay, outgoingVertexF, outgoingVertexA,
inter);
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
Energy2 scale(sqr(inpart.mass()));
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int ifm = 0; ifm < 2; ++ifm) {
for(unsigned int ia = 0; ia < 2; ++ia) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming scalar
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
ScalarWaveFunction scalarInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),
gluon_[2*ig],swave3_,inpart.mass());
assert(swave3_.particle()->id()==scalarInter.particle()->id());
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
- Complex diag = vertex_->evaluate(scale,wave3_[ia],
- wavebar3_[ifm],scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ia],
+ wavebar3_[ifm],scalarInter);
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(0, ia, ifm, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing fermion
if((decay[iferm]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED)) {
assert(outgoingVertexF);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
SpinorBarWaveFunction interS =
outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
gluon_[2*ig],decay[iferm]->mass());
assert(wavebar3_[ifm].particle()->id()==interS.particle()->id());
if(!couplingSet) {
gs = abs(outgoingVertexF->norm());
couplingSet = true;
}
- Complex diag = vertex_->evaluate(scale,wave3_[ia], interS,swave3_);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ia], interS,swave3_);
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(0, ia, ifm, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing antifermion
if((decay[ianti]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED)) {
assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
SpinorWaveFunction interS =
outgoingVertexA->evaluate(scale,3,off,wave3_[ia],
gluon_[2*ig],decay[ianti]->mass());
assert(wave3_[ia].particle()->id()==interS.particle()->id());
if(!couplingSet) {
gs = abs(outgoingVertexA->norm());
couplingSet = true;
}
- Complex diag = vertex_->evaluate(scale,interS,wavebar3_[ifm],swave3_);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,interS,wavebar3_[ifm],swave3_);
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(0, ia, ifm, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha(S,EM)
output *= (4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
void SFFDecayer::identifyVertices(const int iferm, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractFFVVertexPtr & outgoingVertexF,
AbstractFFVVertexPtr & outgoingVertexA,
ShowerInteraction inter) {
// QCD
if(inter==ShowerInteraction::QCD) {
// work out which fermion each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[iferm]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8))) {
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) {
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr()->iColour()==PDT::Colour3){
if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertexF = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertexF = outgoingVertex2_[inter];
}
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8) {
if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[ianti]->dataPtr()))) {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
else {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
}
else if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) {
if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){
if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter];
}
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3) {
if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour6 ||
inpart.dataPtr()->iColour()==PDT::Colour6bar) {
if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
if (! ((incomingVertex_[inter] && (outgoingVertexF || outgoingVertexA)) ||
( outgoingVertexF && outgoingVertexA))) {
throw Exception()
<< "Invalid vertices for QCD radiation in SFF decay in SFFDecayer::identifyVertices"
<< Exception::runerror;
}
}
// QED
else {
if(decay[iferm]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr())))
outgoingVertexF = outgoingVertex1_[inter];
else
outgoingVertexF = outgoingVertex2_[inter];
}
if(decay[ianti]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[ianti]->dataPtr())))
outgoingVertexA = outgoingVertex1_[inter];
else
outgoingVertexA = outgoingVertex2_[inter];
}
}
}
diff --git a/Decay/General/SFFDecayer.h b/Decay/General/SFFDecayer.h
--- a/Decay/General/SFFDecayer.h
+++ b/Decay/General/SFFDecayer.h
@@ -1,226 +1,234 @@
// -*- C++ -*-
//
// SFFDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SFFDecayer_H
#define HERWIG_SFFDecayer_H
//
// This is the declaration of the SFFDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/FFSVertex.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFSVertexPtr;
/** \ingroup Decay
* The SFFDecayer class implements the decay of a scalar to 2
* fermions in a general model. It holds an FFSVertex pointer that
* must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class SFFDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SFFDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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, VertexBasePtr,
+ 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
*/
- AbstractFFSVertexPtr vertex_;
+ vector<AbstractFFSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- FFSVertexPtr perturbativeVertex_;
+ 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/SRFDecayer.cc b/Decay/General/SRFDecayer.cc
--- a/Decay/General/SRFDecayer.cc
+++ b/Decay/General/SRFDecayer.cc
@@ -1,181 +1,196 @@
// -*- C++ -*-
//
// SRFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SRFDecayer class.
//
#include "SRFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SRFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SRFDecayer::fullclone() const {
return new_ptr(*this);
}
void SRFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > &,
map<ShowerInteraction,VertexBasePtr>) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractRFSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<RFSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractRFSVertexPtr>(vert));
+ perturbativeVertex_ .push_back(dynamic_ptr_cast<RFSVertexPtr> (vert));
+ }
}
void SRFDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_;
}
void SRFDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SRFDecayer,GeneralTwoBodyDecayer>
describeHerwigSRFDecayer("Herwig::SRFDecayer", "Herwig.so");
void SRFDecayer::Init() {
static ClassDocumentation<SRFDecayer> documentation
("This class implements to decay of a scalar to a spin-3/2 and"
" spin-1/2 fermion");
}
double SRFDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,MEOption meopt) const {
unsigned int irs=0,ifm=1;
if(decay[0]->dataPtr()->iSpin()==PDT::Spin1Half) swap(irs,ifm);
if(!ME()) {
if(irs==0)
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin3Half,PDT::Spin1Half)));
else
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin3Half)));
}
bool ferm = decay[ifm]->id()<0;
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
if(ferm) {
RSSpinorBarWaveFunction::
constructSpinInfo(RSwavebar_,decay[irs],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave_ ,decay[ifm],outgoing,true);
}
else {
RSSpinorWaveFunction::
constructSpinInfo(RSwave_ ,decay[irs],outgoing,true);
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,decay[ifm],outgoing,true);
}
return 0.;
}
if(ferm) {
RSSpinorBarWaveFunction::
calculateWaveFunctions(RSwavebar_,decay[irs],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[ifm],outgoing);
}
else {
RSSpinorWaveFunction::
calculateWaveFunctions(RSwave_ ,decay[irs],outgoing);
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[ifm],outgoing);
}
Energy2 scale(sqr(inpart.mass()));
for(unsigned int ifm = 0; ifm < 4; ++ifm){
for(unsigned int ia = 0; ia < 2; ++ia) {
if(irs==0) {
- if(ferm)
- (*ME())(0, ifm, ia) = vertex_->evaluate(scale,wave_[ia],
- RSwavebar_[ifm],swave_);
- else
- (*ME())(0, ifm, ia) = vertex_->evaluate(scale,RSwave_[ifm],
- wavebar_[ia],swave_);
+ if(ferm) {
+ (*ME())(0, ifm, ia) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(0, ifm, ia) += vert->evaluate(scale,wave_[ia],
+ RSwavebar_[ifm],swave_);
+ }
+ else {
+ (*ME())(0, ifm, ia) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(0, ifm, ia) += vert->evaluate(scale,RSwave_[ifm],
+ wavebar_[ia],swave_);
+ }
}
else {
- if(ferm)
- (*ME())(0, ia, ifm) = vertex_->evaluate(scale,wave_[ia],
- RSwavebar_[ifm],swave_);
- else
- (*ME())(0, ia, ifm) = vertex_->evaluate(scale,RSwave_[ifm],
- wavebar_[ia],swave_);
+ if(ferm) {
+ (*ME())(0, ia, ifm) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(0, ia, ifm) += vert->evaluate(scale,wave_[ia],
+ RSwavebar_[ifm],swave_);
+ }
+ else {
+ (*ME())(0, ia, ifm) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(0, ia, ifm) += vert->evaluate(scale,RSwave_[ifm],
+ wavebar_[ia],swave_);
+ }
}
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[irs]->dataPtr(),
decay[ifm]->dataPtr());
// return the answer
return output;
}
Energy SRFDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
Energy q = inpart.second;
Energy m1 = outa.second, m2 = outb.second;
// couplings
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if(outa.first->iSpin()==PDT::Spin1Half) {
swap(m1,m2);
- perturbativeVertex_->setCoupling(sqr(inpart.second),outb.first,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second),outb.first,
outa.first, in);
}
else {
- perturbativeVertex_->setCoupling(sqr(inpart.second),outa.first,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second),outa.first,
outb.first, in);
}
- Complex left = perturbativeVertex_-> left()*perturbativeVertex_-> norm();
- Complex right = perturbativeVertex_->right()*perturbativeVertex_-> norm();
+ Complex left = perturbativeVertex_[0]-> left()*perturbativeVertex_[0]-> norm();
+ Complex right = perturbativeVertex_[0]->right()*perturbativeVertex_[0]-> norm();
complex<InvEnergy> A1 = 0.5*(left+right)*UnitRemoval::InvE;
complex<InvEnergy> B1 = 0.5*(right-left)*UnitRemoval::InvE;
Energy2 q2(q*q),m12(m1*m1),m22(m2*m2);
Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2);
Energy pcm(sqrt(pcm2));
Energy Qp(sqrt(-sqr(m2+m1)+q2)),Qm(sqrt(-sqr(m2-m1)+q2));
double r23(sqrt(2./3.));
complex<Energy> h1(-2.*r23*pcm*q/m1*Qm*B1);
complex<Energy> h2( 2.*r23*pcm*q/m1*Qp*A1);
double me2 = real(h1*conj(h1)+h2*conj(h2))/2./sqr(inpart.second);
Energy output = me2*pcm/8./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/SRFDecayer.h b/Decay/General/SRFDecayer.h
--- a/Decay/General/SRFDecayer.h
+++ b/Decay/General/SRFDecayer.h
@@ -1,170 +1,171 @@
// -*- C++ -*-
//
// SRFDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SRFDecayer_H
#define HERWIG_SRFDecayer_H
//
// This is the declaration of the SRFDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/RFSVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::RFSVertexPtr;
/** \ingroup Decay
* The SRFDecayer class implements the decay of a scalar to spin-3/2
* and spin-1/2 fermion in a general model. It holds an RFSVertex pointer that
* must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class SRFDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SRFDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
SRFDecayer & operator=(const SRFDecayer &);
private:
/**
* Abstract pointer to AbstractFFSVertex
*/
- AbstractRFSVertexPtr vertex_;
+ vector<AbstractRFSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- RFSVertexPtr perturbativeVertex_;
+ vector<RFSVertexPtr> perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable ScalarWaveFunction swave_;
/**
* Spinor wavefunction
*/
mutable vector<SpinorWaveFunction> wave_;
/**
* Barred spinor wavefunction
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* RS Spinor wavefunction
*/
mutable vector<RSSpinorWaveFunction> RSwave_;
/**
* Barred RS spinor wavefunction
*/
mutable vector<RSSpinorBarWaveFunction> RSwavebar_;
};
}
#endif /* HERWIG_SRFDecayer_H */
diff --git a/Decay/General/SSSDecayer.cc b/Decay/General/SSSDecayer.cc
--- a/Decay/General/SSSDecayer.cc
+++ b/Decay/General/SSSDecayer.cc
@@ -1,398 +1,410 @@
// -*- C++ -*-
//
// SSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSSDecayer class.
//
#include "SSSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SSSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SSSDecayer::fullclone() const {
return new_ptr(*this);
}
void SSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> ) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractSSSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<SSSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractSSSVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<SSSVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(inV.at(inter));
outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
}
}
void SSSDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertex1_
<< outgoingVertex2_;
}
void SSSDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertex1_
>> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSSDecayer,GeneralTwoBodyDecayer>
describeHerwigSSSDecayer("Herwig::SSSDecayer", "Herwig.so");
void SSSDecayer::Init() {
static ClassDocumentation<SSSDecayer> documentation
("This class implements the decay of a scalar to 2 scalars.");
}
double SSSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin0)));
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
for(unsigned int ix=0;ix<2;++ix)
ScalarWaveFunction::
constructSpinInfo(decay[ix],outgoing,true);
}
ScalarWaveFunction s1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing);
ScalarWaveFunction s2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
- (*ME())(0,0,0) = vertex_->evaluate(scale,s1,s2,swave_);
+ (*ME())(0,0,0) = 0.;
+ for(auto vert : vertex_) {
+ (*ME())(0,0,0) += vert->evaluate(scale,s1,s2,swave_);
+ }
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy SSSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_ && !perturbativeVertex_->kinematics()) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0] && !perturbativeVertex_[0]->kinematics()) {
Energy2 scale(sqr(inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(scale, in, outa.first, outb.first);
+ perturbativeVertex_[0]->setCoupling(scale, in, outa.first, outb.first);
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
- double c2 = norm(perturbativeVertex_->norm());
+ double c2 = norm(perturbativeVertex_[0]->norm());
Energy pWidth = c2*pcm/8./Constants::pi/scale*UnitRemoval::E2;
// colour factor
pWidth *= colourFactor(inpart.first,outa.first,outb.first);
return pWidth;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double SSSDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
// work out which is the scalar and anti scalar
int ianti(0), iscal(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(ianti, iscal);
if(itype[0]==2 && itype[1]==1) swap(ianti, iscal);
if(itype[0]==0 && itype[1]==0 && abs(decay[0]->dataPtr()->id())>abs(decay[1]->dataPtr()->id()))
swap(iscal, ianti);
if(itype[0]==1 && itype[1]==1 && abs(decay[0]->dataPtr()->id())<abs(decay[1]->dataPtr()->id()))
swap(iscal, ianti);
if(meopt==Initialize) {
// create scalar wavefunction for decaying particle
ScalarWaveFunction::calculateWaveFunctions(rho3_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
// setup spin information when needed
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
ScalarWaveFunction::
constructSpinInfo(decay[iscal],outgoing,true);
ScalarWaveFunction::
constructSpinInfo(decay[ianti],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin0,
PDT::Spin0, PDT::Spin1)));
// create wavefunctions
ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing);
ScalarWaveFunction anti(decay[ianti]->momentum(), decay[ianti]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(gluon_,decay[iglu ],outgoing,true);
// gauge invariance test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
AbstractVSSVertexPtr outgoingVertexS;
AbstractVSSVertexPtr outgoingVertexA;
identifyVertices(iscal, ianti, inpart, decay, outgoingVertexS, outgoingVertexA,inter);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming scalar
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
ScalarWaveFunction scalarInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),
gluon_[2*ig],swave3_,inpart.mass());
assert(swave3_.particle()->id()==scalarInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,scal,anti,scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,scal,anti,scalarInter);
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(0, 0, 0, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the outgoing scalar
if((decay[iscal]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexS);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iscal]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
outgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass());
assert(scal.particle()->id()==scalarInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,swave3_,anti,scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,swave3_,anti,scalarInter);
if(!couplingSet) {
gs = abs(outgoingVertexS->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(0, 0, 0, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the outgoing anti scalar
if((decay[ianti]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
outgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass());
assert(anti.particle()->id()==scalarInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,swave3_,scal,scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,swave3_,scal,scalarInter);
if(!couplingSet) {
gs = abs(outgoingVertexA->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(0, 0, 0, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(S,EM)
output*=(4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
void SSSDecayer::identifyVertices(const int iscal, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractVSSVertexPtr & outgoingVertexS,
AbstractVSSVertexPtr & outgoingVertexA,
ShowerInteraction inter){
// QCD
if(inter==ShowerInteraction::QCD) {
// work out which scalar each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[iscal]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
outgoingVertexS = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
outgoingVertexS = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr() ->iColour()==PDT::Colour3){
if(decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertexS = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertexS = outgoingVertex2_[inter];
}
else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8){
if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
outgoingVertexS = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
else {
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour3bar){
if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter];
}
else if (decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour8){
if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else {
outgoingVertexS = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
}
if (! ((incomingVertex_[inter] && (outgoingVertexS || outgoingVertexA)) ||
( outgoingVertexS && outgoingVertexA)))
throw Exception()
<< "Invalid vertices for QCD radiation in SSS decay in SSSDecayer::identifyVertices"
<< Exception::runerror;
}
// QED
else {
if(decay[iscal]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iscal]->dataPtr())))
outgoingVertexS = outgoingVertex1_[inter];
else
outgoingVertexS = outgoingVertex2_[inter];
}
if(decay[ianti]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[ianti]->dataPtr())))
outgoingVertexA = outgoingVertex1_[inter];
else
outgoingVertexA = outgoingVertex2_[inter];
}
}
}
diff --git a/Decay/General/SSSDecayer.h b/Decay/General/SSSDecayer.h
--- a/Decay/General/SSSDecayer.h
+++ b/Decay/General/SSSDecayer.h
@@ -1,203 +1,211 @@
// -*- C++ -*-
//
// SSSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SSSDecayer_H
#define HERWIG_SSSDecayer_H
//
// This is the declaration of the SSSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/SSSVertex.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::SSSVertexPtr;
/** \ingroup Decay
* The SSDecayer class implements the decay of a scalar
* to 2 scalars in a general model. It holds a SSSVertex
* pointer that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class SSSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SSSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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 scalar and anti scalar
*/
void identifyVertices(const int iscal, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractVSSVertexPtr & abstractOutgoingVertexS,
AbstractVSSVertexPtr & abstractOutgoingVertexA,
ShowerInteraction inter);
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
SSSDecayer & operator=(const SSSDecayer &);
private:
/**
* Abstract pointer to AbstractSSSVertex
*/
- AbstractSSSVertexPtr vertex_;
+ vector<AbstractSSSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- SSSVertexPtr perturbativeVertex_;
+ vector<SSSVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from incoming scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from outgoing scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from outgoing scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertex2_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunctions
*/
mutable Helicity::ScalarWaveFunction swave_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable Helicity::ScalarWaveFunction swave3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_SSSDecayer_H */
diff --git a/Decay/General/SSVDecayer.cc b/Decay/General/SSVDecayer.cc
--- a/Decay/General/SSVDecayer.cc
+++ b/Decay/General/SSVDecayer.cc
@@ -1,351 +1,366 @@
// -*- C++ -*-
//
// SSVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSVDecayer class.
//
#include "SSVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SSVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SSVDecayer::fullclone() const {
return new_ptr(*this);
}
void SSVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> fourV) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<VSSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractVSSVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<VSSVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(inV.at(inter));
fourPointVertex_[inter] = dynamic_ptr_cast<AbstractVVSSVertexPtr>(fourV.at(inter));
outgoingVertexS_[inter] = AbstractVSSVertexPtr();
outgoingVertexV_[inter] = AbstractVVVVertexPtr();
if(outV[0].at(inter)) {
if (outV[0].at(inter)->getName()==VertexType::VSS)
outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
else
outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[0].at(inter));
}
if(outV[1].at(inter)) {
if (outV[1].at(inter)->getName()==VertexType::VSS)
outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
else
outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[1].at(inter));
}
}
}
void SSVDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertexS_
<< outgoingVertexV_ << fourPointVertex_;
}
void SSVDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertexS_
>> outgoingVertexV_ >> fourPointVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSVDecayer,GeneralTwoBodyDecayer>
describeHerwigSSVDecayer("Herwig::SSVDecayer", "Herwig.so");
void SSVDecayer::Init() {
static ClassDocumentation<SSVDecayer> documentation
("This implements the decay of a scalar to a vector and a scalar");
}
double SSVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
unsigned int isc(0),ivec(1);
if(decay[0]->dataPtr()->iSpin() != PDT::Spin0) swap(isc,ivec);
if(!ME()) {
if(ivec==1)
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin1)));
else
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin0)));
}
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
ScalarWaveFunction::
constructSpinInfo(decay[isc],outgoing,true);
VectorWaveFunction::
constructSpinInfo(vector_,decay[ivec],outgoing,true,false);
}
VectorWaveFunction::
calculateWaveFunctions(vector_,decay[ivec],outgoing,false);
ScalarWaveFunction sca(decay[isc]->momentum(),decay[isc]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
//make sure decay matrix element is in the correct order
double output(0.);
if(ivec == 0) {
- for(unsigned int ix = 0; ix < 3; ++ix)
- (*ME())(0, ix, 0) = vertex_->evaluate(scale,vector_[ix],sca, swave_);
+ for(unsigned int ix = 0; ix < 3; ++ix) {
+ (*ME())(0, ix, 0) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(0, ix, 0) += vert->evaluate(scale,vector_[ix],sca, swave_);
+ }
}
else {
- for(unsigned int ix = 0; ix < 3; ++ix)
- (*ME())(0, 0, ix) = vertex_->evaluate(scale,vector_[ix],sca,swave_);
+ for(unsigned int ix = 0; ix < 3; ++ix) {
+ (*ME())(0, 0, ix) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(0, 0, ix) += vert->evaluate(scale,vector_[ix],sca,swave_);
+ }
}
output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy SSVDecayer:: partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
double mu1sq(sqr(outa.second/inpart.second)),
mu2sq(sqr(outb.second/inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if(outa.first->iSpin() == PDT::Spin0) {
- perturbativeVertex_->setCoupling(sqr(inpart.second), outb.first, outa.first,in);
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outb.first, outa.first,in);
}
else {
swap(mu1sq,mu2sq);
- perturbativeVertex_->setCoupling(sqr(inpart.second), outa.first, outb.first,in);
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, outb.first,in);
}
double me2(0.);
if(mu2sq == 0.)
me2 = -2.*mu1sq - 2.;
else
me2 = ( sqr(mu2sq - mu1sq) - 2.*(mu2sq + mu1sq) + 1. )/mu2sq;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second,
outb.second);
- Energy output = pcm*me2*norm(perturbativeVertex_->norm())/8./Constants::pi;
+ Energy output = pcm*me2*norm(perturbativeVertex_[0]->norm())/8./Constants::pi;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double SSVDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
int iscal (0), ivect (1), iglu (2);
// get location of outgoing scalar/vector
if(decay[1]->dataPtr()->iSpin()==PDT::Spin0) swap(iscal,ivect);
if(meopt==Initialize) {
// create scalar wavefunction for decaying particle
ScalarWaveFunction::calculateWaveFunctions(rho3_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
// setup spin information when needed
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
ScalarWaveFunction::
constructSpinInfo(decay[iscal],outgoing,true);
VectorWaveFunction::
constructSpinInfo(vector3_,decay[ivect],outgoing,true,false);
VectorWaveFunction::
constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin0,
PDT::Spin1, PDT::Spin1)));
// create wavefunctions
ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(vector3_,decay[ivect],outgoing,false);
VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true );
// gauge invariance test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
if (! ((incomingVertex_[inter] && (outgoingVertexS_[inter] || outgoingVertexV_[inter])) ||
(outgoingVertexS_[inter] && outgoingVertexV_[inter])))
throw Exception()
<< "Invalid vertices for radiation in SSV decay in SSVDecayer::threeBodyME"
<< Exception::runerror;
// sort out colour flows
int S(1), V(2);
if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[ivect]->dataPtr()->iColour()==PDT::Colour8)
swap(S,V);
else if (decay[ivect]->dataPtr()->iColour()==PDT::Colour3 &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour8)
swap(S,V);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int iv = 0; iv < 3; ++iv) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming scalar
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
ScalarWaveFunction scalarInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),
gluon_[2*ig],swave3_,inpart.mass());
assert(swave3_.particle()->id()==scalarInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vector3_[iv],scal,scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vector3_[iv],scal,scalarInter);
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(0, 0, iv, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the outgoing scalar
if((decay[iscal]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexS_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iscal]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass());
assert(scal.particle()->id()==scalarInter.particle()->id());
if(!couplingSet) {
gs = abs(outgoingVertexS_[inter]->norm());
couplingSet = true;
}
- Complex diag = vertex_->evaluate(scale,vector3_[iv],scalarInter,swave3_);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vector3_[iv],scalarInter,swave3_);
for(unsigned int ix=0;ix<colourFlow[S].size();++ix) {
(*ME[colourFlow[S][ix].first])(0, 0, iv, ig) +=
colourFlow[S][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing vector
if((decay[ivect]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[ivect]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexV_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ivect]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectorInter =
outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig],
vector3_[iv],decay[ivect]->mass());
assert(vector3_[iv].particle()->id()==vectorInter.particle()->id());
if(!couplingSet) {
gs = abs(outgoingVertexV_[inter]->norm());
couplingSet = true;
}
- Complex diag = vertex_->evaluate(scale,vectorInter,scal,swave3_);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectorInter,scal,swave3_);
for(unsigned int ix=0;ix<colourFlow[V].size();++ix) {
(*ME[colourFlow[V][ix].first])(0, 0, iv, ig) +=
colourFlow[V][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from 4 point vertex
if (fourPointVertex_[inter]) {
Complex diag = fourPointVertex_[inter]->evaluate(scale, gluon_[2*ig], vector3_[iv],
scal, swave3_);
for(unsigned int ix=0;ix<colourFlow[3].size();++ix) {
(*ME[colourFlow[3][ix].first])(0, 0, iv, ig) +=
colourFlow[3][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(S,EM)
output*=(4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
diff --git a/Decay/General/SSVDecayer.h b/Decay/General/SSVDecayer.h
--- a/Decay/General/SSVDecayer.h
+++ b/Decay/General/SSVDecayer.h
@@ -1,216 +1,224 @@
// -*- C++ -*-
//
// SSVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SSVDecayer_H
#define HERWIG_SSVDecayer_H
//
// This is the declaration of the SSVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
#include "ThePEG/Helicity/Vertex/Scalar/VVSSVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VSSVertexPtr;
/** \ingroup Decay
* The SSVDecayer class implements the decay of a scalar to a vector
* and a scalar in a general model. It holds an VSSVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class SSVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SSVDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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);
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
SSVDecayer & operator=(const SSVDecayer &);
private:
/**
* Abstract pointer to AbstractFFVVertex
*/
- AbstractVSSVertexPtr vertex_;
+ vector<AbstractVSSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- VSSVertexPtr perturbativeVertex_;
+ vector<VSSVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from incoming scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from outgoing scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertexS_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertexV_;
/**
* Abstract pointer to AbstractVVSSVertex for QCD radiation from 4 point vertex
*/
map<ShowerInteraction,AbstractVVSSVertexPtr> fourPointVertex_;
/**
* Spinor density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable Helicity::ScalarWaveFunction swave_;
/**
* Vector wavefunction
*/
mutable vector<Helicity::VectorWaveFunction> vector_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable Helicity::ScalarWaveFunction swave3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable Helicity::ScalarWaveFunction scal_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> vector3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_SSVDecayer_H */
diff --git a/Decay/General/SVVDecayer.cc b/Decay/General/SVVDecayer.cc
--- a/Decay/General/SVVDecayer.cc
+++ b/Decay/General/SVVDecayer.cc
@@ -1,421 +1,432 @@
// -*- C++ -*-
//
// SVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SVVDecayer class.
//
#include "SVVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/Vertex/Scalar/VVSVertex.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr SVVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr SVVDecayer::fullclone() const {
return new_ptr(*this);
}
void SVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> ) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractVVSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<VVSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractVVSVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<VVSVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(inV.at(inter));
outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[0].at(inter));
outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[1].at(inter));
}
}
void SVVDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertex1_
<< outgoingVertex2_;
}
void SVVDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertex1_
>> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SVVDecayer,GeneralTwoBodyDecayer>
describeHerwigSVVDecayer("Herwig::SVVDecayer", "Herwig.so");
void SVVDecayer::Init() {
static ClassDocumentation<SVVDecayer> documentation
("This implements the decay of a scalar to 2 vector bosons.");
}
double SVVDecayer::me2(const int , const Particle & inpart,
const ParticleVector& decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin1)));
bool photon[2];
for(unsigned int ix=0;ix<2;++ix)
photon[ix] = decay[ix]->mass()==ZERO;
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
constructSpinInfo(vectors_[ix],decay[ix],outgoing,true,photon[ix]);
}
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
calculateWaveFunctions(vectors_[ix],decay[ix],outgoing,photon[ix]);
Energy2 scale(sqr(inpart.mass()));
unsigned int iv1,iv2;
for(iv2 = 0; iv2 < 3; ++iv2) {
if( photon[1] && iv2 == 1 ) ++iv2;
for(iv1=0;iv1<3;++iv1) {
if( photon[0] && iv1 == 1) ++iv1;
- (*ME())(0, iv1, iv2) = vertex_->evaluate(scale,vectors_[0][iv1],
+ (*ME())(0, iv1, iv2) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(0, iv1, iv2) += vert->evaluate(scale,vectors_[0][iv1],
vectors_[1][iv2],swave_);
}
}
double output = ME()->contract(rho_).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy SVVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
Energy2 scale(sqr(inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(scale, outa.first ,
+ perturbativeVertex_[0]->setCoupling(scale, outa.first ,
outb.first, in);
double mu1sq = sqr(outa.second/inpart.second);
double mu2sq = sqr(outb.second/inpart.second);
double m1pm2 = mu1sq + mu2sq;
double me2(0.);
if( mu1sq > 0. && mu2sq > 0.)
me2 = ( m1pm2*(m1pm2 - 2.) + 8.*mu1sq*mu2sq + 1.)/4./mu1sq/mu2sq;
else if( mu1sq == 0. || mu2sq == 0. )
me2 = 3.;
else
me2 = 4.;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
- Energy output = norm(perturbativeVertex_->norm())*
+ Energy output = norm(perturbativeVertex_[0]->norm())*
me2*pcm/(8*Constants::pi)/scale*UnitRemoval::E2;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double SVVDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
if(meopt==Initialize) {
// create scalar wavefunction for decaying particle
ScalarWaveFunction::
calculateWaveFunctions(rho3_,const_ptr_cast<tPPtr>(&inpart),incoming);
swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming);
}
if(meopt==Terminate) {
ScalarWaveFunction::
constructSpinInfo(const_ptr_cast<tPPtr>(&inpart),incoming,true);
VectorWaveFunction::
constructSpinInfo(vectors3_[0],decay[0],outgoing,true,false);
VectorWaveFunction::
constructSpinInfo(vectors3_[1],decay[1],outgoing,true,false);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[2],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1,
PDT::Spin1, PDT::Spin1)));
bool massless[2];
for(unsigned int ix=0;ix<2;++ix)
massless[ix] = decay[ix]->mass()!=ZERO;
// create wavefunctions
VectorWaveFunction::calculateWaveFunctions(vectors3_[0],decay[0],outgoing,massless[0]);
VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[1],outgoing,massless[1]);
VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true);
// gauge test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[2]->momentum(),
decay[2]->dataPtr(),10,
outgoing));
}
}
#endif
// get the outgoing vertices
AbstractVVVVertexPtr outgoingVertex1;
AbstractVVVVertexPtr outgoingVertex2;
identifyVertices(inpart,decay, outgoingVertex1, outgoingVertex2,inter);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int iv1 = 0; iv1 < 3; ++iv1) {
if(massless[0] && iv1==1) continue;
for(unsigned int iv2 = 0; iv2 < 3; ++iv2) {
if(massless[1] && iv2==1) continue;
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming vector
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
ScalarWaveFunction scalarInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),gluon_[2*ig],
swave3_,inpart.mass());
assert(swave3_.particle()->id()==scalarInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vectors3_[0][iv1],
- vectors3_[1][iv2],scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectors3_[0][iv1],
+ vectors3_[1][iv2],scalarInter);
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(0, iv1, iv2, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the 1st outgoing vector
if((decay[0]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertex1);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[0]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectorInter =
outgoingVertex1->evaluate(scale,3,off,gluon_[2*ig],vectors3_[0][iv1],decay[0]->mass());
assert(vectors3_[0][iv1].particle()->id()==vectorInter.particle()->id());
- Complex diag =vertex_->evaluate(scale,vectorInter,vectors3_[1][iv2],swave3_);
+ Complex diag =0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectorInter,vectors3_[1][iv2],swave3_);
if(!couplingSet) {
gs = abs(outgoingVertex1->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(0, iv1, iv2, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
if((decay[1]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertex2);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[1]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectorInter =
outgoingVertex2->evaluate(scale,3,off, gluon_[2*ig],vectors3_[1][iv2],decay[1]->mass());
assert(vectors3_[1][iv2].particle()->id()==vectorInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vectors3_[0][iv1],vectorInter,swave3_);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectors3_[0][iv1],vectorInter,swave3_);
if(!couplingSet) {
gs = abs(outgoingVertex2->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(0, iv1, iv2, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(S,EM)
output*=(4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
void SVVDecayer::identifyVertices(const Particle & inpart, const ParticleVector & decay,
AbstractVVVVertexPtr & outgoingVertex1,
AbstractVVVVertexPtr & outgoingVertex2,
ShowerInteraction inter) {
if(inter==ShowerInteraction::QCD) {
// work out which scalar each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[0]->dataPtr()->iColour()==PDT::Colour3 &&
decay[1]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[0]->dataPtr()->iColour()==PDT::Colour8 &&
decay[1]->dataPtr()->iColour()==PDT::Colour8))){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){
outgoingVertex1 = outgoingVertex2_[inter];
outgoingVertex2 = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[0]->dataPtr()->iColour()==PDT::Colour3 &&
decay[1]->dataPtr()->iColour()==PDT::Colour3bar){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){
outgoingVertex1 = outgoingVertex2_[inter];
outgoingVertex2 = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr()->iColour()==PDT::Colour3){
if(decay[0]->dataPtr()->iColour()==PDT::Colour3 &&
decay[1]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertex1 = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertex1 = outgoingVertex2_[inter];
}
else if (decay[0]->dataPtr()->iColour()==PDT::Colour3 &&
decay[1]->dataPtr()->iColour()==PDT::Colour8){
if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->dataPtr()->id()))){
outgoingVertex1 = outgoingVertex2_[inter];
outgoingVertex2 = outgoingVertex1_[inter];
}
else {
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){
if(decay[1]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[0]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertex2 = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertex2 = outgoingVertex2_[inter];
}
else if (decay[0]->dataPtr()->iColour()==PDT::Colour8 &&
decay[1]->dataPtr()->iColour()==PDT::Colour3bar){
if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->dataPtr()->id()))){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else {
outgoingVertex1 = outgoingVertex2_[inter];
outgoingVertex2 = outgoingVertex1_[inter];
}
}
}
if (! ((incomingVertex_[inter] && (outgoingVertex1 || outgoingVertex2)) ||
( outgoingVertex1 && outgoingVertex2)))
throw Exception()
<< "Invalid vertices for QCD radiation in SVV decay in SVVDecayer::identifyVertices"
<< Exception::runerror;
}
else {
if(decay[0]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[0]->dataPtr())))
outgoingVertex1 = outgoingVertex1_[inter];
else
outgoingVertex1 = outgoingVertex2_[inter];
}
if(decay[1]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[1]->dataPtr())))
outgoingVertex2 = outgoingVertex1_[inter];
else
outgoingVertex2 = outgoingVertex2_[inter];
}
}
}
diff --git a/Decay/General/SVVDecayer.h b/Decay/General/SVVDecayer.h
--- a/Decay/General/SVVDecayer.h
+++ b/Decay/General/SVVDecayer.h
@@ -1,222 +1,230 @@
// -*- C++ -*-
//
// SVVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SVVDecayer_H
#define HERWIG_SVVDecayer_H
//
// This is the declaration of the SVVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Scalar/VVSVertex.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VVSVertexPtr;
/** \ingroup Decay
* This SVVDecayer class implements the decay of a scalar to
* 2 vector bosons using either the tree level VVSVertex or the loop vertex.
* It inherits from
* GeneralTwoBodyDecayer and implements the virtual member functions me2()
* and partialWidth(). It also stores a pointer to the VVSVertex.
*
* @see GeneralTwoBodyDecayer
*
*/
class SVVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
SVVDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing,
+ vector<VertexBasePtr>,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > &,
map<ShowerInteraction,VertexBasePtr>);
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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);
//@}
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:
/**
* Find the vertices for the decay
*/
void identifyVertices(const Particle & inpart, const ParticleVector & decay,
AbstractVVVVertexPtr & outgoingVertex1,
AbstractVVVVertexPtr & outgoingVertex2,
ShowerInteraction inter);
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SVVDecayer & operator=(const SVVDecayer &);
private:
/**
* Abstract pointer to general VVS vertex
*/
- AbstractVVSVertexPtr vertex_;
+ vector<AbstractVVSVertexPtr> vertex_;
/**
* Pointer to the perturbative form
*/
- VVSVertexPtr perturbativeVertex_;
+ vector<VVSVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVSSVertex for QCD radiation from incoming scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from the 1st outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from the 2nd outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertex2_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Scalar wavefunction
*/
mutable Helicity::ScalarWaveFunction swave_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors_[2];
private:
/**
* Member for the POWHEG correction
*/
//@{
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable ScalarWaveFunction swave3_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors3_[2];
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
//@}
};
}
#endif /* HERWIG_SVVDecayer_H */
diff --git a/Decay/General/StoFFVDecayer.cc b/Decay/General/StoFFVDecayer.cc
--- a/Decay/General/StoFFVDecayer.cc
+++ b/Decay/General/StoFFVDecayer.cc
@@ -1,331 +1,387 @@
// -*- 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_;
+ os << sca_ << fer_ << vec_ << RSfer_ << four_;
}
void StoFFVDecayer::persistentInput(PersistentIStream & is, int) {
- is >> sca_ >> fer_ >> vec_;
+ 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();
+ 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 {
// particle or CC of particle
bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
// special handling or first/last call
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),
Helicity::incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),
Helicity::incoming);
}
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) {
ivec = ix;
massless = decay[ivec]->mass()==ZERO;
VectorWaveFunction::
calculateWaveFunctions(outVector_, decay[ix], Helicity::outgoing,massless);
}
else {
SpinorWaveFunction::
calculateWaveFunctions(outspin_[ix].first,decay[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()));
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(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], swave_);
- unsigned int h1(s1),h2(s2);
- if(o2 > o3) swap(h1, h2);
- if(decay[o2]->id() < 0 && decay[o3]->id() > 0) {
- diag = -sign*sca_[idiag].second->
- evaluate(scale,outspin_[o2].first[h1],
- outspin_[o3].second[h2],inters);
+ 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) {
+ 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)
+ ? 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)) {
+ 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) {
+ 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)
+ ? 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)) {
+ 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) {
+ diag =-four_[idiag]->
+ evaluate(scale, outspin_[o2].first[s1],
+ outspin_[o3].second[s2], outVector_[v1], swave_);
}
else {
- diag = sign*sca_[idiag].second->
- evaluate(scale, outspin_[o3].first [h2],
- outspin_[o2].second[h1],inters);
+ diag = four_[idiag]->
+ evaluate(scale, outspin_[o3].first[s2],
+ outspin_[o2].second[s1], outVector_[v1], swave_);
}
}
- // intermediate fermion
- else if(offshell->iSpin() == PDT::Spin1Half) {
- int iferm = (decay[o2]->dataPtr()->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)) {
- 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) {
- 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);
- }
- }
- // unknown
- else throw Exception()
- << "Unknown intermediate in StoFFVDecayer::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])(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,149 +1,162 @@
// -*- 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.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Method to return an object to calculate the 3 (or higher body) partial width
* @param dm The DecayMode
* @return A pointer to a WidthCalculatorBase object capable of
* calculating the width
*/
virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const;
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,363 +1,422 @@
// -*- 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_;
+ os << sca_ << fer_ << vec_ << ten_ << RSfer_ << four_;
}
void StoSFFDecayer::persistentInput(PersistentIStream & is, int) {
- is >> sca_ >> fer_ >> vec_ >> ten_;
+ 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();
+ 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,
MEOption meopt) const {
// particle or CC of particle
bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
// special handling or first/last call
if(meopt==Initialize) {
ScalarWaveFunction::
calculateWaveFunctions(rho_,const_ptr_cast<tPPtr>(&inpart),
Helicity::incoming);
swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),
Helicity::incoming);
}
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) {
isca = ix;
outScalar = ScalarWaveFunction(decay[ix]->momentum(),
decay[ix]->dataPtr(),Helicity::outgoing);
}
else {
SpinorWaveFunction::
calculateWaveFunctions(outspin_[ix].first,decay[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()));
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;
- if(cc&&offshell->CC()) offshell=offshell->CC();
Complex diag;
- 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) {
- diag =-sign*sca_[idiag].second->
- evaluate(scale,
- outspin_[out2[dit->channelType]].first [h1],
- outspin_[out3[dit->channelType]].second[h2],inters);
+ 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) {
+ 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);
+ }
}
- 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
- ? 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)) {
- 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 {
+ // intermediate fermion
+ else if(offshell->iSpin() == PDT::Spin1Half) {
+ int iferm =
+ decay[out2[dit->channelType]]->dataPtr()->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)) {
+ 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);
+ // 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) {
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) {
+ 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
+ ? 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)) {
+ 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;
}
- // 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) {
- 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);
- }
+ // 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) {
+ 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_);
+ }
}
- // unknown
- else throw Exception()
- << "Unknown intermediate in StoSFFDecayer::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;
}
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,151 +1,163 @@
// -*- 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.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Method to return an object to calculate the 3 (or higher body) partial width
* @param dm The DecayMode
* @return A pointer to a WidthCalculatorBase object capable of calculating the width
*/
virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const;
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 intrermediate
+ * Store the vertices for scalar intermediate
*/
vector<pair<AbstractSSSVertexPtr, AbstractFFSVertexPtr> > sca_;
/**
- * Store the vertices for fermion intrermediate
+ * Store the vertices for spin-\f$\frac12\f$ fermion intermediate
*/
vector<pair<AbstractFFSVertexPtr, AbstractFFSVertexPtr> > fer_;
/**
- * Store the vertices for vector intrermediate
+ * 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 intrermediate
+ * 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/TFFDecayer.cc b/Decay/General/TFFDecayer.cc
--- a/Decay/General/TFFDecayer.cc
+++ b/Decay/General/TFFDecayer.cc
@@ -1,340 +1,351 @@
// -*- C++ -*-
//
// TFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TFFDecayer class.
//
#include "TFFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr TFFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr TFFDecayer::fullclone() const {
return new_ptr(*this);
}
void TFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> fourV) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractFFTVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<FFTVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractFFTVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<FFTVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
fourPointVertex_[inter] = dynamic_ptr_cast<AbstractFFVTVertexPtr>(fourV.at(inter));
outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr> (outV[0].at(inter));
outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr> (outV[1].at(inter));
}
}
void TFFDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< outgoingVertex1_ << outgoingVertex2_
<< fourPointVertex_;
}
void TFFDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> outgoingVertex1_ >> outgoingVertex2_
>> fourPointVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TFFDecayer,GeneralTwoBodyDecayer>
describeHerwigTFFDecayer("Herwig::TFFDecayer", "Herwig.so");
void TFFDecayer::Init() {
static ClassDocumentation<TFFDecayer> documentation
("The TFFDecayer class implements the decay of a tensor particle "
"to 2 fermions ");
}
double TFFDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
unsigned int iferm(0),ianti(1);
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin1Half,PDT::Spin1Half)));
if(decay[0]->id()>=0) swap(iferm,ianti);
if(meopt==Initialize) {
TensorWaveFunction::
calculateWaveFunctions(tensors_,rho_,const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
TensorWaveFunction::
constructSpinInfo(tensors_,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave_ ,decay[ianti],outgoing,true);
return 0.;
}
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[ianti],outgoing);
Energy2 scale(sqr(inpart.mass()));
unsigned int thel,fhel,ahel;
for(thel=0;thel<5;++thel) {
for(fhel=0;fhel<2;++fhel) {
for(ahel=0;ahel<2;++ahel) {
if(iferm > ianti) {
- (*ME())(thel,fhel,ahel) =
- vertex_->evaluate(scale,wave_[ahel],
- wavebar_[fhel],tensors_[thel]);
+ (*ME())(thel,fhel,ahel) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(thel,fhel,ahel) +=
+ vert->evaluate(scale,wave_[ahel],
+ wavebar_[fhel],tensors_[thel]);
}
else {
- (*ME())(thel,ahel,fhel) =
- vertex_->evaluate(scale,wave_[ahel],
- wavebar_[fhel],tensors_[thel]);
+ (*ME())(thel,ahel,fhel) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(thel,ahel,fhel) +=
+ vert->evaluate(scale,wave_[ahel],
+ wavebar_[fhel],tensors_[thel]);
}
}
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy TFFDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
Energy2 scale = sqr(inpart.second);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(scale, in, outa.first, outb.first);
+ perturbativeVertex_[0]->setCoupling(scale, in, outa.first, outb.first);
double musq = sqr(outa.second/inpart.second);
double b = sqrt(1- 4.*musq);
double me2 = b*b*(5-2*b*b)*scale/120.*UnitRemoval::InvE2;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
- Energy output = norm(perturbativeVertex_->norm())*me2*pcm/(8.*Constants::pi);
+ Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/(8.*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double TFFDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
// work out which is the fermion and antifermion
int ianti(0), iferm(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti);
if(itype[0]==2 && itype[1]==1) swap(iferm, ianti);
if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(meopt==Initialize) {
// create tensor wavefunction for decaying particle
TensorWaveFunction::
calculateWaveFunctions(tensors3_, rho3_, const_ptr_cast<tPPtr>(&inpart), incoming, false);
}
// setup spin information when needed
if(meopt==Terminate) {
TensorWaveFunction::
constructSpinInfo(tensors3_, const_ptr_cast<tPPtr>(&inpart),incoming,true, false);
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_ ,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave3_ ,decay[ianti],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin2, PDT::Spin1Half,
PDT::Spin1Half, PDT::Spin1)));
// create wavefunctions
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave3_ , decay[ianti],outgoing);
VectorWaveFunction::
calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true);
// gauge invariance test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
if (! (outgoingVertex1_[inter] && outgoingVertex2_[inter]))
throw Exception()
<< "Invalid vertices for QCD radiation in TFF decay in TFFDecayer::threeBodyME"
<< Exception::runerror;
// identify fermion and/or anti-fermion vertex
AbstractFFVVertexPtr outgoingVertexF = outgoingVertex1_[inter];
AbstractFFVVertexPtr outgoingVertexA = outgoingVertex2_[inter];
if(outgoingVertex1_[inter]!=outgoingVertex2_[inter] &&
outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->id())))
swap (outgoingVertexF, outgoingVertexA);
if(! (inpart.dataPtr()->iColour()==PDT::Colour0)){
throw Exception()
<< "Invalid vertices for QCD radiation in TFF decay in TFFDecayer::threeBodyME"
<< Exception::runerror;
}
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int it = 0; it < 5; ++it) {
for(unsigned int ifm = 0; ifm < 2; ++ifm) {
for(unsigned int ia = 0; ia < 2; ++ia) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from outgoing fermion
if((decay[iferm]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexF);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
SpinorBarWaveFunction interS =
outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
gluon_[2*ig],decay[iferm]->mass());
assert(wavebar3_[ifm].particle()->id()==interS.particle()->id());
- Complex diag = vertex_->evaluate(scale,wave3_[ia], interS,tensors3_[it]);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ia], interS,tensors3_[it]);
if(!couplingSet) {
gs = abs(outgoingVertexF->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(it, ifm, ia, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing antifermion
if((decay[ianti]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
SpinorWaveFunction interS =
outgoingVertexA->evaluate(scale,3,off,wave3_[ia],
gluon_[2*ig],decay[ianti]->mass());
assert(wave3_[ia].particle()->id()==interS.particle()->id());
- Complex diag = vertex_->evaluate(scale,interS,wavebar3_[ifm],tensors3_[it]);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,interS,wavebar3_[ifm],tensors3_[it]);
if(!couplingSet) {
gs = abs(outgoingVertexA->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(it, ifm, ia, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from 4 point vertex
if (fourPointVertex_[inter]) {
Complex diag = fourPointVertex_[inter]->evaluate(scale, wave3_[ia], wavebar3_[ifm],
gluon_[2*ig], tensors3_[it]);
for(unsigned int ix=0;ix<colourFlow[3].size();++ix) {
(*ME[colourFlow[3][ix].first])(it, ifm, ia, ig) +=
colourFlow[3][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(s,em)
output *= (4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
diff --git a/Decay/General/TFFDecayer.h b/Decay/General/TFFDecayer.h
--- a/Decay/General/TFFDecayer.h
+++ b/Decay/General/TFFDecayer.h
@@ -1,215 +1,223 @@
// -*- C++ -*-
//
// TFFDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_TFFDecayer_H
#define HERWIG_TFFDecayer_H
//
// This is the declaration of the TFFDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Tensor/FFTVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Helicity/Vertex/Tensor/FFVTVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFTVertexPtr;
/** \ingroup Decay
* The TFFDecayer class implements the decay of a tensor
* to 2 fermions in a general model. It holds an FFTVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class TFFDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
TFFDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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);
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
TFFDecayer & operator=(const TFFDecayer &);
private:
/**
* Abstract pointer to AbstractFFTVertex
*/
- AbstractFFTVertexPtr vertex_;
+ vector<AbstractFFTVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- FFTVertexPtr perturbativeVertex_;
+ vector<FFTVertexPtr> perturbativeVertex_;
/**
* 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_;
/**
* Abstract pointer to AbstractFFVTVertex for QCD radiation from 4 point vertex
*/
map<ShowerInteraction,AbstractFFVTVertexPtr> fourPointVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization tensors for the decaying particle
*/
mutable vector<TensorWaveFunction> tensors_;
/**
* Spinors for the decay products
*/
mutable vector<SpinorWaveFunction> wave_;
/**
* Barred spinors for the decay products
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Tensor wavefunction for 3 body decay
*/
mutable vector<TensorWaveFunction> tensors3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_TFFDecayer_H */
diff --git a/Decay/General/TSSDecayer.cc b/Decay/General/TSSDecayer.cc
--- a/Decay/General/TSSDecayer.cc
+++ b/Decay/General/TSSDecayer.cc
@@ -1,125 +1,130 @@
// -*- C++ -*-
//
// TSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TSSDecayer class.
//
#include "TSSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr TSSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr TSSDecayer::fullclone() const {
return new_ptr(*this);
}
void TSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & ,
const vector<map<ShowerInteraction,VertexBasePtr> > & ,
map<ShowerInteraction,VertexBasePtr> ) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractSSTVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<SSTVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractSSTVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<SSTVertexPtr> (vert));
+ }
}
void TSSDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_;
}
void TSSDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TSSDecayer,GeneralTwoBodyDecayer>
describeHerwigTSSDecayer("Herwig::TSSDecayer", "Herwig.so");
void TSSDecayer::Init() {
static ClassDocumentation<TSSDecayer> documentation
("This class implements the decay of a tensor particle into "
"2 scalars.");
}
double TSSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin0,PDT::Spin0)));
if(meopt==Initialize) {
TensorWaveFunction::
calculateWaveFunctions(tensors_,rho_,const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
TensorWaveFunction::
constructSpinInfo(tensors_,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
for(unsigned int ix=0;ix<2;++ix)
ScalarWaveFunction::
constructSpinInfo(decay[ix],outgoing,true);
return 0.;
}
ScalarWaveFunction sca1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing);
ScalarWaveFunction sca2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int thel=0;thel<5;++thel) {
- (*ME())(thel,0,0) = vertex_->evaluate(scale,sca1,sca2,tensors_[thel]);
+ (*ME())(thel,0,0) =0.;
+ for(auto vert : vertex_)
+ (*ME())(thel,0,0) += vert->evaluate(scale,sca1,sca2,tensors_[thel]);
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy TSSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
Energy2 scale(sqr(inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(scale, outa.first, outb.first, in);
+ perturbativeVertex_[0]->setCoupling(scale, outa.first, outb.first, in);
double musq = sqr(outa.second/inpart.second);
double b = sqrt(1. - 4.*musq);
double me2 = scale*pow(b,4)/120*UnitRemoval::InvE2;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
- Energy output = norm(perturbativeVertex_->norm())*me2*pcm/(8.*Constants::pi);
+ Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/(8.*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
diff --git a/Decay/General/TSSDecayer.h b/Decay/General/TSSDecayer.h
--- a/Decay/General/TSSDecayer.h
+++ b/Decay/General/TSSDecayer.h
@@ -1,150 +1,151 @@
// -*- C++ -*-
//
// TSSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_TSSDecayer_H
#define HERWIG_TSSDecayer_H
//
// This is the declaration of the TSSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Tensor/SSTVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::SSTVertexPtr;
/** \ingroup Decay
* The TSSDecayer class implements the decay of a tensor
* to 2 scalars in a general model. It holds an SSTVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class TSSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
TSSDecayer() {}
public:
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
TSSDecayer & operator=(const TSSDecayer &);
private:
/**
* Abstract pointer to AbstractSSTVertex
*/
- AbstractSSTVertexPtr vertex_;
+ vector<AbstractSSTVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- SSTVertexPtr perturbativeVertex_;
+ vector<SSTVertexPtr> perturbativeVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization tensors of the decaying particle
*/
mutable vector<Helicity::TensorWaveFunction> tensors_;
};
}
#endif /* HERWIG_TSSDecayer_H */
diff --git a/Decay/General/TVVDecayer.cc b/Decay/General/TVVDecayer.cc
--- a/Decay/General/TVVDecayer.cc
+++ b/Decay/General/TVVDecayer.cc
@@ -1,329 +1,338 @@
// -*- C++ -*-
//
// TVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TVVDecayer class.
//
#include "TVVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Helicity/LorentzTensor.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr TVVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr TVVDecayer::fullclone() const {
return new_ptr(*this);
}
void TVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> fourV) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractVVTVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<VVTVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractVVTVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<VVTVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
fourPointVertex_[inter] = dynamic_ptr_cast<AbstractVVVTVertexPtr>(fourV.at(inter));
outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr> (outV[0].at(inter));
outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr> (outV[1].at(inter));
}
}
void TVVDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< outgoingVertex1_ << outgoingVertex2_
<< fourPointVertex_;
}
void TVVDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> outgoingVertex1_ >> outgoingVertex2_
>> fourPointVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TVVDecayer,GeneralTwoBodyDecayer>
describeHerwigTVVDecayer("Herwig::TVVDecayer", "Herwig.so");
void TVVDecayer::Init() {
static ClassDocumentation<TVVDecayer> documentation
("This class implements the decay of a tensor to 2 vector bosons");
}
double TVVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin1,PDT::Spin1)));
bool photon[2];
for(unsigned int ix=0;ix<2;++ix)
photon[ix] = decay[ix]->mass()==ZERO;
if(meopt==Initialize) {
TensorWaveFunction::
calculateWaveFunctions(tensors_,rho_,const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
TensorWaveFunction::
constructSpinInfo(tensors_,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
constructSpinInfo(vectors_[ix],decay[ix],outgoing,true,photon[ix]);
return 0.;
}
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
calculateWaveFunctions(vectors_[ix],decay[ix],outgoing,photon[ix]);
Energy2 scale(sqr(inpart.mass()));
unsigned int thel,v1hel,v2hel;
for(thel=0;thel<5;++thel) {
for(v1hel=0;v1hel<3;++v1hel) {
for(v2hel=0;v2hel<3;++v2hel) {
- (*ME())(thel,v1hel,v2hel) = vertex_->evaluate(scale,
- vectors_[0][v1hel],
- vectors_[1][v2hel],
- tensors_[thel]);
+ (*ME())(thel,v1hel,v2hel) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(thel,v1hel,v2hel) += vert->evaluate(scale,
+ vectors_[0][v1hel],
+ vectors_[1][v2hel],
+ tensors_[thel]);
if(photon[1]) ++v2hel;
}
if(photon[0]) ++v1hel;
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy TVVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
Energy2 scale(sqr(inpart.second));
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(scale, outa.first, outb.first, in);
+ perturbativeVertex_[0]->setCoupling(scale, outa.first, outb.first, in);
double mu2 = sqr(outa.second/inpart.second);
double b = sqrt(1 - 4.*mu2);
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy2 me2;
if(outa.second > ZERO && outb.second > ZERO)
me2 = scale*(30 - 20.*b*b + 3.*pow(b,4))/120.;
else
me2 = scale/10.;
- Energy output = norm(perturbativeVertex_->norm())*me2*pcm
+ Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm
/(8.*Constants::pi)*UnitRemoval::InvE2;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double TVVDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
bool massless[2];
for(unsigned int ix=0;ix<2;++ix)
massless[ix] = decay[ix]->mass()==ZERO;
int iglu(2);
if(meopt==Initialize) {
// create tensor wavefunction for decaying particle
TensorWaveFunction::
calculateWaveFunctions(tensors3_, rho3_, const_ptr_cast<tPPtr>(&inpart), incoming, false);
}
// setup spin information when needed
if(meopt==Terminate) {
TensorWaveFunction::
constructSpinInfo(tensors3_, const_ptr_cast<tPPtr>(&inpart),incoming,true, false);
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
constructSpinInfo(vectors3_[ix],decay[ix ],outgoing,true, massless[ix]);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin2, PDT::Spin1,
PDT::Spin1, PDT::Spin1)));
// create wavefunctions
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
calculateWaveFunctions(vectors3_[ix],decay[ix ],outgoing,massless[ix]);
VectorWaveFunction::
calculateWaveFunctions(gluon_ ,decay[iglu ],outgoing,true);
// gauge test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
// work out which vector each outgoing vertex corresponds to
if(outgoingVertex1_[inter]!=outgoingVertex2_[inter] &&
outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->id())))
swap(outgoingVertex1_[inter], outgoingVertex2_[inter]);
if (! (outgoingVertex1_[inter] && outgoingVertex2_[inter]))
throw Exception()
<< "Invalid vertices for radiation in TVV decay in TVVDecayer::threeBodyME"
<< Exception::runerror;
if( !(!inpart.dataPtr()->coloured() && inter ==ShowerInteraction::QCD) &&
!(!inpart.dataPtr()->charged() && inter ==ShowerInteraction::QED))
throw Exception()
<< "Invalid vertices for radiation in TVV decay in TVVDecayer::threeBodyME"
<< Exception::runerror;
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int it = 0; it < 5; ++it) {
for(unsigned int iv0 = 0; iv0 < 3; ++iv0) {
for(unsigned int iv1 = 0; iv1 < 3; ++iv1) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from first outgoing vector
if((decay[0]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertex1_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[0]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectInter =
outgoingVertex1_[inter]->evaluate(scale,3,off,gluon_[2*ig],
vectors3_[0][iv0],decay[0]->mass());
assert(vectors3_[0][iv0].particle()->PDGName()==vectInter.particle()->PDGName());
- Complex diag = vertex_->evaluate(scale,vectors3_[1][iv1],
- vectInter,tensors3_[it]);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectors3_[1][iv1],
+ vectInter,tensors3_[it]);
if(!couplingSet) {
gs = abs(outgoingVertex1_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(it, iv0, iv1, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from second outgoing vector
if((decay[1]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertex2_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[1]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectInter =
outgoingVertex2_[inter]->evaluate(scale,3,off,vectors3_[1][iv1],
gluon_[2*ig],decay[1]->mass());
assert(vectors3_[1][iv1].particle()->PDGName()==vectInter.particle()->PDGName());
- Complex diag = vertex_->evaluate(scale,vectInter,vectors3_[0][iv0],
- tensors3_[it]);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectInter,vectors3_[0][iv0],
+ tensors3_[it]);
if(!couplingSet) {
gs = abs(outgoingVertex2_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(it, iv0, iv1, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from 4 point vertex
if (fourPointVertex_[inter]) {
Complex diag = fourPointVertex_[inter]->evaluate(scale, vectors3_[0][iv0],
vectors3_[1][iv1],gluon_[2*ig],
tensors3_[it]);
for(unsigned int ix=0;ix<colourFlow[3].size();++ix) {
(*ME[colourFlow[3][ix].first])(it, iv0, iv1, ig) +=
colourFlow[3][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
if(massless[1]) ++iv1;
}
if(massless[0]) ++iv0;
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(s,em)
output *= (4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
diff --git a/Decay/General/TVVDecayer.h b/Decay/General/TVVDecayer.h
--- a/Decay/General/TVVDecayer.h
+++ b/Decay/General/TVVDecayer.h
@@ -1,205 +1,213 @@
// -*- C++ -*-
//
// TVVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_TVVDecayer_H
#define HERWIG_TVVDecayer_H
//
// This is the declaration of the TVVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
#include "ThePEG/Helicity/Vertex/Tensor/VVTVertex.h"
#include "ThePEG/Helicity/Vertex/Tensor/VVVTVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VVTVertexPtr;
/** \ingroup Decay
* The TVVDecayer class implements the decay of a tensor
* to 2 vector bosons in a general model. It holds a VVTVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class TVVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
TVVDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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);
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
TVVDecayer & operator=(const TVVDecayer &);
private:
/**
* Abstract pointer to AbstractVVTVertex
*/
- AbstractVVTVertexPtr vertex_;
+ vector<AbstractVVTVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- VVTVertexPtr perturbativeVertex_;
+ vector<VVTVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertex2_;
/**
* Abstract pointer to AbstractVVVTVertex for QCD radiation from 4 point vertex
*/
map<ShowerInteraction,AbstractVVVTVertexPtr> fourPointVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization tensors of decaying particle
*/
mutable vector<Helicity::TensorWaveFunction> tensors_;
/**
* Polarization vectors of outgoing vector bosons
*/
mutable vector<Helicity::VectorWaveFunction> vectors_[2];
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Tensor wavefunction for 3 body decay
*/
mutable vector<Helicity::TensorWaveFunction> tensors3_;
/**
* Polarization vectors of outgoing vector bosons
*/
mutable vector<Helicity::VectorWaveFunction> vectors3_[2];
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_TVVDecayer_H */
diff --git a/Decay/General/VFFDecayer.cc b/Decay/General/VFFDecayer.cc
--- a/Decay/General/VFFDecayer.cc
+++ b/Decay/General/VFFDecayer.cc
@@ -1,456 +1,470 @@
// -*- C++ -*-
//
// VFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VFFDecayer class.
//
#include "VFFDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr VFFDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VFFDecayer::fullclone() const {
return new_ptr(*this);
}
void VFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> ) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractFFVVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<FFVVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractFFVVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<FFVVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(inV.at(inter));
outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[0].at(inter));
outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractFFVVertexPtr>(outV[1].at(inter));
}
}
void VFFDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertex1_
<< outgoingVertex2_;
}
void VFFDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertex1_
>> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VFFDecayer,GeneralTwoBodyDecayer>
describeHerwigVFFDecayer("Herwig::VFFDecayer", "Herwig.so");
void VFFDecayer::Init() {
static ClassDocumentation<VFFDecayer> documentation
("The VFFDecayer implements the matrix element for the"
" decay of a vector to fermion-antifermion pair");
}
double VFFDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
int iferm(1),ianti(0);
if(decay[0]->id()>0) swap(iferm,ianti);
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half)));
if(meopt==Initialize) {
VectorWaveFunction::calculateWaveFunctions(vectors_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
SpinorBarWaveFunction::
constructSpinInfo(wavebar_,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave_ ,decay[ianti],outgoing,true);
return 0.;
}
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar_,decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave_ ,decay[ianti],outgoing);
// compute the matrix element
Energy2 scale(inpart.mass()*inpart.mass());
for(unsigned int ifm = 0; ifm < 2; ++ifm) { //loop over fermion helicities
for(unsigned int ia = 0; ia < 2; ++ia) {// loop over antifermion helicities
for(unsigned int vhel = 0; vhel < 3; ++vhel) {//loop over vector helicities
if(iferm > ianti) {
- (*ME())(vhel, ia, ifm) =
- vertex_->evaluate(scale,wave_[ia],
- wavebar_[ifm],vectors_[vhel]);
+ (*ME())(vhel, ia, ifm) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(vhel, ia, ifm) +=
+ vert->evaluate(scale,wave_[ia],
+ wavebar_[ifm],vectors_[vhel]);
}
- else
- (*ME())(vhel,ifm,ia)=
- vertex_->evaluate(scale,wave_[ia],
- wavebar_[ifm],vectors_[vhel]);
+ else {
+ (*ME())(vhel,ifm,ia)= 0.;
+ for(auto vert : vertex_)
+ (*ME())(vhel,ifm,ia) +=
+ vert->evaluate(scale,wave_[ia],
+ wavebar_[ifm],vectors_[vhel]);
+ }
}
}
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy VFFDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
double mu1(outa.second/inpart.second), mu2(outb.second/inpart.second);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(sqr(inpart.second), outa.first, outb.first,in);
- Complex cl(perturbativeVertex_->left()), cr(perturbativeVertex_->right());
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, outb.first,in);
+ Complex cl(perturbativeVertex_[0]->left()), cr(perturbativeVertex_[0]->right());
double me2 = (norm(cl) + norm(cr))*( sqr(sqr(mu1) - sqr(mu2))
+ sqr(mu1) + sqr(mu2) - 2.)
- 6.*(cl*conj(cr) + cr*conj(cl)).real()*mu1*mu2;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
- Energy output = -norm(perturbativeVertex_->norm())*me2*pcm /
+ Energy output = -norm(perturbativeVertex_[0]->norm())*me2*pcm /
(24.*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double VFFDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
// work out which is the fermion and antifermion
int ianti(0), iferm(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti);
if(itype[0]==2 && itype[1]==1) swap(iferm, ianti);
if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()<decay[1]->dataPtr()->id())
swap(iferm, ianti);
if(meopt==Initialize) {
// create vector wavefunction for decaying particle
VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming, false);
}
// setup spin information when needed
if(meopt==Terminate) {
VectorWaveFunction::
constructSpinInfo(vector3_ ,const_ptr_cast<tPPtr>(&inpart),outgoing,true,false);
SpinorBarWaveFunction::
constructSpinInfo(wavebar3_,decay[iferm],outgoing,true);
SpinorWaveFunction::
constructSpinInfo(wave3_ ,decay[ianti],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1Half,
PDT::Spin1Half, PDT::Spin1)));
// create wavefunctions
SpinorBarWaveFunction::
calculateWaveFunctions(wavebar3_, decay[iferm],outgoing);
SpinorWaveFunction::
calculateWaveFunctions(wave3_ , decay[ianti],outgoing);
VectorWaveFunction::
calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true);
// gauge invariance test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
// identify fermion and/or anti-fermion vertex
AbstractFFVVertexPtr outgoingVertexF;
AbstractFFVVertexPtr outgoingVertexA;
identifyVertices(iferm, ianti, inpart, decay, outgoingVertexF, outgoingVertexA,inter);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int iv = 0; iv < 3; ++iv) {
for(unsigned int ifm = 0; ifm < 2; ++ifm) {
for(unsigned int ia = 0; ia < 2; ++ia) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming vector
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
VectorWaveFunction vectorInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv],
gluon_[2*ig],inpart.mass());
assert(vector3_[iv].particle()->id()==vectorInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,wave3_[ia],wavebar3_[ifm],vectorInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ia],wavebar3_[ifm],vectorInter);
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(iv, ia, ifm, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing fermion
if((decay[iferm]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexF);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iferm]->dataPtr();
if(off->CC()) off = off->CC();
SpinorBarWaveFunction interS =
outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm],
gluon_[2*ig],decay[iferm]->mass());
assert(wavebar3_[ifm].particle()->id()==interS.particle()->id());
- Complex diag = vertex_->evaluate(scale,wave3_[ia], interS,vector3_[iv]);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,wave3_[ia], interS,vector3_[iv]);
if(!couplingSet) {
gs = abs(outgoingVertexF->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(iv, ia, ifm, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from outgoing antifermion
if((decay[ianti]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
SpinorWaveFunction interS =
outgoingVertexA->evaluate(scale,3,off,wave3_[ia],
gluon_[2*ig],decay[ianti]->mass());
assert(wave3_[ia].particle()->id()==interS.particle()->id());
- Complex diag = vertex_->evaluate(scale,interS,wavebar3_[ifm],vector3_[iv]);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,interS,wavebar3_[ifm],vector3_[iv]);
if(!couplingSet) {
gs = abs(outgoingVertexA->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(iv, ia, ifm, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(S,EM)
output*=(4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
//return output
return output;
}
void VFFDecayer::identifyVertices(const int iferm, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractFFVVertexPtr & outgoingVertexF,
AbstractFFVVertexPtr & outgoingVertexA,
ShowerInteraction inter){
// QCD vertices
if(inter==ShowerInteraction::QCD) {
// work out which fermion each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[iferm]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))){
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))){
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))){
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))){
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr()->iColour()==PDT::Colour3){
if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertexF = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertexF = outgoingVertex2_[inter];
}
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8){
if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[ianti]->dataPtr()))){
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
else {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){
if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iferm]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter];
}
else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))){
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour6 ||
inpart.dataPtr()->iColour()==PDT::Colour6bar) {
if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr()))) {
outgoingVertexF = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else {
outgoingVertexF = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
if (! ((incomingVertex_[inter] && (outgoingVertexF || outgoingVertexA)) ||
( outgoingVertexF && outgoingVertexA)))
throw Exception()
<< "Invalid vertices for QCD radiation in VFF decay in VFFDecayer::identifyVertices"
<< Exception::runerror;
}
// QED
else {
if(decay[iferm]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iferm]->dataPtr())))
outgoingVertexF = outgoingVertex1_[inter];
else
outgoingVertexF = outgoingVertex2_[inter];
}
if(decay[ianti]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[ianti]->dataPtr())))
outgoingVertexA = outgoingVertex1_[inter];
else
outgoingVertexA = outgoingVertex2_[inter];
}
}
}
diff --git a/Decay/General/VFFDecayer.h b/Decay/General/VFFDecayer.h
--- a/Decay/General/VFFDecayer.h
+++ b/Decay/General/VFFDecayer.h
@@ -1,224 +1,232 @@
// -*- C++ -*-
//
// VFFDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_VFFDecayer_H
#define HERWIG_VFFDecayer_H
//
// This is the declaration of the VFFDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::FFVVertexPtr;
/** \ingroup Decay
* The VFFDecayer class implements the decay of a vector
* to 2 fermions in a general model. It holds an FFVVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class VFFDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
VFFDecayer() {}
public:
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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 & abstractOutgoingVertexF,
AbstractFFVVertexPtr & abstractOutgoingVertexA,
ShowerInteraction inter);
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
VFFDecayer & operator=(const VFFDecayer &);
private:
/**
* Abstract pointer to AbstractFFVVertex
*/
- AbstractFFVVertexPtr vertex_;
+ vector<AbstractFFVVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- FFVVertexPtr perturbativeVertex_;
+ vector<FFVVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from incoming vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> 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_;
/**
* Polarization vectors for the decaying particle
*/
mutable vector<VectorWaveFunction> vectors_;
/**
* Spinors for the decay products
*/
mutable vector<SpinorWaveFunction> wave_;
/**
* Barred spinors for the decay products
*/
mutable vector<SpinorBarWaveFunction> wavebar_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Scalar wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> vector3_;
/**
* Spinor wavefunction for 3 body decay
*/
mutable vector<SpinorWaveFunction> wave3_;
/**
* Barred spinor wavefunction for 3 body decay
*/
mutable vector<SpinorBarWaveFunction> wavebar3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_VFFDecayer_H */
diff --git a/Decay/General/VSSDecayer.cc b/Decay/General/VSSDecayer.cc
--- a/Decay/General/VSSDecayer.cc
+++ b/Decay/General/VSSDecayer.cc
@@ -1,405 +1,416 @@
// -*- C++ -*-
//
// VSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VSSDecayer class.
//
#include "VSSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr VSSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VSSDecayer::fullclone() const {
return new_ptr(*this);
}
void VSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> ) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractVSSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<VSSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractVSSVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<VSSVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(inV.at(inter));
outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
}
}
void VSSDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertex1_
<< outgoingVertex2_;
}
void VSSDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertex1_
>> outgoingVertex2_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VSSDecayer,GeneralTwoBodyDecayer>
describeHerwigVSSDecayer("Herwig::VSSDecayer", "Herwig.so");
void VSSDecayer::Init() {
static ClassDocumentation<VSSDecayer> documentation
("This implements the decay of a vector to 2 scalars");
}
double VSSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin0,PDT::Spin0)));
if(meopt==Initialize) {
VectorWaveFunction::calculateWaveFunctions(vectors_,rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
for(unsigned int ix=0;ix<2;++ix)
ScalarWaveFunction::
constructSpinInfo(decay[ix],outgoing,true);
return 0.;
}
ScalarWaveFunction sca1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing);
ScalarWaveFunction sca2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int ix=0;ix<3;++ix) {
- (*ME())(ix,0,0) = vertex_->evaluate(scale,vectors_[ix],sca1,sca2);
+ (*ME())(ix,0,0) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(ix,0,0) += vert->evaluate(scale,vectors_[ix],sca1,sca2);
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy VSSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(sqr(inpart.second), in, outa.first,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first,
outb.first);
double mu1sq = sqr(outa.second/inpart.second);
double mu2sq = sqr(outb.second/inpart.second);
double me2 = sqr(mu1sq - mu2sq) - 2.*(mu1sq + mu2sq);
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
- Energy output = -norm(perturbativeVertex_->norm())*me2*pcm /
+ Energy output = -norm(perturbativeVertex_[0]->norm())*me2*pcm /
(24.*Constants::pi);
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double VSSDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
// work out which is the scalar and anti-scalar
int ianti(0), iscal(1), iglu(2);
int itype[2];
for(unsigned int ix=0;ix<2;++ix) {
if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1;
else itype[ix] = 2;
}
if(itype[0]==0 && itype[1]!=0) swap(ianti, iscal);
if(itype[0]==2 && itype[1]==1) swap(ianti, iscal);
if(itype[0]==0 && itype[1]==0 && abs(decay[0]->dataPtr()->id())>abs(decay[1]->dataPtr()->id()))
swap(iscal, ianti);
if(itype[0]==1 && itype[1]==1 && abs(decay[0]->dataPtr()->id())<abs(decay[1]->dataPtr()->id()))
swap(iscal, ianti);
if(meopt==Initialize) {
// create vector wavefunction for decaying particle
VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming, false);
}
// setup spin information when needed
if(meopt==Terminate) {
VectorWaveFunction::
constructSpinInfo(vector3_ ,const_ptr_cast<tPPtr>(&inpart),outgoing,true,false);
ScalarWaveFunction::constructSpinInfo( decay[iscal],outgoing,true);
ScalarWaveFunction::constructSpinInfo( decay[ianti],outgoing,true);
VectorWaveFunction::constructSpinInfo(gluon_,decay[iglu ],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin0,
PDT::Spin0, PDT::Spin1)));
// create wavefunctions
ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing);
ScalarWaveFunction anti(decay[ianti]->momentum(), decay[ianti]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(gluon_,decay[iglu ],outgoing,true);
// gauge test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),
decay[iglu ]->dataPtr(),10,
outgoing));
}
}
#endif
// identify scalar and/or anti-scalar vertex
AbstractVSSVertexPtr outgoingVertexS;
AbstractVSSVertexPtr outgoingVertexA;
identifyVertices(iscal, ianti, inpart, decay, outgoingVertexS, outgoingVertexA,inter);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int iv = 0; iv < 3; ++iv) {
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming vector
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
VectorWaveFunction vectorInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv],
gluon_[2*ig],inpart.mass());
assert(vector3_[iv].particle()->id()==vectorInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vectorInter,scal,anti);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectorInter,scal,anti);
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(iv, 0, 0, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the outgoing scalar
if((decay[iscal]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexS);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[iscal]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
outgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass());
assert(scal.particle()->id()==scalarInter.particle()->id());
- Complex diag =vertex_->evaluate(scale,vector3_[iv],anti,scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vector3_[iv],anti,scalarInter);
if(!couplingSet) {
gs = abs(outgoingVertexS->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(iv, 0, 0, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
if((decay[ianti]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexA);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ianti]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
outgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass());
assert(anti.particle()->id()==scalarInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vector3_[iv],scal,scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vector3_[iv],scal,scalarInter);
if(!couplingSet) {
gs = abs(outgoingVertexA->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(iv, 0, 0, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(S,EM)
output*=(4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
void VSSDecayer::identifyVertices(const int iscal, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractVSSVertexPtr & outgoingVertexS,
AbstractVSSVertexPtr & outgoingVertexA,
ShowerInteraction inter){
if(inter==ShowerInteraction::QCD) {
// work out which scalar each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[iscal]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
outgoingVertexS = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){
outgoingVertexS = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr()->iColour()==PDT::Colour3){
if(decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertexS = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertexS = outgoingVertex2_[inter];
}
else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour8){
if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){
outgoingVertexS = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
else {
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){
if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[iscal]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter];
}
else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour8 &&
decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){
if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){
outgoingVertexS = outgoingVertex1_[inter];
outgoingVertexA = outgoingVertex2_[inter];
}
else {
outgoingVertexS = outgoingVertex2_[inter];
outgoingVertexA = outgoingVertex1_[inter];
}
}
}
if (! ((incomingVertex_[inter] && (outgoingVertexS || outgoingVertexA)) ||
( outgoingVertexS && outgoingVertexA)))
throw Exception()
<< "Invalid vertices for QCD radiation in VSS decay in VSSDecayer::identifyVertices"
<< Exception::runerror;
}
else {
if(decay[iscal]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[iscal]->dataPtr())))
outgoingVertexS = outgoingVertex1_[inter];
else
outgoingVertexS = outgoingVertex2_[inter];
}
if(decay[ianti]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[ianti]->dataPtr())))
outgoingVertexA = outgoingVertex1_[inter];
else
outgoingVertexA = outgoingVertex2_[inter];
}
}
}
diff --git a/Decay/General/VSSDecayer.h b/Decay/General/VSSDecayer.h
--- a/Decay/General/VSSDecayer.h
+++ b/Decay/General/VSSDecayer.h
@@ -1,203 +1,211 @@
// -*- C++ -*-
//
// VSSDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_VSSDecayer_H
#define HERWIG_VSSDecayer_H
//
// This is the declaration of the VSSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VSSVertexPtr;
/** \ingroup Decay
* The VSSDecayer class implements the decay of a vector
* to 2 scalars in a general model. It holds an VSSVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class VSSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
VSSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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 scalar and antiscalar
*/
void identifyVertices(const int iscal, const int ianti,
const Particle & inpart, const ParticleVector & decay,
AbstractVSSVertexPtr & abstractOutgoingVertexS,
AbstractVSSVertexPtr & abstractOutgoingVertexA,
ShowerInteraction inter);
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ 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.
*/
VSSDecayer & operator=(const VSSDecayer &);
private:
/**
* Abstract pointer to AbstractVSSVertex
*/
- AbstractVSSVertexPtr vertex_;
+ vector<AbstractVSSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- VSSVertexPtr perturbativeVertex_;
+ vector<VSSVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from incoming vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractFFVVertex for QCD radiation from outgoing scalar
*/
map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertex2_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Polarization vectors for the decaying particle
*/
mutable vector<Helicity::VectorWaveFunction> vectors_;
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> vector3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
};
}
#endif /* HERWIG_VSSDecayer_H */
diff --git a/Decay/General/VVSDecayer.cc b/Decay/General/VVSDecayer.cc
--- a/Decay/General/VVSDecayer.cc
+++ b/Decay/General/VVSDecayer.cc
@@ -1,302 +1,313 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VVSDecayer class.
//
#include "VVSDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr VVSDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VVSDecayer::fullclone() const {
return new_ptr(*this);
}
void VVSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr>) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractVVSVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<VVSVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractVVSVertexPtr>(vert));
+ perturbativeVertex_.push_back(dynamic_ptr_cast<VVSVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(inV.at(inter));
outgoingVertexS_[inter] = AbstractVSSVertexPtr();
outgoingVertexV_[inter] = AbstractVVVVertexPtr();
if(outV[0].at(inter)) {
if (outV[0].at(inter)->getName()==VertexType::VSS)
outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[0].at(inter));
else
outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[0].at(inter));
}
if(outV[1].at(inter)) {
if (outV[1].at(inter)->getName()==VertexType::VSS)
outgoingVertexS_[inter] = dynamic_ptr_cast<AbstractVSSVertexPtr>(outV[1].at(inter));
else
outgoingVertexV_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[1].at(inter));
}
}
}
void VVSDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertexS_ << outgoingVertexV_;
}
void VVSDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertexS_ >> outgoingVertexV_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VVSDecayer,GeneralTwoBodyDecayer>
describeHerwigVVSDecayer("Herwig::VVSDecayer", "Herwig.so");
void VVSDecayer::Init() {
static ClassDocumentation<VVSDecayer> documentation
("The VVSDecayer class implements the decay of a vector"
" to a vector and a scalar");
}
double VVSDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
bool massless = ( decay[0]->id()==ParticleID::gamma ||
decay[0]->id()==ParticleID::g );
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin0)));
if(meopt==Initialize) {
VectorWaveFunction::calculateWaveFunctions(vectors_[0],rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
VectorWaveFunction::constructSpinInfo(vectors_[0],const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
VectorWaveFunction::
constructSpinInfo(vectors_[1],decay[0],outgoing,true,massless);
ScalarWaveFunction::
constructSpinInfo(decay[1],outgoing,true);
return 0.;
}
VectorWaveFunction::
calculateWaveFunctions(vectors_[1],decay[0],outgoing,massless);
ScalarWaveFunction sca(decay[1]->momentum(),decay[1]->dataPtr(),outgoing);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int in=0;in<3;++in) {
for(unsigned int out=0;out<3;++out) {
if(massless&&out==1) ++out;
- (*ME())(in,out,0) =
- vertex_->evaluate(scale,vectors_[0][in],vectors_[1][out],sca);
+ (*ME())(in,out,0) = 0.;
+ for(auto vert : vertex_)
+ (*ME())(in,out,0) +=
+ vert->evaluate(scale,vectors_[0][in],vectors_[1][out],sca);
}
}
double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy VVSDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
Energy2 scale(sqr(inpart.second));
double mu1sq = sqr(outa.second/inpart.second);
double mu2sq = sqr(outb.second/inpart.second);
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
if( outb.first->iSpin() == PDT::Spin0 )
- perturbativeVertex_->setCoupling(sqr(inpart.second), in,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in,
outa.first, outb.first);
else {
- perturbativeVertex_->setCoupling(sqr(inpart.second), in,
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in,
outb.first, outa.first);
swap(mu1sq, mu2sq);
}
- double vn = norm(perturbativeVertex_->norm());
+ double vn = norm(perturbativeVertex_[0]->norm());
if(vn == ZERO || mu1sq == ZERO) return ZERO;
double me2 = 2. + 0.25*sqr(1. + mu1sq - mu2sq)/mu1sq;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy output = vn*me2*pcm/(24.*Constants::pi)/scale*UnitRemoval::E2;
// colour factor
output *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return output;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double VVSDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
unsigned int ivec(0),isca(1);
if(decay[ivec]->dataPtr()->iSpin()!=PDT::Spin1) swap(ivec,isca);
if(meopt==Initialize) {
// create vector wavefunction for decaying particle
VectorWaveFunction::calculateWaveFunctions(vectors3_[0], rho3_,
const_ptr_cast<tPPtr>(&inpart),
incoming, false);
}
if(meopt==Terminate) {
VectorWaveFunction::
constructSpinInfo(vectors3_[0] ,const_ptr_cast<tPPtr>(&inpart),outgoing,true,false);
VectorWaveFunction::
constructSpinInfo(vectors3_[1],decay[ivec],outgoing,true,false);
ScalarWaveFunction::
constructSpinInfo(decay[isca],outgoing,true);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[2],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1,
PDT::Spin0, PDT::Spin1)));
bool massless= decay[ivec]->mass()!=ZERO;
// create wavefunctions
VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[0],outgoing,massless);
ScalarWaveFunction scal(decay[isca]->momentum(), decay[isca]->dataPtr(),outgoing);
VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true);
// gauge test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[2]->momentum(),
decay[2]->dataPtr(),10,
outgoing));
}
}
#endif
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int iv0 = 0; iv0 < 3; ++iv0) {
for(unsigned int iv1 = 0; iv1 < 3; ++iv1) {
if(massless && iv1==1) continue;
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming vector
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
VectorWaveFunction vectorInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vectors3_[0][iv0],
gluon_[2*ig],inpart.mass());
assert(vectors3_[0][iv0].particle()->id()==vectorInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vectorInter,vectors3_[1][iv1],scal);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectorInter,vectors3_[1][iv1],scal);
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(iv0, iv1, 0, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the outgoing vector
if((decay[ivec]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[ivec]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexV_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[ivec]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectorInter =
outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig],vectors3_[1][iv1],decay[ivec]->mass());
assert(vectors3_[1][iv1].particle()->id()==vectorInter.particle()->id());
- Complex diag =vertex_->evaluate(scale,vectors3_[0][iv0],vectorInter,scal);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectors3_[0][iv0],vectorInter,scal);
if(!couplingSet) {
gs = abs(outgoingVertexV_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(iv0, iv1, 0, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the outgoing scalar
if((decay[isca]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[isca]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertexS_[inter]);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[isca]->dataPtr();
if(off->CC()) off = off->CC();
ScalarWaveFunction scalarInter =
outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],scal,decay[isca]->mass());
assert(scal.particle()->id()==scalarInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vectors3_[0][iv0],vectors3_[1][iv1],scalarInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectors3_[0][iv0],vectors3_[1][iv1],scalarInter);
if(!couplingSet) {
gs = abs(outgoingVertexS_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(iv0, iv1, 0, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(S,EM)
output*=(4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
diff --git a/Decay/General/VVSDecayer.h b/Decay/General/VVSDecayer.h
--- a/Decay/General/VVSDecayer.h
+++ b/Decay/General/VVSDecayer.h
@@ -1,193 +1,201 @@
// -*- C++ -*-
#ifndef THEPEG_VVSDecayer_H
#define THEPEG_VVSDecayer_H
//
// This is the declaration of the VVSDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Helicity/Vertex/Scalar/VVSVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VVSVertexPtr;
/** \ingroup Decay
* The VVSDecayer class implements the decay of a vector to a
* vector and a scalar in a general model. It holds an VVSVertex pointer
* that must be typecast from the VertexBase pointer helid in the
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see \ref VVSDecayerInterfaces "The interfaces"
* defined for VVSDecayer.
*/
class VVSDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
VVSDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing,
+ vector<VertexBasePtr>,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > &,
map<ShowerInteraction,VertexBasePtr>);
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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);
//@}
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.
*/
VVSDecayer & operator=(const VVSDecayer &);
private:
/**
* Abstract pointer to AbstractVVSVertex
*/
- AbstractVVSVertexPtr vertex_;
+ vector<AbstractVVSVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- VVSVertexPtr perturbativeVertex_;
+ vector<VVSVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from incoming vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from the first outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertexV_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from the second outgoing vector
*/
map<ShowerInteraction,AbstractVSSVertexPtr> outgoingVertexS_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors_[2];
private:
/**
* Members for the POWHEG correction
*/
//@{
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors3_[2];
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
//@}
};
}
#endif /* THEPEG_VVSDecayer_H */
diff --git a/Decay/General/VVVDecayer.cc b/Decay/General/VVVDecayer.cc
--- a/Decay/General/VVVDecayer.cc
+++ b/Decay/General/VVVDecayer.cc
@@ -1,429 +1,441 @@
// -*- C++ -*-
//
// VVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VVVDecayer class.
//
#include "VVVDecayer.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Utilities/Kinematics.h"
#include "Herwig/Decay/GeneralDecayMatrixElement.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
IBPtr VVVDecayer::clone() const {
return new_ptr(*this);
}
IBPtr VVVDecayer::fullclone() const {
return new_ptr(*this);
}
void VVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing,
- VertexBasePtr vertex,
+ vector<VertexBasePtr> vertex,
map<ShowerInteraction,VertexBasePtr> & inV,
const vector<map<ShowerInteraction,VertexBasePtr> > & outV,
map<ShowerInteraction,VertexBasePtr> fourV) {
decayInfo(incoming,outgoing);
- vertex_ = dynamic_ptr_cast<AbstractVVVVertexPtr>(vertex);
- perturbativeVertex_ = dynamic_ptr_cast<VVVVertexPtr> (vertex);
+ for(auto vert : vertex) {
+ vertex_ .push_back(dynamic_ptr_cast<AbstractVVVVertexPtr>(vert));
+ perturbativeVertex_ .push_back(dynamic_ptr_cast<VVVVertexPtr> (vert));
+ }
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
incomingVertex_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(inV.at(inter));
outgoingVertex1_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[0].at(inter));
outgoingVertex2_[inter] = dynamic_ptr_cast<AbstractVVVVertexPtr>(outV[1].at(inter));
fourPointVertex_[inter] = dynamic_ptr_cast<AbstractVVVVVertexPtr>(fourV.at(inter));
}
}
void VVVDecayer::persistentOutput(PersistentOStream & os) const {
os << vertex_ << perturbativeVertex_
<< incomingVertex_ << outgoingVertex1_
<< outgoingVertex2_ << fourPointVertex_;
}
void VVVDecayer::persistentInput(PersistentIStream & is, int) {
is >> vertex_ >> perturbativeVertex_
>> incomingVertex_ >> outgoingVertex1_
>> outgoingVertex2_ >> fourPointVertex_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VVVDecayer,GeneralTwoBodyDecayer>
describeHerwigVVVDecayer("Herwig::VVVDecayer", "Herwig.so");
void VVVDecayer::Init() {
static ClassDocumentation<VVVDecayer> documentation
("The VVVDecayer class implements the decay of a vector boson "
"into 2 vector bosons");
}
double VVVDecayer::me2(const int , const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
if(!ME())
ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin1)));
bool massless[2];
for(unsigned int ix=0;ix<2;++ix)
massless[ix] = (decay[ix]->id()==ParticleID::gamma ||
decay[ix]->id()==ParticleID::g);
if(meopt==Initialize) {
VectorWaveFunction::calculateWaveFunctions(vectors_[0],rho_,
const_ptr_cast<tPPtr>(&inpart),
incoming,false);
}
if(meopt==Terminate) {
VectorWaveFunction::constructSpinInfo(vectors_[0],const_ptr_cast<tPPtr>(&inpart),
incoming,true,false);
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
constructSpinInfo(vectors_[ix+1],decay[ix],outgoing,true,massless[ix]);
return 0.;
}
for(unsigned int ix=0;ix<2;++ix)
VectorWaveFunction::
calculateWaveFunctions(vectors_[ix+1],decay[ix],outgoing,massless[ix]);
Energy2 scale(sqr(inpart.mass()));
for(unsigned int iv3=0;iv3<3;++iv3) {
for(unsigned int iv2=0;iv2<3;++iv2) {
for(unsigned int iv1=0;iv1<3;++iv1) {
- (*ME())(iv1,iv2,iv3) = vertex_->
- evaluate(scale,vectors_[1][iv2],vectors_[2][iv3],vectors_[0][iv1]);
+ (*ME())(iv1,iv2,iv3) = 0.;
+ for(auto vert : vertex_) {
+ (*ME())(iv1,iv2,iv3) += vert->
+ evaluate(scale,vectors_[1][iv2],vectors_[2][iv3],vectors_[0][iv1]);
+ }
}
}
}
double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2;
// colour and identical particle factors
output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),
decay[1]->dataPtr());
// return the answer
return output;
}
Energy VVVDecayer::partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const {
if( inpart.second < outa.second + outb.second ) return ZERO;
- if(perturbativeVertex_) {
+ if(perturbativeVertex_.size()==1 &&
+ perturbativeVertex_[0]) {
tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first;
- perturbativeVertex_->setCoupling(sqr(inpart.second), in,
- outa.first, outb.first);
+ perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in,
+ outa.first, outb.first);
double mu1(outa.second/inpart.second), mu1sq(sqr(mu1)),
mu2(outb.second/inpart.second), mu2sq(sqr(mu2));
- double vn = norm(perturbativeVertex_->norm());
+ double vn = norm(perturbativeVertex_[0]->norm());
if(vn == ZERO || mu1sq == ZERO || mu2sq == ZERO) return ZERO;
double me2 =
(mu1 - mu2 - 1.)*(mu1 - mu2 + 1.)*(mu1 + mu2 - 1.)*(mu1 + mu2 + 1.)
* (sqr(mu1sq) + sqr(mu2sq) + 10.*(mu1sq*mu2sq + mu1sq + mu2sq) + 1.)
/4./mu1sq/mu2sq;
Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second,
outb.second);
Energy pWidth = vn*me2*pcm/24./Constants::pi;
// colour factor
pWidth *= colourFactor(inpart.first,outa.first,outb.first);
// return the answer
return pWidth;
}
else {
return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb);
}
}
double VVVDecayer::threeBodyME(const int , const Particle & inpart,
const ParticleVector & decay,
ShowerInteraction inter, MEOption meopt) {
if(meopt==Initialize) {
// create vector wavefunction for decaying particle
VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast<tPPtr>(&inpart),
incoming, false);
}
if(meopt==Terminate) {
VectorWaveFunction::
constructSpinInfo(vector3_ ,const_ptr_cast<tPPtr>(&inpart),outgoing,true,false);
VectorWaveFunction::
constructSpinInfo(vectors3_[0],decay[0],outgoing,true,false);
VectorWaveFunction::
constructSpinInfo(vectors3_[1],decay[1],outgoing,true,false);
VectorWaveFunction::
constructSpinInfo(gluon_ ,decay[2],outgoing,true,false);
return 0.;
}
// calculate colour factors and number of colour flows
unsigned int nflow;
vector<DVector> cfactors = getColourFactors(inpart, decay, nflow);
vector<GeneralDecayMEPtr> ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1,
PDT::Spin1, PDT::Spin1)));
bool massless[2];
for(unsigned int ix=0;ix<2;++ix)
massless[ix] = decay[ix]->mass()!=ZERO;
// create wavefunctions
VectorWaveFunction::calculateWaveFunctions(vectors3_[0],decay[0],outgoing,massless[0]);
VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[1],outgoing,massless[1]);
VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true);
// gauge test
#ifdef GAUGE_CHECK
gluon_.clear();
for(unsigned int ix=0;ix<3;++ix) {
if(ix==1) gluon_.push_back(VectorWaveFunction());
else {
gluon_.push_back(VectorWaveFunction(decay[2]->momentum(),
decay[2]->dataPtr(),10,
outgoing));
}
}
#endif
// get the outgoing vertices
AbstractVVVVertexPtr outgoingVertex1;
AbstractVVVVertexPtr outgoingVertex2;
identifyVertices(inpart,decay, outgoingVertex1, outgoingVertex2,inter);
Energy2 scale(sqr(inpart.mass()));
const GeneralTwoBodyDecayer::CFlow & colourFlow
= colourFlows(inpart, decay);
double gs(0.);
bool couplingSet(false);
#ifdef GAUGE_CHECK
double total=0.;
#endif
for(unsigned int iv0 = 0; iv0 < 3; ++iv0) {
for(unsigned int iv1 = 0; iv1 < 3; ++iv1) {
if(massless[0] && iv1==1) continue;
for(unsigned int iv2 = 0; iv2 < 3; ++iv2) {
if(massless[1] && iv2==1) continue;
for(unsigned int ig = 0; ig < 2; ++ig) {
// radiation from the incoming vector
if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(incomingVertex_[inter]);
VectorWaveFunction vectorInter =
incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv0],
gluon_[2*ig],inpart.mass());
assert(vector3_[iv0].particle()->id()==vectorInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vectorInter,vectors3_[0][iv1],
- vectors3_[1][iv2]);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vectorInter,vectors3_[0][iv1],
+ vectors3_[1][iv2]);
if(!couplingSet) {
gs = abs(incomingVertex_[inter]->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[0].size();++ix) {
(*ME[colourFlow[0][ix].first])(iv0, iv1, iv2, ig) +=
colourFlow[0][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the 1st outgoing vector
if((decay[0]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertex1);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[0]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectorInter =
outgoingVertex1->evaluate(scale,3,off,gluon_[2*ig],vectors3_[0][iv1],decay[0]->mass());
assert(vectors3_[0][iv1].particle()->id()==vectorInter.particle()->id());
- Complex diag =vertex_->evaluate(scale,vector3_[iv0],vectorInter,vectors3_[1][iv2]);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vector3_[iv0],vectorInter,vectors3_[1][iv2]);
if(!couplingSet) {
gs = abs(outgoingVertex1->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[1].size();++ix) {
(*ME[colourFlow[1][ix].first])(iv0, iv1, iv2, ig) +=
colourFlow[1][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// radiation from the second outgoing vector
if((decay[1]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) ||
(decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) {
assert(outgoingVertex2);
// ensure you get correct outgoing particle from first vertex
tcPDPtr off = decay[1]->dataPtr();
if(off->CC()) off = off->CC();
VectorWaveFunction vectorInter =
outgoingVertex2->evaluate(scale,3,off, gluon_[2*ig],vectors3_[1][iv2],decay[1]->mass());
assert(vectors3_[1][iv2].particle()->id()==vectorInter.particle()->id());
- Complex diag = vertex_->evaluate(scale,vector3_[iv0],vectors3_[0][iv1],vectorInter);
+ Complex diag = 0.;
+ for(auto vertex : vertex_)
+ diag += vertex->evaluate(scale,vector3_[iv0],vectors3_[0][iv1],vectorInter);
if(!couplingSet) {
gs = abs(outgoingVertex2->norm());
couplingSet = true;
}
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[2][ix].first])(iv0, iv1, iv2, ig) +=
colourFlow[2][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
// 4-point vertex
if (fourPointVertex_[inter]) {
Complex diag = fourPointVertex_[inter]->evaluate(scale,0, vector3_[iv0],
vectors3_[0][iv1],
vectors3_[1][iv2],gluon_[2*ig]);
for(unsigned int ix=0;ix<colourFlow[2].size();++ix) {
(*ME[colourFlow[3][ix].first])(iv0, iv1, iv2, ig) +=
colourFlow[3][ix].second*diag;
}
#ifdef GAUGE_CHECK
total+=norm(diag);
#endif
}
}
}
}
}
// contract matrices
double output=0.;
for(unsigned int ix=0; ix<nflow; ++ix){
for(unsigned int iy=0; iy<nflow; ++iy){
output+=cfactors[ix][iy]*(ME[ix]->contract(*ME[iy],rho3_)).real();
}
}
// divide by alpha_(S,EM)
output*=(4.*Constants::pi)/sqr(gs);
#ifdef GAUGE_CHECK
double ratio = output/total;
if(abs(ratio)>1e-20) {
generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n";
for(unsigned int ix=0;ix<decay.size();++ix)
generator()->log() << *decay[ix] << "\n";
generator()->log() << "Test of gauge invariance " << ratio << "\n";
}
#endif
// return the answer
return output;
}
void VVVDecayer::identifyVertices(const Particle & inpart, const ParticleVector & decay,
AbstractVVVVertexPtr & outgoingVertex1,
AbstractVVVVertexPtr & outgoingVertex2,
ShowerInteraction inter) {
if(inter==ShowerInteraction::QCD) {
// work out which scalar each outgoing vertex corresponds to
// two outgoing vertices
if( inpart.dataPtr() ->iColour()==PDT::Colour0 &&
((decay[0]->dataPtr()->iColour()==PDT::Colour3 &&
decay[1]->dataPtr()->iColour()==PDT::Colour3bar) ||
(decay[0]->dataPtr()->iColour()==PDT::Colour8 &&
decay[1]->dataPtr()->iColour()==PDT::Colour8))){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){
outgoingVertex1 = outgoingVertex2_[inter];
outgoingVertex2 = outgoingVertex1_[inter];
}
}
else if(inpart.dataPtr() ->iColour()==PDT::Colour8 &&
decay[0]->dataPtr()->iColour()==PDT::Colour3 &&
decay[1]->dataPtr()->iColour()==PDT::Colour3bar){
if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){
outgoingVertex1 = outgoingVertex2_[inter];
outgoingVertex2 = outgoingVertex1_[inter];
}
}
// one outgoing vertex
else if(inpart.dataPtr()->iColour()==PDT::Colour3){
if(decay[0]->dataPtr()->iColour()==PDT::Colour3 &&
decay[1]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertex1 = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertex1 = outgoingVertex2_[inter];
}
else if (decay[0]->dataPtr()->iColour()==PDT::Colour3 &&
decay[1]->dataPtr()->iColour()==PDT::Colour8){
if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->dataPtr()->id()))){
outgoingVertex1 = outgoingVertex2_[inter];
outgoingVertex2 = outgoingVertex1_[inter];
}
else {
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
}
}
else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){
if(decay[1]->dataPtr()->iColour()==PDT::Colour3bar &&
decay[0]->dataPtr()->iColour()==PDT::Colour0){
if (outgoingVertex1_[inter]) outgoingVertex2 = outgoingVertex1_[inter];
else if(outgoingVertex2_[inter]) outgoingVertex2 = outgoingVertex2_[inter];
}
else if (decay[0]->dataPtr()->iColour()==PDT::Colour8 &&
decay[1]->dataPtr()->iColour()==PDT::Colour3bar){
if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->dataPtr()->id()))){
outgoingVertex1 = outgoingVertex1_[inter];
outgoingVertex2 = outgoingVertex2_[inter];
}
else {
outgoingVertex1 = outgoingVertex2_[inter];
outgoingVertex2 = outgoingVertex1_[inter];
}
}
}
if (! ((incomingVertex_[inter] && (outgoingVertex1 || outgoingVertex2)) ||
( outgoingVertex1 && outgoingVertex2)))
throw Exception()
<< "Invalid vertices for QCD radiation in VVV decay in VVVDecayer::identifyVertices"
<< Exception::runerror;
}
else {
if(decay[0]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[0]->dataPtr())))
outgoingVertex1 = outgoingVertex1_[inter];
else
outgoingVertex1 = outgoingVertex2_[inter];
}
if(decay[1]->dataPtr()->charged()) {
if (outgoingVertex1_[inter] &&
outgoingVertex1_[inter]->isIncoming(const_ptr_cast<tPDPtr>(decay[1]->dataPtr())))
outgoingVertex2 = outgoingVertex1_[inter];
else
outgoingVertex2 = outgoingVertex2_[inter];
}
}
}
diff --git a/Decay/General/VVVDecayer.h b/Decay/General/VVVDecayer.h
--- a/Decay/General/VVVDecayer.h
+++ b/Decay/General/VVVDecayer.h
@@ -1,220 +1,228 @@
// -*- C++ -*-
//
// VVVDecayer.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_VVVDecayer_H
#define HERWIG_VVVDecayer_H
//
// This is the declaration of the VVVDecayer class.
//
#include "GeneralTwoBodyDecayer.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VVVVertexPtr;
/** \ingroup Decay
* The VVVDecayer class implements the decay of a vector
* to 2 vectors in a general model. It holds an VVVVertex pointer
* that must be typecast from the VertexBase pointer held in
* GeneralTwoBodyDecayer. It implents the virtual functions me2() and
* partialWidth().
*
* @see GeneralTwoBodyDecayer
*/
class VVVDecayer: public GeneralTwoBodyDecayer {
public:
/**
* The default constructor.
*/
VVVDecayer() {}
/** @name Virtual functions required by the Decayer class. */
//@{
/**
* Return the matrix element squared for a given mode and phase-space channel.
* @param ichan The channel we are calculating the matrix element for.
* @param part The decaying Particle.
* @param decay The particles produced in the decay.
* @param meopt Option for the calculation of the matrix element
* @return The matrix element squared for the phase-space configuration.
*/
virtual double me2(const int ichan, const Particle & part,
const ParticleVector & decay, MEOption meopt) const;
/**
* Function to return partial Width
* @param inpart The decaying particle.
* @param outa One of the decay products.
* @param outb The other decay product.
*/
virtual Energy partialWidth(PMPair inpart, PMPair outa,
PMPair outb) const;
/**
* Set the information on the decay
*/
- virtual void setDecayInfo(PDPtr incoming, PDPair outgoing, VertexBasePtr,
+ virtual void setDecayInfo(PDPtr incoming, PDPair outgoing,
+ vector<VertexBasePtr>,
map<ShowerInteraction,VertexBasePtr> &,
const vector<map<ShowerInteraction,VertexBasePtr> > &,
map<ShowerInteraction,VertexBasePtr>);
/**
* Has a POWHEG style correction
*/
virtual POWHEGType hasPOWHEGCorrection() {
- return (vertex_->orderInGem()+vertex_->orderInGs())==1 ? FSR : No;
+ 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);
//@}
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:
/**
* Find the vertices for the decay
*/
void identifyVertices(const Particle & inpart, const ParticleVector & decay,
AbstractVVVVertexPtr & outgoingVertex1,
AbstractVVVVertexPtr & outgoingVertex2,
ShowerInteraction inter);
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
VVVDecayer & operator=(const VVVDecayer &);
private:
/**
* Abstract pointer to AbstractVVVVertex
*/
- AbstractVVVVertexPtr vertex_;
+ vector<AbstractVVVVertexPtr> vertex_;
/**
* Pointer to the perturbative vertex
*/
- VVVVertexPtr perturbativeVertex_;
+ vector<VVVVertexPtr> perturbativeVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from incoming vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> incomingVertex_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from the first outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertex1_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from the second outgoing vector
*/
map<ShowerInteraction,AbstractVVVVertexPtr> outgoingVertex2_;
/**
* Abstract pointer to AbstractVVVVertex for QCD radiation from the 4-point vertex
*/
map<ShowerInteraction,AbstractVVVVVertexPtr> fourPointVertex_;
/**
* Spin density matrix
*/
mutable RhoDMatrix rho_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors_[3];
private:
/**
* Members for the POWHEG correction
*/
//@{
/**
* Spin density matrix for 3 body decay
*/
mutable RhoDMatrix rho3_;
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> vector3_;
/**
* Vector wavefunctions
*/
mutable vector<Helicity::VectorWaveFunction> vectors3_[2];
/**
* Vector wavefunction for 3 body decay
*/
mutable vector<Helicity::VectorWaveFunction> gluon_;
//@}
};
}
#endif /* HERWIG_VVVDecayer_H */
diff --git a/Decay/General/VtoFFVDecayer.cc b/Decay/General/VtoFFVDecayer.cc
--- a/Decay/General/VtoFFVDecayer.cc
+++ b/Decay/General/VtoFFVDecayer.cc
@@ -1,368 +1,369 @@
// -*- 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();
+ 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);
}
}
}
double VtoFFVDecayer::me2(const int ichan, const Particle & inpart,
const ParticleVector & decay,
MEOption meopt) const {
// particle or CC of particle
bool cc = (*getProcessInfo().begin()).incoming != inpart.id();
// special handling or first/last call
if(meopt==Initialize) {
VectorWaveFunction::
calculateWaveFunctions(inVector_,rho_,const_ptr_cast<tPPtr>(&inpart),
Helicity::incoming,false);
}
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;
ivec = ix;
VectorWaveFunction::
calculateWaveFunctions(outVector_, decay[ix], Helicity::outgoing, massless );
}
else {
SpinorWaveFunction::
calculateWaveFunctions(outspin_[ix].first,decay[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()));
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) {
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)
? 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 ) {
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) {
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) {
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/PerturbativeDecayer.cc b/Decay/PerturbativeDecayer.cc
--- a/Decay/PerturbativeDecayer.cc
+++ b/Decay/PerturbativeDecayer.cc
@@ -1,1169 +1,1172 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the PerturbativeDecayer class.
//
#include "PerturbativeDecayer.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Utilities/EnumIO.h"
using namespace Herwig;
void PerturbativeDecayer::persistentOutput(PersistentOStream & os) const {
os << ounit(pTmin_,GeV) << oenum(inter_) << alphaS_ << alphaEM_
<< useMEforT2_ << C_ << ymax_ << phaseOpt_;
}
void PerturbativeDecayer::persistentInput(PersistentIStream & is, int) {
is >> iunit(pTmin_,GeV) >> ienum(inter_) >> alphaS_ >> alphaEM_
>> useMEforT2_ >> C_ >> ymax_ >> phaseOpt_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeAbstractClass<PerturbativeDecayer,DecayIntegrator>
describeHerwigPerturbativeDecayer("Herwig::PerturbativeDecayer",
"Herwig.so HwPerturbativeDecay.so");
void PerturbativeDecayer::Init() {
static ClassDocumentation<PerturbativeDecayer> documentation
("The PerturbativeDecayer class is the mase class for "
"perturbative decays in Herwig");
static Parameter<PerturbativeDecayer,Energy> interfacepTmin
("pTmin",
"Minimum transverse momentum from gluon radiation",
&PerturbativeDecayer::pTmin_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Switch<PerturbativeDecayer,ShowerInteraction> interfaceInteractions
("Interactions",
"which interactions to include for the hard corrections",
&PerturbativeDecayer::inter_, ShowerInteraction::QCD, false, false);
static SwitchOption interfaceInteractionsQCD
(interfaceInteractions,
"QCD",
"QCD Only",
ShowerInteraction::QCD);
static SwitchOption interfaceInteractionsQED
(interfaceInteractions,
"QED",
"QED only",
ShowerInteraction::QED);
static SwitchOption interfaceInteractionsQCDandQED
(interfaceInteractions,
"QCDandQED",
"Both QCD and QED",
ShowerInteraction::QEDQCD);
static Reference<PerturbativeDecayer,ShowerAlpha> interfaceAlphaS
("AlphaS",
"Object for the coupling in the generation of hard QCD radiation",
&PerturbativeDecayer::alphaS_, false, false, true, true, false);
static Reference<PerturbativeDecayer,ShowerAlpha> interfaceAlphaEM
("AlphaEM",
"Object for the coupling in the generation of hard QED radiation",
&PerturbativeDecayer::alphaEM_, false, false, true, true, false);
static Switch<PerturbativeDecayer,bool> interfaceUseMEForT2
("UseMEForT2",
"Use the matrix element correction, if available to fill the T2"
" region for the decay shower and don't fill using the shower",
&PerturbativeDecayer::useMEforT2_, true, false, false);
static SwitchOption interfaceUseMEForT2Shower
(interfaceUseMEForT2,
"Shower",
"Use the shower to fill the T2 region",
false);
static SwitchOption interfaceUseMEForT2ME
(interfaceUseMEForT2,
"ME",
"Use the Matrix element to fill the T2 region",
true);
static Parameter<PerturbativeDecayer,double> interfacePrefactor
("Prefactor",
"The prefactor for the sampling of the powheg Sudakov",
&PerturbativeDecayer::C_, 6.3, 0.0, 1e10,
false, false, Interface::limited);
static Parameter<PerturbativeDecayer,double> interfaceYMax
("YMax",
"The maximum value for the rapidity",
&PerturbativeDecayer::ymax_, 10., 0.0, 100.,
false, false, Interface::limited);
static Switch<PerturbativeDecayer,unsigned int> interfacePhaseSpaceOption
("PhaseSpaceOption",
"Option for the phase-space sampling",
&PerturbativeDecayer::phaseOpt_, 0, false, false);
static SwitchOption interfacePhaseSpaceOptionFixedYLimits
(interfacePhaseSpaceOption,
"FixedYLimits",
"Use a fixed limit for the rapidity",
0);
static SwitchOption interfacePhaseSpaceOptionVariableYLimits
(interfacePhaseSpaceOption,
"VariableYLimits",
"Change limit for the rapidity with pT",
1);
}
double PerturbativeDecayer::matrixElementRatio(const Particle & ,
const ParticleVector & ,
const ParticleVector & ,
MEOption ,
ShowerInteraction ) {
throw Exception() << "Base class PerturbativeDecayer::matrixElementRatio() "
<< "called, should have an implementation in the inheriting class"
<< Exception::runerror;
return 0.;
}
RealEmissionProcessPtr PerturbativeDecayer::generateHardest(RealEmissionProcessPtr born) {
return getHardEvent(born,false,inter_);
}
RealEmissionProcessPtr PerturbativeDecayer::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) {
return getHardEvent(born,true,ShowerInteraction::QCD);
}
RealEmissionProcessPtr PerturbativeDecayer::getHardEvent(RealEmissionProcessPtr born,
bool inDeadZone,
ShowerInteraction inter) {
// check one incoming
assert(born->bornIncoming().size()==1);
// check exactly two outgoing particles
assert(born->bornOutgoing().size()==2); // search for coloured particles
bool colouredParticles=born->bornIncoming()[0]->dataPtr()->coloured();
bool chargedParticles=born->bornIncoming()[0]->dataPtr()->charged();
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]->dataPtr()->coloured())
colouredParticles=true;
if(born->bornOutgoing()[ix]->dataPtr()->charged())
chargedParticles=true;
}
// if no coloured/charged particles return
if ( !colouredParticles && !chargedParticles ) return RealEmissionProcessPtr();
if ( !colouredParticles && inter==ShowerInteraction::QCD ) return RealEmissionProcessPtr();
if ( ! chargedParticles && inter==ShowerInteraction::QED ) return RealEmissionProcessPtr();
// for decay b -> a c
// set progenitors
PPtr cProgenitor = born->bornOutgoing()[0];
PPtr aProgenitor = born->bornOutgoing()[1];
// get the decaying particle
PPtr bProgenitor = born->bornIncoming()[0];
// identify which dipoles are required
vector<DipoleType> dipoles;
if(!identifyDipoles(dipoles,aProgenitor,bProgenitor,cProgenitor,inter)) {
return RealEmissionProcessPtr();
}
Energy trialpT = pTmin_;
LorentzRotation eventFrame;
vector<Lorentz5Momentum> momenta;
vector<Lorentz5Momentum> trialMomenta(4);
PPtr finalEmitter, finalSpectator;
PPtr trialEmitter, trialSpectator;
DipoleType finalType(FFa,ShowerInteraction::QCD);
for (int i=0; i<int(dipoles.size()); ++i) {
if(dipoles[i].type==FFg) continue;
// assign emitter and spectator based on current dipole
if (dipoles[i].type==FFc || dipoles[i].type==IFc || dipoles[i].type==IFbc) {
trialEmitter = cProgenitor;
trialSpectator = aProgenitor;
}
else if (dipoles[i].type==FFa || dipoles[i].type==IFa || dipoles[i].type==IFba) {
trialEmitter = aProgenitor;
trialSpectator = cProgenitor;
}
// find rotation from lab to frame with the spectator along -z
LorentzRotation trialEventFrame(bProgenitor->momentum().findBoostToCM());
Lorentz5Momentum pspectator = (trialEventFrame*trialSpectator->momentum());
trialEventFrame.rotateZ( -pspectator.phi() );
trialEventFrame.rotateY( -pspectator.theta() - Constants::pi );
// invert it
trialEventFrame.invert();
// try to generate an emission
pT_ = pTmin_;
vector<Lorentz5Momentum> trialMomenta
= hardMomenta(bProgenitor, trialEmitter, trialSpectator,
dipoles, i, inDeadZone);
// select dipole which gives highest pT emission
if(pT_>trialpT) {
trialpT = pT_;
momenta = trialMomenta;
eventFrame = trialEventFrame;
finalEmitter = trialEmitter;
finalSpectator = trialSpectator;
finalType = dipoles[i];
if (dipoles[i].type==FFc || dipoles[i].type==FFa ) {
if((momenta[3]+momenta[1]).m2()-momenta[1].m2()>
(momenta[3]+momenta[2]).m2()-momenta[2].m2()) {
swap(finalEmitter,finalSpectator);
swap(momenta[1],momenta[2]);
}
}
}
}
pT_ = trialpT;
// if no emission return
if(momenta.empty()) {
if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::QCD)
born->pT()[ShowerInteraction::QCD] = pTmin_;
if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::QED)
born->pT()[ShowerInteraction::QED] = pTmin_;
return born;
}
// rotate momenta back to the lab
for(unsigned int ix=0;ix<momenta.size();++ix) {
momenta[ix] *= eventFrame;
}
// set maximum pT for subsequent branchings
if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::QCD)
born->pT()[ShowerInteraction::QCD] = pT_;
if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::QED)
born->pT()[ShowerInteraction::QED] = pT_;
// get ParticleData objects
tcPDPtr b = bProgenitor ->dataPtr();
tcPDPtr e = finalEmitter ->dataPtr();
tcPDPtr s = finalSpectator->dataPtr();
tcPDPtr boson = getParticleData(finalType.interaction==ShowerInteraction::QCD ?
ParticleID::g : ParticleID::gamma);
// create new ShowerParticles
PPtr emitter = e ->produceParticle(momenta[1]);
PPtr spectator = s ->produceParticle(momenta[2]);
PPtr gauge = boson->produceParticle(momenta[3]);
PPtr incoming = b ->produceParticle(bProgenitor->momentum());
// insert the particles
born->incoming().push_back(incoming);
unsigned int iemit(0),ispect(0);
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]==finalEmitter) {
born->outgoing().push_back(emitter);
iemit = born->outgoing().size();
}
else if(born->bornOutgoing()[ix]==finalSpectator) {
born->outgoing().push_back(spectator);
ispect = born->outgoing().size();
}
}
born->outgoing().push_back(gauge);
if(!spectator->dataPtr()->coloured() ||
(finalType.type != FFa && finalType.type!=FFc) ) ispect = 0;
born->emitter(iemit);
born->spectator(ispect);
born->emitted(3);
// boost if being use as ME correction
if(inDeadZone) {
if(finalType.type==IFa || finalType.type==IFba) {
LorentzRotation trans(cProgenitor->momentum().findBoostToCM());
trans.boost(spectator->momentum().boostVector());
born->transformation(trans);
}
else if(finalType.type==IFc || finalType.type==IFbc) {
LorentzRotation trans(bProgenitor->momentum().findBoostToCM());
trans.boost(spectator->momentum().boostVector());
born->transformation(trans);
}
}
// set the interaction
born->interaction(finalType.interaction);
// set up colour lines
getColourLines(born);
// return the tree
return born;
}
bool PerturbativeDecayer::identifyDipoles(vector<DipoleType> & dipoles,
PPtr & aProgenitor,
PPtr & bProgenitor,
PPtr & cProgenitor,
ShowerInteraction inter) const {
enhance_ = 1.;
// identify any QCD dipoles
if(inter==ShowerInteraction::QCD ||
inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD ) {
PDT::Colour bColour = bProgenitor->dataPtr()->iColour();
PDT::Colour cColour = cProgenitor->dataPtr()->iColour();
PDT::Colour aColour = aProgenitor->dataPtr()->iColour();
// decaying colour singlet
if (bColour==PDT::Colour0 ) {
if ((cColour==PDT::Colour3 && aColour==PDT::Colour3bar) ||
(cColour==PDT::Colour3bar && aColour==PDT::Colour3) ||
(cColour==PDT::Colour8 && aColour==PDT::Colour8)){
dipoles.push_back(DipoleType(FFa,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc,ShowerInteraction::QCD));
if(aProgenitor->id()==ParticleID::g &&
cProgenitor->id()==ParticleID::g ) {
enhance_ = 1.5;
dipoles.push_back(DipoleType(FFg,ShowerInteraction::QCD));
}
}
}
// decaying colour triplet
else if (bColour==PDT::Colour3 ) {
if (cColour==PDT::Colour3 && aColour==PDT::Colour0){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour0 && aColour==PDT::Colour3){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour8 && aColour==PDT::Colour3){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour3 && aColour==PDT::Colour8){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
else if(cColour==PDT::Colour3bar && aColour==PDT::Colour3bar) {
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
}
// decaying colour anti-triplet
else if (bColour==PDT::Colour3bar) {
if ((cColour==PDT::Colour3bar && aColour==PDT::Colour0)){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD));
}
else if ((cColour==PDT::Colour0 && aColour==PDT::Colour3bar)){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour8 && aColour==PDT::Colour3bar){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour3bar && aColour==PDT::Colour8){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
else if(cColour==PDT::Colour3 && aColour==PDT::Colour3) {
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFc ,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(FFa ,ShowerInteraction::QCD));
}
}
// decaying colour octet
else if (bColour==PDT::Colour8){
if ((cColour==PDT::Colour3 && aColour==PDT::Colour3bar) ||
(cColour==PDT::Colour3bar && aColour==PDT::Colour3)){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour8 && aColour==PDT::Colour0){
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD));
}
else if (cColour==PDT::Colour0 && aColour==PDT::Colour8){
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD));
}
}
// decaying colour sextet
else if(bColour==PDT::Colour6) {
if (cColour==PDT::Colour3 && aColour==PDT::Colour3) {
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD));
}
}
// decaying colour antisextet
else if(bColour==PDT::Colour6bar) {
if (cColour==PDT::Colour3bar && aColour==PDT::Colour3bar) {
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFa,ShowerInteraction::QCD));
dipoles.push_back(DipoleType(IFc,ShowerInteraction::QCD));
}
}
}
// QED dipoles
if(inter==ShowerInteraction::ALL || inter==ShowerInteraction::QEDQCD ||
inter==ShowerInteraction::QED) {
const bool & bCharged = bProgenitor->dataPtr()->charged();
const bool & cCharged = cProgenitor->dataPtr()->charged();
const bool & aCharged = aProgenitor->dataPtr()->charged();
// initial-final
if(bCharged && aCharged) {
dipoles.push_back(DipoleType(IFba,ShowerInteraction::QED));
dipoles.push_back(DipoleType(IFa ,ShowerInteraction::QED));
}
if(bCharged && cCharged) {
dipoles.push_back(DipoleType(IFbc,ShowerInteraction::QED));
dipoles.push_back(DipoleType(IFc ,ShowerInteraction::QED));
}
// final-state
if(aCharged && cCharged) {
dipoles.push_back(DipoleType(FFa,ShowerInteraction::QED));
dipoles.push_back(DipoleType(FFc,ShowerInteraction::QED));
}
}
// check colour structure is allowed
return !dipoles.empty();
}
vector<Lorentz5Momentum> PerturbativeDecayer::hardMomenta(PPtr in, PPtr emitter,
PPtr spectator,
const vector<DipoleType> &dipoles,
int i, bool inDeadZone) {
// get masses of the particles
mb_ = in ->momentum().mass();
e_ = emitter ->momentum().mass()/mb_;
s_ = spectator->momentum().mass()/mb_;
e2_ = sqr(e_);
s2_ = sqr(s_);
vector<Lorentz5Momentum> particleMomenta;
Energy2 lambda = sqr(mb_)*sqrt(1.+sqr(s2_)+sqr(e2_)-2.*s2_-2.*e2_-2.*s2_*e2_);
// calculate A
double pre = C_;
// multiply by the colour factor of the dipole
// ISR
if (dipoles[i].type==IFba || dipoles[i].type==IFbc) {
pre *= colourCoeff(in->dataPtr(),emitter->dataPtr(),spectator->dataPtr(),dipoles[i]);
}
// radiation from a/c with initial-final connection
else if (dipoles[i].type==IFa || dipoles[i].type==IFc) {
pre *= colourCoeff(emitter->dataPtr(),in->dataPtr(),spectator->dataPtr(),dipoles[i]);
}
// radiation from a/c with final-final connection
else if (dipoles[i].type==FFa || dipoles[i].type==FFc) {
pre *= colourCoeff(emitter->dataPtr(),spectator->dataPtr(),in->dataPtr(),dipoles[i]);
}
double A = 2.*abs(pre)/Constants::twopi;
// factor due sampling choice
if(phaseOpt_==0) A *= ymax_;
// coupling factor
if(dipoles[i].interaction==ShowerInteraction::QCD)
A *= alphaS() ->overestimateValue();
else
A *= alphaEM()->overestimateValue();
Energy pTmax = 0.5*mb_*(1.-sqr(s_+e_));
// if no possible branching return
if ( pTmax < pTmin_ ) return particleMomenta;
// loop over the two regions
for(unsigned int j=0;j<2;++j) {
Energy pT=pTmax;
vector<Lorentz5Momentum> momenta(4);
while (pT >= pTmin_) {
double ymax;
// overestimate with flat y limit
if(phaseOpt_==0) {
pT *= pow(UseRandom::rnd(),(1./A));
ymax=ymax_;
}
// pT sampling including tighter pT dependent y limit
else {
pT = 2.*pTmax*exp(-sqrt(-2.*log(UseRandom::rnd())/A+sqr(log(2.*pTmax/pT))));
// choice of limit overestimate ln(2*pTmax/pT) (true limit acosh(pTmax/pT))
ymax = log(2.*pTmax/pT);
}
if (pT < pTmin_) break;
double phi = UseRandom::rnd()*Constants::twopi;
double y = ymax*(2.*UseRandom::rnd()-1.);
double xs, xe, xe_z, xg;
// check if the momenta are physical
if (!calcMomenta(j, pT, y, phi, xg, xs, xe,
xe_z, momenta))
continue;
// check if point lies within phase space
if (!psCheck(xg, xs)) continue;
// check if point lies within the dead-zone (if required)
if(inDeadZone && !inTotalDeadZone(xg,xs,dipoles,i)) continue;
// decay products for 3 body decay
PPtr inpart = in ->dataPtr()->produceParticle(momenta[0]);
ParticleVector decay3;
decay3.push_back(emitter ->dataPtr()->produceParticle(momenta[1]));
decay3.push_back(spectator->dataPtr()->produceParticle(momenta[2]));
if(dipoles[i].interaction==ShowerInteraction::QCD)
decay3.push_back(getParticleData(ParticleID::g )->produceParticle(momenta[3]));
else
decay3.push_back(getParticleData(ParticleID::gamma)->produceParticle(momenta[3]));
// decay products for 2 body decay
Lorentz5Momentum p1(ZERO,ZERO, lambda/2./mb_,(mb_/2.)*(1.+e2_-s2_),mb_*e_);
Lorentz5Momentum p2(ZERO,ZERO,-lambda/2./mb_,(mb_/2.)*(1.+s2_-e2_),mb_*s_);
ParticleVector decay2;
decay2.push_back(emitter ->dataPtr()->produceParticle(p1));
decay2.push_back(spectator->dataPtr()->produceParticle(p2));
if (dipoles[i].type==FFa || dipoles[i].type==IFa || dipoles[i].type==IFba) {
swap(decay2[0],decay2[1]);
swap(decay3[0],decay3[1]);
}
// calculate matrix element ratio R/B
double meRatio = matrixElementRatio(*inpart,decay2,decay3,Initialize,dipoles[i].interaction);
// calculate dipole factor
double dipoleSum(0.),numerator(0.);
for (int k=0; k<int(dipoles.size()); ++k) {
// skip dipoles which are not of the interaction being considered
if(dipoles[k].interaction!=dipoles[i].interaction) continue;
pair<double,double> dipole = calculateDipole(dipoles[k],*inpart,decay3);
dipoleSum += abs(dipole.first);
if (k==i) numerator = abs(dipole.second);
}
meRatio *= numerator/dipoleSum;
// calculate jacobian
Energy2 denom = (mb_-momenta[3].e())*momenta[2].vect().mag() -
momenta[2].e()*momenta[3].z();
InvEnergy2 J = (momenta[2].vect().mag2())/(lambda*denom);
// calculate weight
double weight = enhance_*meRatio*fabs(sqr(pT)*J)/pre/Constants::twopi;
if(dipoles[i].interaction==ShowerInteraction::QCD)
weight *= alphaS() ->ratio(pT*pT);
else
weight *= alphaEM()->ratio(pT*pT);
// accept point if weight > R
if (pT > pT_ && weight > UseRandom::rnd()) {
particleMomenta=momenta;
if (weight > 1.) {
generator()->log() << "WEIGHT PROBLEM " << fullName() << " " << weight << "\n";
generator()->log() << xe << " " << xs << " " << xg << "\n";
for(unsigned int ix=0;ix<particleMomenta.size();++ix)
generator()->log() << particleMomenta[ix]/GeV << "\n";
}
pT_ = pT;
break;
}
}
}
return particleMomenta;
}
bool PerturbativeDecayer::calcMomenta(int j, Energy pT, double y, double phi,
double& xg, double& xs, double& xe, double& xe_z,
vector<Lorentz5Momentum>& particleMomenta) {
// calculate xg
xg = 2.*pT*cosh(y) / mb_;
if (xg>(1. - sqr(e_ + s_)) || xg<0.) return false;
// calculate the two values of zs
double xT = 2.*pT / mb_;
double zg = 2.*pT*sinh(y) / mb_;
double A = (sqr(xT) - 4. * xg + 4.);
double B = 2. * zg * (s2_ - e2_ - xg + 1.);
double det = -4. * (-sqr(s2_) + (2. * e2_ + sqr(xT) - 2. * xg + 2.) * s2_ - sqr(e2_ + xg - 1.)) * sqr(xg - 2.);
if (det<0.) return false;
double zs= j==0 ? (-B+sqrt(det))/A : (-B-sqrt(det))/A;
+ // zs must be negative
+ if(zs>0.) return false;
xs = sqrt(sqr(zs)+4.*s2_);
// check value of xs is physical
if (xs>(1.+s2_-e2_) || xs<2.*s_) return false;
// calculate xe
xe = 2.-xs-xg;
// check value of xe is physical
if (xe>(1.+e2_-s2_) || xe<2.*e_) return false;
+ // calculate xe_z
xe_z = -zg-zs;
// calculate 4 momenta
particleMomenta[0].setE ( mb_);
particleMomenta[0].setX ( ZERO);
particleMomenta[0].setY ( ZERO);
particleMomenta[0].setZ ( ZERO);
particleMomenta[0].setMass( mb_);
particleMomenta[1].setE ( mb_*xe/2.);
particleMomenta[1].setX (-pT*cos(phi));
particleMomenta[1].setY (-pT*sin(phi));
particleMomenta[1].setZ ( mb_*xe_z/2.);
particleMomenta[1].setMass( mb_*e_);
particleMomenta[2].setE ( mb_*xs/2.);
particleMomenta[2].setX ( ZERO);
particleMomenta[2].setY ( ZERO);
particleMomenta[2].setZ ( mb_*zs/2.);
particleMomenta[2].setMass( mb_*s_);
particleMomenta[3].setE ( pT*cosh(y));
particleMomenta[3].setX ( pT*cos(phi));
particleMomenta[3].setY ( pT*sin(phi));
particleMomenta[3].setZ ( pT*sinh(y));
particleMomenta[3].setMass( ZERO);
return true;
}
bool PerturbativeDecayer::psCheck(const double xg, const double xs) {
// check is point is in allowed region of phase space
double xe_star = (1.-s2_+e2_-xg)/sqrt(1.-xg);
double xg_star = xg/sqrt(1.-xg);
if ((sqr(xe_star)-4.*e2_) < 1e-10) return false;
double xs_max = (4.+4.*s2_-sqr(xe_star+xg_star)+
sqr(sqrt(sqr(xe_star)-4.*e2_)+xg_star))/ 4.;
double xs_min = (4.+4.*s2_-sqr(xe_star+xg_star)+
sqr(sqrt(sqr(xe_star)-4.*e2_)-xg_star))/ 4.;
if (xs < xs_min || xs > xs_max) return false;
return true;
}
pair<double,double> PerturbativeDecayer::calculateDipole(const DipoleType & dipoleId,
const Particle & inpart,
const ParticleVector & decay3) {
// calculate dipole for decay b->ac
pair<double,double> dipole = make_pair(0.,0.);
double x1 = 2.*decay3[0]->momentum().e()/mb_;
double x2 = 2.*decay3[1]->momentum().e()/mb_;
double xg = 2.*decay3[2]->momentum().e()/mb_;
double mu12 = sqr(decay3[0]->mass()/mb_);
double mu22 = sqr(decay3[1]->mass()/mb_);
tcPDPtr part[3] = {inpart.dataPtr(),decay3[0]->dataPtr(),decay3[1]->dataPtr()};
if(dipoleId.type==FFa || dipoleId.type == IFa || dipoleId.type == IFba) {
swap(part[1],part[2]);
swap(x1,x2);
swap(mu12,mu22);
}
// radiation from b with initial-final connection
if (dipoleId.type==IFba || dipoleId.type==IFbc) {
dipole.first = -2./sqr(xg);
dipole.first *= colourCoeff(part[0],part[1],part[2],dipoleId);
}
// radiation from a/c with initial-final connection
else if (dipoleId.type==IFa || dipoleId.type==IFc) {
double z = 1. - xg/(1.-mu22+mu12);
dipole.first = (-2.*mu12/sqr(1.-x2+mu22-mu12) + (1./(1.-x2+mu22-mu12))*
(2./(1.-z)-dipoleSpinFactor(part[1],z)));
dipole.first *= colourCoeff(part[1],part[0],part[2],dipoleId);
}
// radiation from a/c with final-final connection
else if (dipoleId.type==FFa || dipoleId.type==FFc) {
double z = 1. + ((x1-1.+mu22-mu12)/(x2-2.*mu22));
double y = (1.-x2-mu12+mu22)/(1.-mu12-mu22);
double vt = sqrt((1.-sqr(e_+s_))*(1.-sqr(e_-s_)))/(1.-mu12-mu22);
double v = sqrt(sqr(2.*mu22+(1.-mu12-mu22)*(1.-y))-4.*mu22)
/(1.-y)/(1.-mu12-mu22);
if(part[1]->iSpin()!=PDT::Spin1) {
dipole.first = (1./(1.-x2+mu22-mu12))*
((2./(1.-z*(1.-y)))-vt/v*(dipoleSpinFactor(part[1],z)+(2.*mu12/(1.+mu22-mu12-x2))));
}
else {
dipole.first = (1./(1.-x2+mu22-mu12))*
(1./(1.-z*(1.-y))+1./(1.-(1.-z)*(1.-y))+(z*(1.-z)-2.)/v-vt/v*(2.*mu12/(1.+mu22-mu12-x2)));
dipole.second = (1./(1.-x2+mu22-mu12))*
(2./(1.-z*(1.-y))+(z*(1.-z)-2.)/v-vt/v*(2.*mu12/(1.+mu22-mu12-x2)));
dipole.second *= colourCoeff(part[1],part[2],part[0],dipoleId);
}
dipole.first *= colourCoeff(part[1],part[2],part[0],dipoleId);
}
// special for the case that all particles are gluons
else if(dipoleId.type==FFg) {
double z = (1.-x2)/xg;
double y = 1.-xg;
dipole.first = 1./(1.-xg)*(1./(1.-z*(1.-y))+1./(1.-(1.-z)*(1.-y))+(z*(1.-z)-2.));
dipole.first *= colourCoeff(part[1],part[2],part[0],dipoleId);
}
else
assert(false);
// coupling prefactors
if(dipole.second==0.) dipole.second=dipole.first;
dipole.first *= 8.*Constants::pi;
dipole.second *= 8.*Constants::pi;
// return the answer
return dipole;
}
double PerturbativeDecayer::dipoleSpinFactor(tcPDPtr part, double z){
// calculate the spin dependent component of the dipole
if (part->iSpin()==PDT::Spin0)
return 2.;
else if (part->iSpin()==PDT::Spin1Half)
return (1. + z);
else if (part->iSpin()==PDT::Spin1)
return -(z*(1.-z) - 1./(1.-z) + 1./z -2.);
return 0.;
}
namespace {
double colourCharge(PDT::Colour icol) {
switch(icol) {
case PDT::Colour0 :
return 0.;
case PDT::Colour3 : case PDT::Colour3bar :
return 4./3.;
case PDT::Colour8:
return 3.;
case PDT::Colour6 : case PDT::Colour6bar :
return 10./3.;
default :
assert(false);
}
}
}
double PerturbativeDecayer::colourCoeff(tcPDPtr emitter,
tcPDPtr spectator,
tcPDPtr other,
DipoleType dipole) {
if(dipole.interaction==ShowerInteraction::QCD) {
double emitterColour = colourCharge(emitter ->iColour());
double spectatorColour = colourCharge(spectator->iColour());
double otherColour = colourCharge(other ->iColour());
double val = 0.5*(sqr(emitterColour)+sqr(spectatorColour)-sqr(otherColour))/emitterColour;
return val;
}
else {
double val = double(emitter->iCharge()*spectator->iCharge())/9.;
// FF dipoles
if(dipole.type==FFa || dipole.type == FFc) return -val;
// IF dipoles
else return val;
}
}
void PerturbativeDecayer::getColourLines(RealEmissionProcessPtr real) {
// extract the particles
vector<tPPtr> branchingPart;
branchingPart.push_back(real->incoming()[0]);
for(unsigned int ix=0;ix<real->outgoing().size();++ix) {
branchingPart.push_back(real->outgoing()[ix]);
}
vector<unsigned int> sing,trip,atrip,oct,sex,asex;
for (size_t ib=0;ib<branchingPart.size()-1;++ib) {
if (branchingPart[ib]->dataPtr()->iColour()==PDT::Colour0 ) sing. push_back(ib);
else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour3 ) trip. push_back(ib);
else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour3bar) atrip.push_back(ib);
else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour8 ) oct. push_back(ib);
else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour6 ) sex. push_back(ib);
else if(branchingPart[ib]->dataPtr()->iColour()==PDT::Colour6bar) asex. push_back(ib);
}
// decaying colour singlet
if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour0) {
// 0 -> 3 3bar
if (trip.size()==1 && atrip.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
branchingPart[atrip[0]]->colourConnect(branchingPart[ 3 ]);
branchingPart[ 3 ]->colourConnect(branchingPart[trip[0]]);
}
else {
branchingPart[atrip[0]]->colourConnect(branchingPart[trip[0]]);
}
}
// 0 -> 8 8
else if (oct.size()==2 ) {
if(real->interaction()==ShowerInteraction::QCD) {
bool col = UseRandom::rndbool();
branchingPart[oct[0]]->colourConnect(branchingPart[ 3 ],col);
branchingPart[ 3 ]->colourConnect(branchingPart[oct[1]],col);
branchingPart[oct[1]]->colourConnect(branchingPart[oct[0]],col);
}
else {
branchingPart[oct[0]]->colourConnect(branchingPart[oct[1]]);
branchingPart[oct[1]]->colourConnect(branchingPart[oct[0]]);
}
}
else
assert(real->interaction()==ShowerInteraction::QED);
}
// decaying colour triplet
else if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour3 ) {
// 3 -> 3 0
if (trip.size()==2 && sing.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
branchingPart[3]->incomingColour(branchingPart[trip[0]]);
branchingPart[3]-> colourConnect(branchingPart[trip[1]]);
}
else {
branchingPart[trip[1]]->incomingColour(branchingPart[trip[0]]);
}
}
// 3 -> 3 8
else if (trip.size()==2 && oct.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
// 8 emit incoming partner
if(real->emitter()==oct[0]&&real->spectator()==0) {
branchingPart[ 3 ]->incomingColour(branchingPart[trip[0]]);
branchingPart[ 3 ]-> colourConnect(branchingPart[oct[0] ]);
branchingPart[oct[0]]-> colourConnect(branchingPart[trip[1]]);
}
// 8 emit final spectator or vice veras
else {
branchingPart[oct[0]]->incomingColour(branchingPart[trip[0]]);
branchingPart[oct[0]]-> colourConnect(branchingPart[ 3 ]);
branchingPart[ 3 ]-> colourConnect(branchingPart[trip[1]]);
}
}
else {
branchingPart[oct[0]]->incomingColour(branchingPart[trip[0]]);
branchingPart[oct[0]]-> colourConnect(branchingPart[trip[1]]);
}
}
// 3 -> 3bar 3bar
else if(trip.size() ==1 && atrip.size()==2) {
if(real->interaction()==ShowerInteraction::QCD) {
if(real->emitter()==atrip[0]) {
branchingPart[3]->colourConnect(branchingPart[atrip[0]],true);
tColinePtr col[3] = {ColourLine::create(branchingPart[ trip[0]],false),
ColourLine::create(branchingPart[ 3],true ),
ColourLine::create(branchingPart[atrip[1]],true)};
col[0]->setSinkNeighbours(col[1],col[2]);
}
else {
branchingPart[3]->colourConnect(branchingPart[atrip[1]],true);
tColinePtr col[3] = {ColourLine::create(branchingPart[ trip[0]],false),
ColourLine::create(branchingPart[atrip[0]],true ),
ColourLine::create(branchingPart[ 3],true)};
col[0]->setSinkNeighbours(col[1],col[2]);
}
}
else {
tColinePtr col[3] = {ColourLine::create(branchingPart[ trip[0]],false),
ColourLine::create(branchingPart[atrip[0]],true ),
ColourLine::create(branchingPart[atrip[1]],true)};
col[0]->setSinkNeighbours(col[1],col[2]);
}
}
else
assert(false);
}
// decaying colour anti-triplet
else if (branchingPart[0]->dataPtr()->iColour()==PDT::Colour3bar) {
// 3bar -> 3bar 0
if (atrip.size()==2 && sing.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
branchingPart[3]->incomingColour(branchingPart[atrip[0]],true);
branchingPart[3]-> colourConnect(branchingPart[atrip[1]],true);
}
else {
branchingPart[atrip[1]]->incomingColour(branchingPart[atrip[0]],true);
}
}
// 3 -> 3 8
else if (atrip.size()==2 && oct.size()==1){
if(real->interaction()==ShowerInteraction::QCD) {
// 8 emit incoming partner
if(real->emitter()==oct[0]&&real->spectator()==0) {
branchingPart[ 3 ]->incomingColour(branchingPart[atrip[0]],true);
branchingPart[ 3 ]-> colourConnect(branchingPart[oct[0] ],true);
branchingPart[oct[0]]-> colourConnect(branchingPart[atrip[1]],true);
}
// 8 emit final spectator or vice veras
else {
if(real->interaction()==ShowerInteraction::QCD) {
branchingPart[oct[0]]->incomingColour(branchingPart[atrip[0]],true);
branchingPart[oct[0]]-> colourConnect(branchingPart[ 3 ],true);
branchingPart[3]-> colourConnect(branchingPart[atrip[1]] ,true);
}
}
}
else {
branchingPart[oct[0]]->incomingColour(branchingPart[atrip[0]],true);
branchingPart[oct[0]]-> colourConnect(branchingPart[atrip[1]],true);
}
}
// 3bar -> 3 3
else if(atrip.size() ==1 && trip.size()==2) {
if(real->interaction()==ShowerInteraction::QCD) {
if(real->emitter()==trip[0]) {
branchingPart[3]->colourConnect(branchingPart[trip[0]],false);
tColinePtr col[3] = {ColourLine::create(branchingPart[atrip[0]],true ),
ColourLine::create(branchingPart[ 3],false),
ColourLine::create(branchingPart[ trip[1]],false)};
col[0]->setSourceNeighbours(col[1],col[2]);
}
else {
branchingPart[3]->colourConnect(branchingPart[trip[1]],false);
tColinePtr col[3] = {ColourLine::create(branchingPart[atrip[0]],true ),
ColourLine::create(branchingPart[ trip[0]],false),
ColourLine::create(branchingPart[ 3],false)};
col[0]->setSourceNeighbours(col[1],col[2]);
}
}
else {
tColinePtr col[3] = {ColourLine::create(branchingPart[atrip[0]],true ),
ColourLine::create(branchingPart[ trip[0]],false),
ColourLine::create(branchingPart[ trip[1]],false)};
col[0]->setSourceNeighbours(col[1],col[2]);
}
}
else
assert(false);
}
// decaying colour octet
else if(branchingPart[0]->dataPtr()->iColour()==PDT::Colour8 ) {
// 8 -> 3 3bar
if (trip.size()==1 && atrip.size()==1) {
if(real->interaction()==ShowerInteraction::QCD) {
// 3 emits
if(trip[0]==real->emitter()) {
branchingPart[3] ->incomingColour(branchingPart[oct[0]] );
branchingPart[3] -> colourConnect(branchingPart[trip[0]]);
branchingPart[atrip[0]]->incomingColour(branchingPart[oct[0]],true);
}
// 3bar emits
else {
branchingPart[3] ->incomingColour(branchingPart[oct[0]] ,true);
branchingPart[3] -> colourConnect(branchingPart[atrip[0]],true);
branchingPart[trip[0]]->incomingColour(branchingPart[oct[0]] );
}
}
else {
branchingPart[trip[0]]->incomingColour(branchingPart[oct[0]] );
branchingPart[atrip[0]]->incomingColour(branchingPart[oct[0]],true);
}
}
// 8 -> 8 0
else if (sing.size()==1 && oct.size()==2) {
if(real->interaction()==ShowerInteraction::QCD) {
bool col = UseRandom::rndbool();
branchingPart[ 3 ]->colourConnect (branchingPart[oct[1]], col);
branchingPart[ 3 ]->incomingColour(branchingPart[oct[0]], col);
branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]],!col);
}
else {
branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]]);
branchingPart[oct[1]]->incomingColour(branchingPart[oct[0]],true);
}
}
else
assert(false);
}
// sextet
else if(branchingPart[0]->dataPtr()->iColour() == PDT::Colour6) {
if(trip.size()==2) {
if(real->interaction()==ShowerInteraction::QCD) {
Ptr<MultiColour>::pointer parentColour =
dynamic_ptr_cast<Ptr<MultiColour>::pointer>
(branchingPart[0]->colourInfo());
if(trip[0]==real->emitter()) {
ColinePtr cline = new_ptr(ColourLine());
parentColour->colourLine(cline);
cline->addColoured(branchingPart[3]);
branchingPart[3] -> colourConnect(branchingPart[trip[0]]);
cline = new_ptr(ColourLine());
parentColour->colourLine(cline);
cline->addColoured(branchingPart[trip[1]]);
}
else {
ColinePtr cline = new_ptr(ColourLine());
parentColour->colourLine(cline);
cline->addColoured(branchingPart[3]);
branchingPart[3] -> colourConnect(branchingPart[trip[1]]);
cline = new_ptr(ColourLine());
parentColour->colourLine(cline);
cline->addColoured(branchingPart[trip[0]]);
}
}
else {
Ptr<MultiColour>::pointer parentColour =
dynamic_ptr_cast<Ptr<MultiColour>::pointer>
(branchingPart[0]->colourInfo());
for(unsigned int ix=0;ix<2;++ix) {
ColinePtr cline = new_ptr(ColourLine());
parentColour->colourLine(cline);
cline->addColoured(branchingPart[trip[ix]]);
}
}
}
else
assert(false);
}
// antisextet
else if(branchingPart[0]->dataPtr()->iColour() == PDT::Colour6bar) {
if(atrip.size()==2) {
if(real->interaction()==ShowerInteraction::QCD) {
Ptr<MultiColour>::pointer parentColour =
dynamic_ptr_cast<Ptr<MultiColour>::pointer>
(branchingPart[0]->colourInfo());
if(atrip[0]==real->emitter()) {
ColinePtr cline = new_ptr(ColourLine());
parentColour->antiColourLine(cline);
cline->addAntiColoured(branchingPart[3]);
branchingPart[3]->antiColourConnect(branchingPart[atrip[0]]);
cline = new_ptr(ColourLine());
parentColour->antiColourLine(cline);
cline->addAntiColoured(branchingPart[atrip[1]]);
}
else {
ColinePtr cline = new_ptr(ColourLine());
parentColour->antiColourLine(cline);
cline->addAntiColoured(branchingPart[3]);
branchingPart[3]->antiColourConnect(branchingPart[atrip[1]]);
cline = new_ptr(ColourLine());
parentColour->antiColourLine(cline);
cline->addAntiColoured(branchingPart[trip[0]]);
}
}
else {
Ptr<MultiColour>::pointer parentColour =
dynamic_ptr_cast<Ptr<MultiColour>::pointer>
(branchingPart[0]->colourInfo());
for(unsigned int ix=0;ix<2;++ix) {
ColinePtr cline = new_ptr(ColourLine());
parentColour->antiColourLine(cline);
cline->addColoured(branchingPart[atrip[ix]],true);
}
}
}
else
assert(false);
}
else
assert(false);
}
PerturbativeDecayer::phaseSpaceRegion
PerturbativeDecayer::inInitialFinalDeadZone(double xg, double xa,
double a, double c) const {
double lam = sqrt(1.+a*a+c*c-2.*a-2.*c-2.*a*c);
double kappab = 1.+0.5*(1.-a+c+lam);
double kappac = kappab-1.+c;
double kappa(0.);
// check whether or not in the region for emission from c
double r = 0.5;
if(c!=0.) r += 0.5*c/(1.+a-xa);
double pa = sqrt(sqr(xa)-4.*a);
double z = ((2.-xa)*(1.-r)+r*pa-xg)/pa;
if(z<1. && z>0.) {
kappa = (1.+a-c-xa)/(z*(1.-z));
if(kappa<kappac)
return emissionFromC;
}
// check in region for emission from b (T1)
double cq = sqr(1.+a-c)-4*a;
double bq = -2.*kappab*(1.-a-c);
double aq = sqr(kappab)-4.*a*(kappab-1);
double dis = sqr(bq)-4.*aq*cq;
z=1.-(-bq-sqrt(dis))/2./aq;
double w = 1.-(1.-z)*(kappab-1.);
double xgmax = (1.-z)*kappab;
// possibly in T1 region
if(xg<xgmax) {
z = 1.-xg/kappab;
kappa=kappab;
}
// possibly in T2 region
else {
aq = 4.*a;
bq = -4.*a*(2.-xg);
cq = sqr(1.+a-c-xg);
dis = sqr(bq)-4.*aq*cq;
z = (-bq-sqrt(dis))/2./aq;
kappa = xg/(1.-z);
}
// compute limit on xa
double u = 1.+a-c-(1.-z)*kappa;
w = 1.-(1.-z)*(kappa-1.);
double v = sqr(u)-4.*z*a*w;
if(v<0. && v>-1e-10) v= 0.;
v = sqrt(v);
if(xa<0.5*((u+v)/w+(u-v)/z)) {
if(xg<xgmax)
return emissionFromA1;
else if(useMEforT2_)
return deadZone;
else
return emissionFromA2;
}
else
return deadZone;
}
PerturbativeDecayer::phaseSpaceRegion
PerturbativeDecayer::inFinalFinalDeadZone(double xb, double xc,
double b, double c) const {
// basic kinematics
double lam = sqrt(1.+b*b+c*c-2.*b-2.*c-2.*b*c);
// check whether or not in the region for emission from b
double r = 0.5;
if(b!=0.) r+=0.5*b/(1.+c-xc);
double pc = sqrt(sqr(xc)-4.*c);
double z = -((2.-xc)*r-r*pc-xb)/pc;
if(z<1. and z>0.) {
if((1.-b+c-xc)/(z*(1.-z))<0.5*(1.+b-c+lam)) return emissionFromB;
}
// check whether or not in the region for emission from c
r = 0.5;
if(c!=0.) r+=0.5*c/(1.+b-xb);
double pb = sqrt(sqr(xb)-4.*b);
z = -((2.-xb)*r-r*pb-xc)/pb;
if(z<1. and z>0.) {
if((1.-c+b-xb)/(z*(1.-z))<0.5*(1.-b+c+lam)) return emissionFromC;
}
return deadZone;
}
bool PerturbativeDecayer::inTotalDeadZone(double xg, double xs,
const vector<DipoleType> & dipoles,
int i) {
double xb,xc,b,c;
if(dipoles[i].type==FFa || dipoles[i].type == IFa || dipoles[i].type == IFba) {
xc = xs;
xb = 2.-xg-xs;
b = e2_;
c = s2_;
}
else {
xb = xs;
xc = 2.-xg-xs;
b = s2_;
c = e2_;
}
for(unsigned int ix=0;ix<dipoles.size();++ix) {
if(dipoles[ix].interaction!=dipoles[i].interaction)
continue;
// should also remove negative QED dipoles but shouldn't be an issue unless we
// support QED ME corrections
switch (dipoles[ix].type) {
case FFa :
if(inFinalFinalDeadZone(xb,xc,b,c)!=deadZone) return false;
break;
case FFc :
if(inFinalFinalDeadZone(xc,xb,c,b)!=deadZone) return false;
break;
case IFa : case IFba:
if(inInitialFinalDeadZone(xg,xc,c,b)!=deadZone) return false;
break;
case IFc : case IFbc:
if(inInitialFinalDeadZone(xg,xb,b,c)!=deadZone) return false;
break;
case FFg:
break;
}
}
return true;
}
diff --git a/Hadronization/ClusterHadronizationHandler.cc b/Hadronization/ClusterHadronizationHandler.cc
--- a/Hadronization/ClusterHadronizationHandler.cc
+++ b/Hadronization/ClusterHadronizationHandler.cc
@@ -1,303 +1,307 @@
// -*- C++ -*-
//
// ClusterHadronizationHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ClusterHadronizationHandler class.
//
#include "ClusterHadronizationHandler.h"
#include <ThePEG/Interface/ClassDocumentation.h>
#include <ThePEG/Persistency/PersistentOStream.h>
#include <ThePEG/Persistency/PersistentIStream.h>
#include <ThePEG/Interface/Switch.h>
#include <ThePEG/Interface/Parameter.h>
#include <ThePEG/Interface/Reference.h>
#include <ThePEG/Handlers/EventHandler.h>
#include <ThePEG/Handlers/Hint.h>
#include <ThePEG/PDT/ParticleData.h>
#include <ThePEG/EventRecord/Particle.h>
#include <ThePEG/EventRecord/Step.h>
#include <ThePEG/PDT/PDT.h>
#include <ThePEG/PDT/EnumParticles.h>
#include <ThePEG/Utilities/Throw.h>
#include "Herwig/Utilities/EnumParticles.h"
#include "CluHadConfig.h"
#include "Cluster.h"
#include <ThePEG/Utilities/DescribeClass.h>
using namespace Herwig;
ClusterHadronizationHandler * ClusterHadronizationHandler::currentHandler_ = 0;
DescribeClass<ClusterHadronizationHandler,HadronizationHandler>
describeClusterHadronizationHandler("Herwig::ClusterHadronizationHandler","");
IBPtr ClusterHadronizationHandler::clone() const {
return new_ptr(*this);
}
IBPtr ClusterHadronizationHandler::fullclone() const {
return new_ptr(*this);
}
void ClusterHadronizationHandler::persistentOutput(PersistentOStream & os)
const {
os << _partonSplitter << _clusterFinder << _colourReconnector
<< _clusterFissioner << _lightClusterDecayer << _clusterDecayer
<< ounit(_minVirtuality2,GeV2) << ounit(_maxDisplacement,mm)
<< _underlyingEventHandler << _reduceToTwoComponents;
}
void ClusterHadronizationHandler::persistentInput(PersistentIStream & is, int) {
is >> _partonSplitter >> _clusterFinder >> _colourReconnector
>> _clusterFissioner >> _lightClusterDecayer >> _clusterDecayer
>> iunit(_minVirtuality2,GeV2) >> iunit(_maxDisplacement,mm)
>> _underlyingEventHandler >> _reduceToTwoComponents;
}
void ClusterHadronizationHandler::Init() {
static ClassDocumentation<ClusterHadronizationHandler> documentation
("This is the main handler class for the Cluster Hadronization",
"The hadronization was performed using the cluster model of \\cite{Webber:1983if}.",
"%\\cite{Webber:1983if}\n"
"\\bibitem{Webber:1983if}\n"
" B.~R.~Webber,\n"
" ``A QCD Model For Jet Fragmentation Including Soft Gluon Interference,''\n"
" Nucl.\\ Phys.\\ B {\\bf 238}, 492 (1984).\n"
" %%CITATION = NUPHA,B238,492;%%\n"
// main manual
);
static Reference<ClusterHadronizationHandler,PartonSplitter>
interfacePartonSplitter("PartonSplitter",
"A reference to the PartonSplitter object",
&Herwig::ClusterHadronizationHandler::_partonSplitter,
false, false, true, false);
static Reference<ClusterHadronizationHandler,ClusterFinder>
interfaceClusterFinder("ClusterFinder",
"A reference to the ClusterFinder object",
&Herwig::ClusterHadronizationHandler::_clusterFinder,
false, false, true, false);
static Reference<ClusterHadronizationHandler,ColourReconnector>
interfaceColourReconnector("ColourReconnector",
"A reference to the ColourReconnector object",
&Herwig::ClusterHadronizationHandler::_colourReconnector,
false, false, true, false);
static Reference<ClusterHadronizationHandler,ClusterFissioner>
interfaceClusterFissioner("ClusterFissioner",
"A reference to the ClusterFissioner object",
&Herwig::ClusterHadronizationHandler::_clusterFissioner,
false, false, true, false);
static Reference<ClusterHadronizationHandler,LightClusterDecayer>
interfaceLightClusterDecayer("LightClusterDecayer",
"A reference to the LightClusterDecayer object",
&Herwig::ClusterHadronizationHandler::_lightClusterDecayer,
false, false, true, false);
static Reference<ClusterHadronizationHandler,ClusterDecayer>
interfaceClusterDecayer("ClusterDecayer",
"A reference to the ClusterDecayer object",
&Herwig::ClusterHadronizationHandler::_clusterDecayer,
false, false, true, false);
static Parameter<ClusterHadronizationHandler,Energy2> interfaceMinVirtuality2
("MinVirtuality2",
"Minimum virtuality^2 of partons to use in calculating distances (unit [GeV2]).",
&ClusterHadronizationHandler::_minVirtuality2, GeV2, 0.1*GeV2, ZERO, 10.0*GeV2,false,false,false);
static Parameter<ClusterHadronizationHandler,Length> interfaceMaxDisplacement
("MaxDisplacement",
"Maximum displacement that is allowed for a particle (unit [millimeter]).",
&ClusterHadronizationHandler::_maxDisplacement, mm, 1.0e-10*mm,
0.0*mm, 1.0e-9*mm,false,false,false);
static Reference<ClusterHadronizationHandler,StepHandler> interfaceUnderlyingEventHandler
("UnderlyingEventHandler",
"Pointer to the handler for the Underlying Event. "
"Set to NULL to disable.",
&ClusterHadronizationHandler::_underlyingEventHandler, false, false, true, true, false);
static Switch<ClusterHadronizationHandler,bool> interfaceReduceToTwoComponents
("ReduceToTwoComponents",
"Whether or not to reduce three component baryon-number violating clusters to two components before cluster splitting or leave"
" this till after the cluster splitting",
&ClusterHadronizationHandler::_reduceToTwoComponents, true, false, false);
static SwitchOption interfaceReduceToTwoComponentsYes
(interfaceReduceToTwoComponents,
"BeforeSplitting",
"Reduce to two components",
true);
static SwitchOption interfaceReduceToTwoComponentsNo
(interfaceReduceToTwoComponents,
"AfterSplitting",
"Treat as three components",
false);
}
namespace {
void extractChildren(tPPtr p, set<PPtr> & all) {
if (p->children().empty()) return;
for (PVector::const_iterator child = p->children().begin();
child != p->children().end(); ++child) {
all.insert(*child);
extractChildren(*child, all);
}
}
}
void ClusterHadronizationHandler::
handle(EventHandler & ch, const tPVector & tagged,
const Hint &) {
useMe();
currentHandler_ = this;
PVector currentlist(tagged.begin(),tagged.end());
// set the scale for coloured particles to just above the gluon mass squared
// if less than this so they are classed as perturbative
Energy2 Q02 = 1.01*sqr(getParticleData(ParticleID::g)->constituentMass());
for(unsigned int ix=0;ix<currentlist.size();++ix) {
if(currentlist[ix]->scale()<Q02) currentlist[ix]->scale(Q02);
}
// split the gluons
_partonSplitter->split(currentlist);
// form the clusters
ClusterVector clusters =
_clusterFinder->formClusters(currentlist);
// reduce BV clusters to two components now if needed
if(_reduceToTwoComponents)
_clusterFinder->reduceToTwoComponents(clusters);
// perform colour reconnection if needed and then
// decay the clusters into one hadron
bool lightOK = false;
short tried = 0;
const ClusterVector savedclusters = clusters;
tPVector finalHadrons; // only needed for partonic decayer
while (!lightOK && tried++ < 10) {
// no colour reconnection with baryon-number-violating (BV) clusters
ClusterVector CRclusters, BVclusters;
CRclusters.reserve( clusters.size() );
BVclusters.reserve( clusters.size() );
for (size_t ic = 0; ic < clusters.size(); ++ic) {
ClusterPtr cl = clusters.at(ic);
bool hasClusterParent = false;
for (unsigned int ix=0; ix < cl->parents().size(); ++ix) {
if (cl->parents()[ix]->id() == ParticleID::Cluster) {
hasClusterParent = true;
break;
}
}
if (cl->numComponents() > 2 || hasClusterParent) BVclusters.push_back(cl);
else CRclusters.push_back(cl);
}
// colour reconnection
_colourReconnector->rearrange(CRclusters);
// tag new clusters as children of the partons to hadronize
_setChildren(CRclusters);
+ // forms diquarks
+ _clusterFinder->reduceToTwoComponents(CRclusters);
+
// recombine vectors of (possibly) reconnected and BV clusters
clusters.clear();
clusters.insert( clusters.end(), CRclusters.begin(), CRclusters.end() );
clusters.insert( clusters.end(), BVclusters.begin(), BVclusters.end() );
// fission of heavy clusters
// NB: during cluster fission, light hadrons might be produced straight away
finalHadrons = _clusterFissioner->fission(clusters,isSoftUnderlyingEventON());
// if clusters not previously reduced to two components do it now
if(!_reduceToTwoComponents)
_clusterFinder->reduceToTwoComponents(clusters);
lightOK = _lightClusterDecayer->decay(clusters,finalHadrons);
// if the decay of the light clusters was not successful, undo the cluster
// fission and decay steps and revert to the original state of the event
// record
if (!lightOK) {
clusters = savedclusters;
for_each(clusters.begin(),
clusters.end(),
mem_fun(&Particle::undecay));
}
}
if (!lightOK) {
- // currentHandler_ = 0;
throw Exception("CluHad::handle(): tried LightClusterDecayer 10 times!",
Exception::eventerror);
}
// decay the remaining clusters
_clusterDecayer->decay(clusters,finalHadrons);
// *****************************************
// *****************************************
// *****************************************
StepPtr pstep = newStep();
set<PPtr> allDecendants;
for (tPVector::const_iterator it = tagged.begin();
it != tagged.end(); ++it) {
extractChildren(*it, allDecendants);
}
for(set<PPtr>::const_iterator it = allDecendants.begin();
it != allDecendants.end(); ++it) {
// this is a workaround because the set sometimes
// re-orders parents after their children
if ((*it)->children().empty())
pstep->addDecayProduct(*it);
else {
pstep->addDecayProduct(*it);
pstep->addIntermediate(*it);
}
}
// *****************************************
// *****************************************
// *****************************************
// soft underlying event if needed
if (isSoftUnderlyingEventON()) {
assert(_underlyingEventHandler);
ch.performStep(_underlyingEventHandler,Hint::Default());
}
}
-void ClusterHadronizationHandler::_setChildren(ClusterVector clusters) const {
+// Sets parent child relationship of all clusters with two components
+// Relationships for clusters with more than two components are set elsewhere in the Colour Reconnector
+void ClusterHadronizationHandler::_setChildren(const ClusterVector & clusters) const {
// erase existing information about the partons' children
tPVector partons;
- for (ClusterVector::const_iterator cl = clusters.begin();
- cl != clusters.end(); cl++) {
- partons.push_back( (*cl)->colParticle() );
- partons.push_back( (*cl)->antiColParticle() );
+ for ( const auto & cl : clusters ) {
+ if ( cl->numComponents() > 2 ) continue;
+ partons.push_back( cl->colParticle() );
+ partons.push_back( cl->antiColParticle() );
}
+ // erase all previous information about parent child relationship
for_each(partons.begin(), partons.end(), mem_fun(&Particle::undecay));
// give new parents to the clusters: their constituents
- for (ClusterVector::iterator cl = clusters.begin();
- cl != clusters.end(); cl++) {
- (*cl)->colParticle()->addChild(*cl);
- (*cl)->antiColParticle()->addChild(*cl);
+ for ( const auto & cl : clusters ) {
+ if ( cl->numComponents() > 2 ) continue;
+ cl->colParticle()->addChild(cl);
+ cl->antiColParticle()->addChild(cl);
}
-
}
diff --git a/Hadronization/ClusterHadronizationHandler.h b/Hadronization/ClusterHadronizationHandler.h
--- a/Hadronization/ClusterHadronizationHandler.h
+++ b/Hadronization/ClusterHadronizationHandler.h
@@ -1,223 +1,209 @@
// -*- C++ -*-
//
// ClusterHadronizationHandler.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_ClusterHadronizationHandler_H
#define HERWIG_ClusterHadronizationHandler_H
#include <ThePEG/Handlers/HadronizationHandler.h>
#include "PartonSplitter.h"
#include "ClusterFinder.h"
#include "ColourReconnector.h"
#include "ClusterFissioner.h"
#include "LightClusterDecayer.h"
#include "ClusterDecayer.h"
#include "ClusterHadronizationHandler.fh"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Hadronization
* \class ClusterHadronizationHandler
* \brief Class that controls the cluster hadronization algorithm.
* \author Philip Stephens // cerr << *ch.currentEvent() << '\n';
cerr << finalHadrons.size() << '\n';
cerr << "Finished hadronizing \n";
* \author Alberto Ribon
*
* This class is the main driver of the cluster hadronization: it is
* responsible for the proper handling of all other specific collaborating
* classes PartonSplitter, ClusterFinder, ColourReconnector, ClusterFissioner,
* LightClusterDecayer, ClusterDecayer;
* and for the storing of the produced particles in the Event record.
*
* @see PartonSplitter
* @see ClusterFinder
* @see ColourReconnector
* @see ClusterFissioner
* @see LightClusterDecayer
* @see ClusterDecayer
* @see Cluster
* @see \ref ClusterHadronizationHandlerInterfaces "The interfaces"
* defined for ClusterHadronizationHandler.
*/
class ClusterHadronizationHandler: public HadronizationHandler {
public:
- /** @name Standard constructors and destructors. */
- //@{
- /**
- * The default constructor.
- */
- ClusterHadronizationHandler()
- : _minVirtuality2( 0.1*GeV2 ), _maxDisplacement( 1.0e-10*mm ),
- _reduceToTwoComponents(true)
- {}
-
- //@}
-
-public:
-
/**
* The main method which manages the all cluster hadronization.
*
* This routine directs "traffic". It determines which function is called
* and on which particles/clusters. This function also handles the
* situation of vetos on the hadronization.
*/
virtual void handle(EventHandler & ch, const tPVector & tagged,
const Hint & hint);
/**
* It returns minimum virtuality^2 of partons to use in calculating
* distances. It is used both in the Showering and Hadronization.
*/
Energy2 minVirtuality2() const
{ return _minVirtuality2; }
/**
* It returns the maximum displacement that is allowed for a particle
* (used to determine the position of a cluster with two components).
*/
Length maxDisplacement() const
{ return _maxDisplacement; }
/**
* It returns true/false according if the soft underlying model
* is switched on/off.
*/
bool isSoftUnderlyingEventON() const
{ return _underlyingEventHandler; }
/**
* pointer to "this", the current HadronizationHandler.
*/
static const ClusterHadronizationHandler * currentHandler() {
assert(currentHandler_);
return currentHandler_;
}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* Standard Init function used to initialize the interfaces.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** 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:
/**
* Private and non-existent assignment operator.
*/
- ClusterHadronizationHandler & operator=(const ClusterHadronizationHandler &);
+ ClusterHadronizationHandler & operator=(const ClusterHadronizationHandler &) = delete;
/**
* This is a pointer to a Herwig::PartonSplitter object.
*/
PartonSplitterPtr _partonSplitter;
/**
* This is a pointer to a Herwig::ClusterFinder object.
*/
ClusterFinderPtr _clusterFinder;
/**
* This is a pointer to a Herwig::ColourReconnector object.
*/
ColourReconnectorPtr _colourReconnector;
/**
* This is a pointer to a Herwig::ClusterFissioner object.
*/
ClusterFissionerPtr _clusterFissioner;
/**
* This is a pointer to a Herwig::LightClusterDecayer object.
*/
LightClusterDecayerPtr _lightClusterDecayer;
/**
* This is a pointer to a Herwig::ClusterDecayer object.
*/
ClusterDecayerPtr _clusterDecayer;
/**
* The minimum virtuality^2 of partons to use in calculating
* distances.
*/
- Energy2 _minVirtuality2;
+ Energy2 _minVirtuality2 = 0.1_GeV2;
/**
* The maximum displacement that is allowed for a particle
* (used to determine the position of a cluster with two components).
*/
- Length _maxDisplacement;
+ Length _maxDisplacement = 1.0e-10_mm;
/**
* The pointer to the Underlying Event handler.
*/
StepHdlPtr _underlyingEventHandler;
/**
* How to handle baryon-number clusters
*/
- bool _reduceToTwoComponents;
+ bool _reduceToTwoComponents = true;
/**
* Tag the constituents of the clusters as their parents
*/
- void _setChildren(ClusterVector clusters) const;
+ void _setChildren(const ClusterVector & clusters) const;
/**
* pointer to "this", the current HadronizationHandler.
*/
static ClusterHadronizationHandler * currentHandler_;
};
}
#endif /* HERWIG_ClusterHadronizationHandler_H */
diff --git a/Hadronization/ColourReconnector.cc b/Hadronization/ColourReconnector.cc
--- a/Hadronization/ColourReconnector.cc
+++ b/Hadronization/ColourReconnector.cc
@@ -1,488 +1,821 @@
// -*- C++ -*-
//
// ColourReconnector.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ColourReconnector class.
//
#include "ColourReconnector.h"
#include "Cluster.h"
-#include "Herwig/Utilities/Maths.h"
-#include <ThePEG/Interface/Switch.h>
-#include "ThePEG/Interface/Parameter.h"
+
+#include <ThePEG/Utilities/DescribeClass.h>
+#include <ThePEG/Repository/UseRandom.h>
+#include <ThePEG/PDT/StandardMatchers.h>
#include <ThePEG/Persistency/PersistentOStream.h>
#include <ThePEG/Persistency/PersistentIStream.h>
-#include <ThePEG/Repository/UseRandom.h>
-#include <algorithm>
-#include <ThePEG/Utilities/DescribeClass.h>
-#include <ThePEG/Repository/EventGenerator.h>
+#include <ThePEG/Interface/Switch.h>
+#include <ThePEG/Interface/Parameter.h>
+
+#include "Herwig/Utilities/Maths.h"
using namespace Herwig;
-typedef ClusterVector::iterator CluVecIt;
+using CluVecIt = ColourReconnector::CluVecIt;
+using Constants::pi;
+using Constants::twopi;
+
DescribeClass<ColourReconnector,Interfaced>
describeColourReconnector("Herwig::ColourReconnector","");
IBPtr ColourReconnector::clone() const {
return new_ptr(*this);
}
IBPtr ColourReconnector::fullclone() const {
return new_ptr(*this);
}
void ColourReconnector::rearrange(ClusterVector & clusters) {
if (_clreco == 0) return;
// need at least two clusters
if (clusters.size() < 2) return;
// do the colour reconnection
switch (_algorithm) {
- case 0: _doRecoPlain(clusters);
- break;
- case 1: _doRecoStatistical(clusters);
- break;
+ case 0: _doRecoPlain(clusters); break;
+ case 1: _doRecoStatistical(clusters); break;
+ case 2: _doRecoBaryonic(clusters); break;
}
-
- return;
}
Energy2 ColourReconnector::_clusterMassSum(const PVector & q,
const PVector & aq) const {
const size_t nclusters = q.size();
assert (aq.size() == nclusters);
Energy2 sum = ZERO;
for (size_t i = 0; i < nclusters; i++)
sum += ( q[i]->momentum() + aq[i]->momentum() ).m2();
return sum;
}
bool ColourReconnector::_containsColour8(const ClusterVector & cv,
const vector<size_t> & P) const {
assert (P.size() == cv.size());
for (size_t i = 0; i < cv.size(); i++) {
tcPPtr p = cv[i]->colParticle();
tcPPtr q = cv[P[i]]->antiColParticle();
- if (isColour8(p, q)) return true;
+ if (_isColour8(p, q)) return true;
}
return false;
}
void ColourReconnector::_doRecoStatistical(ClusterVector & cv) const {
const size_t nclusters = cv.size();
// initially, enumerate (anti)quarks as given in the cluster vector
ParticleVector q, aq;
for (size_t i = 0; i < nclusters; i++) {
q.push_back( cv[i]->colParticle() );
aq.push_back( cv[i]->antiColParticle() );
}
// annealing scheme
Energy2 t, delta;
Energy2 lambda = _clusterMassSum(q,aq);
const unsigned _ntries = _triesPerStepFactor * nclusters;
// find appropriate starting temperature by measuring the largest lambda
// difference in some dry-run random rearrangements
{
vector<Energy2> typical;
for (int i = 0; i < 10; i++) {
const pair <int,int> toswap = _shuffle(q,aq,5);
ParticleVector newaq = aq;
swap (newaq[toswap.first], newaq[toswap.second]);
Energy2 newlambda = _clusterMassSum(q,newaq);
typical.push_back( abs(newlambda - lambda) );
}
t = _initTemp * Math::median(typical);
}
// anneal in up to _annealingSteps temperature steps
for (unsigned step = 0; step < _annealingSteps; step++) {
// For this temperature step, try to reconnect _ntries times. Stop the
// algorithm if no successful reconnection happens.
unsigned nSuccess = 0;
for (unsigned it = 0; it < _ntries; it++) {
// make a random rearrangement
const unsigned maxtries = 10;
const pair <int,int> toswap = _shuffle(q,aq,maxtries);
const int i = toswap.first;
const int j = toswap.second;
// stop here if we cannot find any allowed reconfiguration
if (i == -1) break;
// create a new antiquark vector with the two partons swapped
ParticleVector newaq = aq;
swap (newaq[i], newaq[j]);
// Check if lambda would decrease. If yes, accept the reconnection. If no,
// accept it only with a probability given by the current Boltzmann
// factor. In the latter case we set p = 0 if the temperature is close to
// 0, to avoid division by 0.
Energy2 newlambda = _clusterMassSum(q,newaq);
delta = newlambda - lambda;
double prob = 1.0;
if (delta > ZERO) prob = ( abs(t) < 1e-8*MeV2 ) ? 0.0 : exp(-delta/t);
if (UseRandom::rnd() < prob) {
lambda = newlambda;
swap (newaq, aq);
nSuccess++;
}
}
if (nSuccess == 0) break;
// reduce temperature
t *= _annealingFactor;
}
// construct the new cluster vector
ClusterVector newclusters;
for (size_t i = 0; i < nclusters; i++) {
ClusterPtr cl = new_ptr( Cluster( q[i], aq[i] ) );
newclusters.push_back(cl);
}
swap(newclusters,cv);
return;
}
void ColourReconnector::_doRecoPlain(ClusterVector & cv) const {
ClusterVector newcv = cv;
// try to avoid systematic errors by randomising the reconnection order
long (*p_irnd)(long) = UseRandom::irnd;
random_shuffle( newcv.begin(), newcv.end(), p_irnd );
// iterate over all clusters
for (CluVecIt cit = newcv.begin(); cit != newcv.end(); cit++) {
-
// find the cluster which, if reconnected with *cit, would result in the
// smallest sum of cluster masses
// NB this method returns *cit if no reconnection partner can be found
CluVecIt candidate = _findRecoPartner(cit, newcv);
// skip this cluster if no possible reshuffling partner can be found
if (candidate == cit) continue;
// accept the reconnection with probability _preco.
if (UseRandom::rnd() < _preco) {
pair <ClusterPtr,ClusterPtr> reconnected = _reconnect(*cit, *candidate);
// Replace the clusters in the ClusterVector. The order of the
// colour-triplet partons in the cluster vector is retained here.
// replace *cit by reconnected.first
*cit = reconnected.first;
// replace candidate by reconnected.second
*candidate = reconnected.second;
}
}
swap(cv,newcv);
return;
}
+namespace {
+ inline bool hasDiquark(CluVecIt cit) {
+ for(int i = 0; i<(*cit)->numComponents(); i++) {
+ if (DiquarkMatcher::Check(*((*cit)->particle(i)->dataPtr())))
+ return true;
+ }
+ return false;
+ }
+}
+
+
+// Implementation of the baryonic reconnection algorithm
+void ColourReconnector::_doRecoBaryonic(ClusterVector & cv) const {
+
+ ClusterVector newcv = cv;
+
+ ClusterVector deleted; deleted.reserve(cv.size());
+
+ // try to avoid systematic errors by randomising the reconnection order
+ long (*p_irnd)(long) = UseRandom::irnd;
+ random_shuffle( newcv.begin(), newcv.end(), p_irnd );
+
+ // iterate over all clusters
+ for (CluVecIt cit = newcv.begin(); cit != newcv.end(); ++cit) {
+ //avoid clusters already containing diuarks
+ if (hasDiquark(cit)) continue;
+
+ //skip the cluster to be deleted later 3->2 cluster
+ if (find(deleted.begin(), deleted.end(), *cit) != deleted.end())
+ continue;
+
+ // Skip all found baryonic clusters, this biases the algorithm but implementing
+ // something like re-reconnection is ongoing work
+ if ((*cit)->numComponents()==3) continue;
+
+ // Find a candidate suitable for reconnection
+ CluVecIt baryonic1, baryonic2;
+ bool isBaryonicCandidate = false;
+ CluVecIt candidate = _findPartnerBaryonic(cit, newcv,
+ isBaryonicCandidate,
+ deleted,
+ baryonic1, baryonic2);
+
+ // skip this cluster if no possible reconnection partner can be found
+ if ( !isBaryonicCandidate && candidate==cit )
+ continue;
+
+ if ( isBaryonicCandidate
+ && UseRandom::rnd() < _precoBaryonic ) {
+ deleted.push_back(*baryonic2);
+
+ // Function that does the reconnection from 3 -> 2 clusters
+ ClusterPtr b1, b2;
+ _makeBaryonicClusters(*cit,*baryonic1,*baryonic2, b1, b2);
+
+ *cit = b1;
+ *baryonic1 = b2;
+
+ // Baryonic2 is easily skipped in the next loop
+ }
+
+ // Normal 2->2 Colour reconnection
+ if ( !isBaryonicCandidate
+ && UseRandom::rnd() < _preco ) {
+ auto reconnected = _reconnectBaryonic(*cit, *candidate);
+ *cit = reconnected.first;
+ *candidate = reconnected.second;
+ }
+ }
+
+ // create a new vector of clusters except for the ones which are "deleted" during
+ // baryonic reconnection
+ ClusterVector clustervector;
+ for ( const auto & cluster : newcv )
+ if ( find(deleted.begin(),
+ deleted.end(), cluster) == deleted.end() )
+ clustervector.push_back(cluster);
+
+ swap(cv,clustervector);
+}
+
+
+
+namespace {
+
+double calculateRapidityRF(const Lorentz5Momentum & q1,
+ const Lorentz5Momentum & p2) {
+ //calculate rapidity wrt the direction of q1
+ //angle between the particles in the RF of cluster of q1
+
+ // calculate the z component of p2 w.r.t the direction of q1
+ const Energy pz = p2.vect() * q1.vect().unit();
+ if ( pz == ZERO ) return 0.;
+
+ // Transverse momentum of p2 w.r.t the direction of q1
+ const Energy pt = sqrt(p2.vect().mag2() - sqr(pz));
+
+ // Transverse mass pf p2 w.r.t to the direction of q1
+ const Energy mtrans = sqrt(p2.mass()*p2.mass() + (pt*pt));
+
+ // Correct formula
+ const double y2 = log((p2.t() + abs(pz))/mtrans);
+
+ return ( pz < ZERO ) ? -y2 : y2;
+}
+
+}
+
+
+CluVecIt ColourReconnector::_findPartnerBaryonic(
+ CluVecIt cl, ClusterVector & cv,
+ bool & baryonicCand,
+ const ClusterVector& deleted,
+ CluVecIt &baryonic1,
+ CluVecIt &baryonic2 ) const {
+
+ using Constants::pi;
+ using Constants::twopi;
+
+ // Returns a candidate for possible reconnection
+ CluVecIt candidate = cl;
+
+ bool bcand = false;
+
+ double maxrap = 0.0;
+ double minrap = 0.0;
+ double maxrapNormal = 0.0;
+ double minrapNormal = 0.0;
+ double maxsumnormal = 0.0;
+
+ double maxsum = 0.0;
+ double secondsum = 0.0;
+
+
+ // boost into RF of cl
+ Lorentz5Momentum cl1 = (*cl)->momentum();
+ const Boost boostv(-cl1.boostVector());
+ cl1.boost(boostv);
+ // boost constituents of cl into RF of cl
+ Lorentz5Momentum p1col = (*cl)->colParticle()->momentum();
+ Lorentz5Momentum p1anticol = (*cl)->antiColParticle()->momentum();
+ p1col.boost(boostv);
+ p1anticol.boost(boostv);
+
+
+ for (CluVecIt cit=cv.begin(); cit != cv.end(); ++cit) {
+ //avoid looping over clusters containing diquarks
+ if ( hasDiquark(cit) ) continue;
+ if ( (*cit)->numComponents()==3 ) continue;
+ if ( cit==cl ) continue;
+
+ //skip the cluster to be deleted later 3->2 cluster
+ if ( find(deleted.begin(), deleted.end(), *cit) != deleted.end() )
+ continue;
+
+ if ( (*cl)->isBeamCluster() && (*cit)->isBeamCluster() )
+ continue;
+
+ // stop it putting far apart clusters together
+ if ( ( (**cl).vertex()-(**cit).vertex() ).m() >_maxDistance )
+ continue;
+
+ const bool Colour8 =
+ _isColour8( (*cl)->colParticle(), (*cit)->antiColParticle() )
+ ||
+ _isColour8( (*cit)->colParticle(), (*cl)->antiColParticle() ) ;
+ if ( Colour8 ) continue;
+
+
+ // boost constituents of cit into RF of cl
+ Lorentz5Momentum p2col = (*cit)->colParticle()->momentum();
+ Lorentz5Momentum p2anticol = (*cit)->antiColParticle()->momentum();
+
+ p2col.boost(boostv);
+ p2anticol.boost(boostv);
+
+ // calculate the rapidity of the other constituents of the clusters
+ // w.r.t axis of p1anticol.vect.unit
+ const double rapq = calculateRapidityRF(p1anticol,p2col);
+ const double rapqbar = calculateRapidityRF(p1anticol,p2anticol);
+
+ // configuration for normal CR
+ if ( rapq > 0.0 && rapqbar < 0.0
+ && rapq > maxrap
+ && rapqbar < minrap ) {
+ maxrap = rapq;
+ minrap = rapqbar;
+ //sum of rapidities of quarks
+ const double normalsum = abs(rapq) + abs(rapqbar);
+ if ( normalsum > maxsumnormal ) {
+ maxsumnormal = normalsum;
+ maxrapNormal = rapq;
+ minrapNormal = rapqbar;
+ bcand = false;
+ candidate = cit;
+ }
+ }
+
+ if ( rapq < 0.0 && rapqbar >0.0
+ && rapqbar > maxrapNormal
+ && rapq < minrapNormal ) {
+ maxrap = rapqbar;
+ minrap = rapq;
+ const double sumrap = abs(rapqbar) + abs(rapq);
+ // first candidate gets here. If second baryonic candidate has higher Ysum than the first
+ // one, the second candidate becomes the first one and the first the second.
+ if (sumrap > maxsum) {
+ if(maxsum != 0){
+ baryonic2 = baryonic1;
+ baryonic1 = cit;
+ bcand = true;
+ } else {
+ baryonic1 = cit;
+ }
+ maxsum = sumrap;
+ } else {
+ if (sumrap > secondsum && sumrap != maxsum) {
+ secondsum = sumrap;
+ bcand = true;
+ baryonic2 = cit;
+ }
+ }
+ }
+
+ }
+
+ if(bcand == true){
+ baryonicCand = true;
+ }
+
+ return candidate;
+}
+
CluVecIt ColourReconnector::_findRecoPartner(CluVecIt cl,
ClusterVector & cv) const {
CluVecIt candidate = cl;
Energy minMass = 1*TeV;
for (CluVecIt cit=cv.begin(); cit != cv.end(); ++cit) {
// don't even look at original cluster
if(cit==cl) continue;
// don't allow colour octet clusters
- if ( isColour8( (*cl)->colParticle(),
- (*cit)->antiColParticle() ) ||
- isColour8( (*cit)->colParticle(),
- (*cl)->antiColParticle() ) ) {
+ if ( _isColour8( (*cl)->colParticle(),
+ (*cit)->antiColParticle() ) ||
+ _isColour8( (*cit)->colParticle(),
+ (*cl)->antiColParticle() ) ) {
continue;
}
// stop it putting beam remnants together
if((*cl)->isBeamCluster() && (*cit)->isBeamCluster()) continue;
// stop it putting far apart clusters together
if(((**cl).vertex()-(**cit).vertex()).m()>_maxDistance) continue;
// momenta of the old clusters
Lorentz5Momentum p1 = (*cl)->colParticle()->momentum() +
(*cl)->antiColParticle()->momentum();
Lorentz5Momentum p2 = (*cit)->colParticle()->momentum() +
(*cit)->antiColParticle()->momentum();
// momenta of the new clusters
Lorentz5Momentum p3 = (*cl)->colParticle()->momentum() +
(*cit)->antiColParticle()->momentum();
Lorentz5Momentum p4 = (*cit)->colParticle()->momentum() +
(*cl)->antiColParticle()->momentum();
Energy oldMass = abs( p1.m() ) + abs( p2.m() );
Energy newMass = abs( p3.m() ) + abs( p4.m() );
+
if ( newMass < oldMass && newMass < minMass ) {
minMass = newMass;
candidate = cit;
}
}
+
return candidate;
}
+// forms two baryonic clusters from three clusters
+void ColourReconnector::_makeBaryonicClusters(
+ ClusterPtr &c1, ClusterPtr &c2,
+ ClusterPtr &c3,
+ ClusterPtr &newcluster1,
+ ClusterPtr &newcluster2) const{
+
+ //make sure they all have 2 components
+ assert(c1->numComponents()==2);
+ assert(c2->numComponents()==2);
+ assert(c3->numComponents()==2);
+ //abandon childs
+ c1->colParticle()->abandonChild(c1);
+ c1->antiColParticle()->abandonChild(c1);
+ c2->colParticle()->abandonChild(c2);
+ c2->antiColParticle()->abandonChild(c2);
+ c3->colParticle()->abandonChild(c3);
+ c3->antiColParticle()->abandonChild(c3);
+
+ newcluster1 = new_ptr(Cluster(c1->colParticle(),c2->colParticle(), c3->colParticle()));
+ c1->colParticle()->addChild(newcluster1);
+ c2->colParticle()->addChild(newcluster1);
+ c3->colParticle()->addChild(newcluster1);
+ newcluster1->setVertex(LorentzPoint());
+ newcluster2 = new_ptr(Cluster(c1->antiColParticle(), c2->antiColParticle(),
+ c3->antiColParticle()));
+ c1->antiColParticle()->addChild(newcluster2);
+ c2->antiColParticle()->addChild(newcluster2);
+ c3->antiColParticle()->addChild(newcluster2);
+ newcluster2->setVertex(LorentzPoint());
+}
pair <ClusterPtr,ClusterPtr>
-ColourReconnector::_reconnect(ClusterPtr c1, ClusterPtr c2) const {
+ColourReconnector::_reconnect(ClusterPtr &c1, ClusterPtr &c2) const {
// choose the other possibility to form two clusters from the given
// constituents
+
assert(c1->numComponents()==2);
assert(c2->numComponents()==2);
int c1_col(-1),c1_anti(-1),c2_col(-1),c2_anti(-1);
for(unsigned int ix=0;ix<2;++ix) {
if (c1->particle(ix)->hasColour(false)) c1_col = ix;
else if(c1->particle(ix)->hasColour(true )) c1_anti = ix;
if (c2->particle(ix)->hasColour(false)) c2_col = ix;
else if(c2->particle(ix)->hasColour(true )) c2_anti = ix;
}
assert(c1_col>=0&&c2_col>=0&&c1_anti>=0&&c2_anti>=0);
ClusterPtr newCluster1
= new_ptr( Cluster( c1->colParticle(), c2->antiColParticle() ) );
newCluster1->setVertex(0.5*( c1->colParticle()->vertex() +
- c2->antiColParticle()->vertex() ));
+ c2->antiColParticle()->vertex() ));
if(c1->isBeamRemnant(c1_col )) newCluster1->setBeamRemnant(0,true);
if(c2->isBeamRemnant(c2_anti)) newCluster1->setBeamRemnant(1,true);
-
+
ClusterPtr newCluster2
= new_ptr( Cluster( c2->colParticle(), c1->antiColParticle() ) );
newCluster2->setVertex(0.5*( c2->colParticle()->vertex() +
- c1->antiColParticle()->vertex() ));
+ c1->antiColParticle()->vertex() ));
+
+ if(c2->isBeamRemnant(c2_col )) newCluster2->setBeamRemnant(0,true);
+ if(c1->isBeamRemnant(c1_anti)) newCluster2->setBeamRemnant(1,true);
+
+ return pair <ClusterPtr,ClusterPtr> (newCluster1, newCluster2);
+}
+
+
+
+
+
+pair <ClusterPtr,ClusterPtr>
+ColourReconnector::_reconnectBaryonic(ClusterPtr &c1, ClusterPtr &c2) const {
+
+ // choose the other possibility to form two clusters from the given
+ // constituents
+
+ assert(c1->numComponents()==2);
+ assert(c2->numComponents()==2);
+ int c1_col(-1),c1_anti(-1),c2_col(-1),c2_anti(-1);
+ for(unsigned int ix=0;ix<2;++ix) {
+ if (c1->particle(ix)->hasColour(false)) c1_col = ix;
+ else if(c1->particle(ix)->hasColour(true )) c1_anti = ix;
+ if (c2->particle(ix)->hasColour(false)) c2_col = ix;
+ else if(c2->particle(ix)->hasColour(true )) c2_anti = ix;
+ }
+ assert(c1_col>=0&&c2_col>=0&&c1_anti>=0&&c2_anti>=0);
+
+c1->colParticle()->abandonChild(c1);
+c2->antiColParticle()->abandonChild(c2);
+
+ ClusterPtr newCluster1
+ = new_ptr( Cluster( c1->colParticle(), c2->antiColParticle() ) );
+
+ c1->colParticle()->addChild(newCluster1);
+ c2->antiColParticle()->addChild(newCluster1);
+
+ newCluster1->setVertex(0.5*( c1->colParticle()->vertex() +
+ c2->antiColParticle()->vertex() ));
+
+ if(c1->isBeamRemnant(c1_col )) newCluster1->setBeamRemnant(0,true);
+ if(c2->isBeamRemnant(c2_anti)) newCluster1->setBeamRemnant(1,true);
+
+ c1->antiColParticle()->abandonChild(c1);
+ c2->colParticle()->abandonChild(c2);
+
+ ClusterPtr newCluster2
+ = new_ptr( Cluster( c2->colParticle(), c1->antiColParticle() ) );
+
+ c1->antiColParticle()->addChild(newCluster2);
+ c2->colParticle()->addChild(newCluster2);
+
+ newCluster2->setVertex(0.5*( c2->colParticle()->vertex() +
+ c1->antiColParticle()->vertex() ));
if(c2->isBeamRemnant(c2_col )) newCluster2->setBeamRemnant(0,true);
if(c1->isBeamRemnant(c1_anti)) newCluster2->setBeamRemnant(1,true);
return pair <ClusterPtr,ClusterPtr> (newCluster1, newCluster2);
}
pair <int,int> ColourReconnector::_shuffle
(const PVector & q, const PVector & aq, unsigned maxtries) const {
const size_t nclusters = q.size();
assert (nclusters > 1);
assert (aq.size() == nclusters);
int i, j;
unsigned tries = 0;
bool octet;
do {
// find two different random integers in the range [0, nclusters)
i = UseRandom::irnd( nclusters );
do { j = UseRandom::irnd( nclusters ); } while (i == j);
// check if one of the two potential clusters would be a colour octet state
- octet = isColour8( q[i], aq[j] ) || isColour8( q[j], aq[i] ) ;
+ octet = _isColour8( q[i], aq[j] ) || _isColour8( q[j], aq[i] ) ;
tries++;
} while (octet && tries < maxtries);
if (octet) i = j = -1;
return make_pair(i,j);
}
-bool ColourReconnector::isColour8(cPPtr p, cPPtr q) const {
+
+bool ColourReconnector::_isColour8(tcPPtr p, tcPPtr q) const {
bool octet = false;
// make sure we have a triplet and an anti-triplet
if ( ( p->hasColour() && q->hasAntiColour() ) ||
( p->hasAntiColour() && q->hasColour() ) ) {
// true if p and q are originated from a colour octet
if ( !p->parents().empty() && !q->parents().empty() ) {
octet = ( p->parents()[0] == q->parents()[0] ) &&
( p->parents()[0]->data().iColour() == PDT::Colour8 );
}
// (Final) option: check if same colour8 parent
// or already found an octet.
if(_octetOption==0||octet) return octet;
// (All) option handling more octets
// by browsing particle history/colour lines.
tColinePtr cline,aline;
// Get colourlines form final states.
if(p->hasColour() && q->hasAntiColour()) {
cline = p-> colourLine();
aline = q->antiColourLine();
}
else {
cline = q-> colourLine();
aline = p->antiColourLine();
}
// Follow the colourline of p.
if ( !p->parents().empty() ) {
tPPtr parent = p->parents()[0];
while (parent) {
if(parent->data().iColour() == PDT::Colour8) {
// Coulour8 particles should have a colour
// and an anticolour line. Currently the
// remnant has none of those. Since the children
// of the remnant are not allowed to emit currently,
// the colour octet remnant is handled by the return
// statement above. The assert also catches other
// colour octets without clines. If the children of
// a remnant should be allowed to emit, the remnant
// should get appropriate colour lines and
// colour states.
// See Ticket: #407
- // assert(parent->colourLine()&&parent->antiColourLine());
+ // assert(parent->colourLine()&&parent->antiColourLine());
octet = (parent-> colourLine()==cline &&
parent->antiColourLine()==aline);
}
if(octet||parent->parents().empty()) break;
parent = parent->parents()[0];
}
}
}
return octet;
}
void ColourReconnector::persistentOutput(PersistentOStream & os) const {
- os << _clreco << _preco << _algorithm << _initTemp << _annealingFactor
+ os << _clreco << _preco << _precoBaryonic << _algorithm << _initTemp << _annealingFactor
<< _annealingSteps << _triesPerStepFactor << ounit(_maxDistance,femtometer)
<< _octetOption;
}
void ColourReconnector::persistentInput(PersistentIStream & is, int) {
- is >> _clreco >> _preco >> _algorithm >> _initTemp >> _annealingFactor
+ is >> _clreco >> _preco >> _precoBaryonic >> _algorithm >> _initTemp >> _annealingFactor
>> _annealingSteps >> _triesPerStepFactor >> iunit(_maxDistance,femtometer)
>> _octetOption;
}
void ColourReconnector::Init() {
static ClassDocumentation<ColourReconnector> documentation
("This class is responsible of the colour reconnection.");
static Switch<ColourReconnector,int> interfaceColourReconnection
("ColourReconnection",
"Colour reconnections",
&ColourReconnector::_clreco, 0, true, false);
static SwitchOption interfaceColourReconnectionNo
(interfaceColourReconnection,
"No",
"Colour reconnections off",
0);
static SwitchOption interfaceColourReconnectionYes
(interfaceColourReconnection,
"Yes",
"Colour reconnections on",
1);
static Parameter<ColourReconnector,double> interfaceMtrpAnnealingFactor
("AnnealingFactor",
"The annealing factor is the ratio of the temperatures in two successive "
"temperature steps.",
&ColourReconnector::_annealingFactor, 0.9, 0.0, 1.0,
false, false, Interface::limited);
static Parameter<ColourReconnector,unsigned> interfaceMtrpAnnealingSteps
("AnnealingSteps",
"Number of temperature steps in the statistical annealing algorithm",
&ColourReconnector::_annealingSteps, 50, 1, 10000,
false, false, Interface::limited);
static Parameter<ColourReconnector,double> interfaceMtrpTriesPerStepFactor
("TriesPerStepFactor",
"The number of reconnection tries per temperature steps is the number of "
"clusters times this factor.",
&ColourReconnector::_triesPerStepFactor, 5.0, 0.0, 100.0,
false, false, Interface::limited);
static Parameter<ColourReconnector,double> interfaceMtrpInitialTemp
("InitialTemperature",
"Factor used to determine the initial temperature from the median of the "
"energy change in a few random rearrangements.",
&ColourReconnector::_initTemp, 0.1, 0.00001, 100.0,
false, false, Interface::limited);
static Parameter<ColourReconnector,double> interfaceRecoProb
("ReconnectionProbability",
"Probability that a found reconnection possibility is actually accepted",
&ColourReconnector::_preco, 0.5, 0.0, 1.0,
false, false, Interface::limited);
+ static Parameter<ColourReconnector,double> interfaceRecoProbBaryonic
+ ("ReconnectionProbabilityBaryonic",
+ "Probability that a found reconnection possibility is actually accepted",
+ &ColourReconnector::_precoBaryonic, 0.5, 0.0, 1.0,
+ false, false, Interface::limited);
+
static Switch<ColourReconnector,int> interfaceAlgorithm
("Algorithm",
"Specifies the colour reconnection algorithm",
&ColourReconnector::_algorithm, 0, true, false);
static SwitchOption interfaceAlgorithmPlain
(interfaceAlgorithm,
"Plain",
"Plain colour reconnection as in Herwig 2.5.0",
0);
static SwitchOption interfaceAlgorithmStatistical
(interfaceAlgorithm,
"Statistical",
"Statistical colour reconnection using simulated annealing",
1);
-
+ static SwitchOption interfaceAlgorithmBaryonic
+ (interfaceAlgorithm,
+ "BaryonicReco",
+ "Baryonic cluster reconnection",
+ 2);
static Parameter<ColourReconnector,Length> interfaceMaxDistance
("MaxDistance",
"Maximum distance between the clusters at which to consider rearrangement"
" to avoid colour reconneections of displaced vertices",
&ColourReconnector::_maxDistance, femtometer, 1000.*femtometer, 0.0*femtometer, 1e100*femtometer,
false, false, Interface::limited);
+
static Switch<ColourReconnector,unsigned int> interfaceOctetTreatment
("OctetTreatment",
"Which octets are not allowed to be reconnected",
&ColourReconnector::_octetOption, 0, false, false);
static SwitchOption interfaceOctetTreatmentFinal
(interfaceOctetTreatment,
"Final",
"Only prevent for the final (usuaslly non-perturbative) g -> q qbar splitting",
0);
static SwitchOption interfaceOctetTreatmentAll
(interfaceOctetTreatment,
"All",
"Prevent for all octets",
1);
+}
-}
diff --git a/Hadronization/ColourReconnector.h b/Hadronization/ColourReconnector.h
--- a/Hadronization/ColourReconnector.h
+++ b/Hadronization/ColourReconnector.h
@@ -1,247 +1,265 @@
// -*- C++ -*-
//
// ColourReconnector.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_ColourReconnector_H
#define HERWIG_ColourReconnector_H
#include <ThePEG/Interface/Interfaced.h>
#include "CluHadConfig.h"
#include "ColourReconnector.fh"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Hadronization
* \class ColourReconnector
* \brief Class for changing colour reconnections of partons.
* \author Alberto Ribon, Christian Roehr
*
* This class does the nonperturbative colour rearrangement, after the
* nonperturbative gluon splitting and the "normal" cluster formation.
* It uses the list of particles in the event record, and the collections of
* "usual" clusters which is passed to the main method. If the colour
* reconnection is actually accepted, then the previous collections of "usual"
* clusters is first deleted and then the new one is created.
*
* * @see \ref ColourReconnectorInterfaces "The interfaces"
* defined for ColourReconnector.
*/
class ColourReconnector: public Interfaced {
public:
- /** @name Standard constructors and destructors. */
- //@{
- /**
- * Default constructor.
- */
- ColourReconnector() :
- _algorithm(0),
- _annealingFactor(0.9),
- _annealingSteps(50),
- _clreco(0),
- _initTemp(0.1),
- _preco(0.5),
- _triesPerStepFactor(5.0),
- _maxDistance(1000.*femtometer),
- _octetOption(0)
- {}
- //@}
-
/**
* Does the colour rearrangement, starting out from the list of particles in
* the event record and the collection of "usual" clusters passed as
* arguments. If the actual rearrangement is accepted, the initial collection of
* clusters is overridden by the old ones.
*/
void rearrange(ClusterVector & clusters);
+ using CluVecIt = ClusterVector::iterator;
private:
/** PRIVATE MEMBER FUNCTIONS */
/**
* @brief Calculates the sum of the squared cluster masses.
* @arguments q, aq vectors containing the quarks and antiquarks respectively
* @return Sum of cluster squared masses M^2_{q[i],aq[i]}.
*/
Energy2 _clusterMassSum(const PVector & q, const PVector & aq) const;
/**
* @brief Examines whether the cluster vector (under the given permutation of
* the antiquarks) contains colour-octet clusters
* @param cv Cluster vector
* @param P Permutation, a vector of permutated indices from 0 to
* cv.size()-1
*/
bool _containsColour8(const ClusterVector & cv, const vector<size_t> & P) const;
/**
* @brief A Metropolis-type algorithm which finds a local minimum in the
* total sum of cluster masses
* @arguments cv cluster vector
*/
void _doRecoStatistical(ClusterVector & cv) const;
/**
* @brief Plain colour reconnection as used in Herwig 2.5.0
* @arguments cv cluster vector
*/
void _doRecoPlain(ClusterVector & cv) const;
+
+ /**
+ * Baryonic Colour Reconnection model
+ */
+ void _doRecoBaryonic(ClusterVector & cv) const;
+
+
+ void _makeBaryonicClusters(ClusterPtr &c1, ClusterPtr &c2, ClusterPtr &c3,
+ ClusterPtr &newcluster1, ClusterPtr &newcluster2) const;
+
+
/**
* @brief Finds the cluster in cv which, if reconnected with the given
* cluster cl, would result in the smallest sum of cluster masses.
* If no reconnection partner can be found, a pointer to the
* original Cluster cl is returned.
* @arguments cv cluster vector
* cl cluster iterator (must be from cv) which wants to have a reconnection partner
* @return iterator to the found cluster, or the original cluster pointer if
* no mass-reducing combination can be found
*/
- ClusterVector::iterator _findRecoPartner(ClusterVector::iterator cl,
- ClusterVector & cv) const;
+
+
+ CluVecIt _findRecoPartner(CluVecIt cl, ClusterVector & cv) const;
+
+ CluVecIt _findPartnerRapidity(CluVecIt cl, ClusterVector & cv) const;
+
+ CluVecIt _findPartnerBaryonic(CluVecIt cl, ClusterVector & cv,
+ bool & tetraCand,
+ const ClusterVector& a,
+ CluVecIt &baryonic1,
+ CluVecIt &baryonic2 ) const;
+
+
+
/**
* @brief Reconnects the constituents of the given clusters to the (only)
* other possible cluster combination.
* @return pair of pointers to the two new clusters
*/
- pair <ClusterPtr,ClusterPtr> _reconnect(ClusterPtr c1, ClusterPtr c2) const;
+ pair <ClusterPtr,ClusterPtr> _reconnect(ClusterPtr &c1, ClusterPtr &c2) const;
+
+ /**
+ * Reconnection method for baryonic reconenction model
+ */
+ pair <ClusterPtr,ClusterPtr> _reconnectBaryonic(ClusterPtr &c1, ClusterPtr &c2) const;
+
/**
* @brief At random, swap two antiquarks, if not excluded by the
* constraint that there must not be any colour-octet clusters.
* @arguments q, aq vectors containing the quarks and antiquarks respectively
* maxtries maximal number of tries to find a non-colour-octet
* reconfiguration
* @return Pair of ints indicating the indices of the antiquarks to be
* swapped. Returns (-1,-1) if no valid reconfiguration could be
* found after maxtries trials
*/
pair <int,int>
_shuffle(const PVector & q, const PVector & aq, unsigned maxtries = 10) const;
+
+ /** DATA MEMBERS */
+
+ /**
+ * Specifies the colour reconnection algorithm to be used.
+ */
+ int _algorithm = 0;
+
+ /**
+ * The annealing factor is the ratio of two successive temperature steps:
+ * T_n = _annealingFactor * T_(n-1)
+ */
+ double _annealingFactor = 0.9;
+
+ /**
+ * Number of temperature steps in the statistical annealing algorithm
+ */
+ unsigned int _annealingSteps = 50;
+
+ /**
+ * Do we do colour reconnections?
+ */
+ int _clreco = 0;
+
+ /**
+ * Factor used to determine the initial temperature according to
+ * InitialTemperature = _initTemp * median {energy changes in a few random
+ * rearrangements}
+ */
+ double _initTemp = 0.1;
+
+ /**
+ * Probability that a found reconnection possibility is actually accepted.
+ */
+ double _preco = 0.5;
+
+
+ double _precoBaryonic = 0.5;
+
+ /**
+ * The number of tries per temperature steps is the number of clusters times
+ * this factor.
+ */
+ double _triesPerStepFactor = 5.0;
+ /**
+ * maximum allowed distance in the eta phi space for reconnection to occur
+ */
+
+ /**
+ * Maximium distance for reconnections
+ */
+ Length _maxDistance = picometer;
+
/**
* @return true, if the two partons are splitting products of the same
* gluon
*/
- bool isColour8(cPPtr p, cPPtr q) const;
-
+ bool _isColour8(tcPPtr p, tcPPtr q) const;
+
+ /**
+ * Option for handling octets
+ */
+ unsigned int _octetOption = 0;
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* Standard Init function used to initialize the interfaces.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** 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:
/**
* Private and non-existent assignment operator.
*/
- ColourReconnector & operator=(const ColourReconnector &);
+ ColourReconnector & operator=(const ColourReconnector &) = delete;
-private:
-
- /** DATA MEMBERS */
-
- /**
- * Specifies the colour reconnection algorithm to be used.
- */
- int _algorithm;
-
- /**
- * The annealing factor is the ratio of two successive temperature steps:
- * T_n = _annealingFactor * T_(n-1)
- */
- double _annealingFactor;
-
- /**
- * Number of temperature steps in the statistical annealing algorithm
- */
- unsigned _annealingSteps;
-
- /**
- * Do we do colour reconnections?
- */
- int _clreco;
-
- /**
- * Factor used to determine the initial temperature according to
- * InitialTemperature = _initTemp * median {energy changes in a few random
- * rearrangements}
- */
- double _initTemp;
-
- /**
- * Probability that a found reconnection possibility is actually accepted.
- */
- double _preco;
-
- /**
- * The number of tries per temperature steps is the number of clusters times
- * this factor.
- */
- double _triesPerStepFactor;
-
- /**
- * Maximium distance for reconnections
- */
- Length _maxDistance;
-
- /**
- * Option for handling octets
- */
- unsigned int _octetOption;
};
}
#endif /* HERWIG_ColourReconnector_H */
+
diff --git a/Hadronization/PartonSplitter.cc b/Hadronization/PartonSplitter.cc
--- a/Hadronization/PartonSplitter.cc
+++ b/Hadronization/PartonSplitter.cc
@@ -1,149 +1,223 @@
// -*- C++ -*-
//
// PartonSplitter.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the PartonSplitter class.
//
#include "PartonSplitter.h"
#include <ThePEG/Interface/ClassDocumentation.h>
#include <ThePEG/Interface/Reference.h>
+#include <ThePEG/Interface/Switch.h>
#include <ThePEG/Persistency/PersistentOStream.h>
#include <ThePEG/Persistency/PersistentIStream.h>
#include <ThePEG/PDT/EnumParticles.h>
#include <ThePEG/EventRecord/Step.h>
+#include "ThePEG/Interface/Parameter.h"
#include <ThePEG/Repository/EventGenerator.h>
#include <ThePEG/Repository/CurrentGenerator.h>
+#include "ThePEG/Repository/UseRandom.h"
#include "Herwig/Utilities/Kinematics.h"
#include <ThePEG/Utilities/DescribeClass.h>
#include "ClusterHadronizationHandler.h"
+#include "CheckId.h"
using namespace Herwig;
IBPtr PartonSplitter::clone() const {
return new_ptr(*this);
}
IBPtr PartonSplitter::fullclone() const {
return new_ptr(*this);
}
void PartonSplitter::persistentOutput(PersistentOStream & os) const {
- os << _quarkSelector << ounit(_gluonDistance,femtometer);
+ os << _quarkSelector << ounit(_gluonDistance,femtometer)
+ << _splitGluon << _splitPwtUquark << _splitPwtDquark << _splitPwtSquark;
}
void PartonSplitter::persistentInput(PersistentIStream & is, int) {
- is >> _quarkSelector >> iunit(_gluonDistance,femtometer);
+ is >> _quarkSelector >> iunit(_gluonDistance,femtometer)
+ >> _splitGluon >> _splitPwtUquark >> _splitPwtDquark >> _splitPwtSquark;
}
DescribeClass<PartonSplitter,Interfaced>
describePartonSplitter("Herwig::PartonSplitter","");
+
void PartonSplitter::Init() {
static ClassDocumentation<PartonSplitter> documentation
("This class is reponsible of the nonperturbative splitting of partons");
-
+
+ static Switch<PartonSplitter,int> interfaceSplit
+ ("Split",
+ "Option for different splitting options",
+ &PartonSplitter::_splitGluon, 1, false, false);
+ static SwitchOption interfaceSplitDefault
+ (interfaceSplit,
+ "ud",
+ "Normal cluster splitting where only u and d quarks are drawn is used.",
+ 0);
+ static SwitchOption interfaceSplitAll
+ (interfaceSplit,
+ "uds",
+ "Alternative cluster splitting where all light quark pairs (u, d, s) can be drawn.",
+ 1);
+
+ static Parameter<PartonSplitter,double> interfaceSplitPwtUquark
+ ("SplitPwtUquark",
+ "Weight for splitting in U quarks",
+ &PartonSplitter::_splitPwtUquark, 1, 0.0, 1.0,
+ false, false, Interface::limited);
+ static Parameter<PartonSplitter,double> interfaceSplitPwtDquark
+ ("SplitPwtDquark",
+ "Weight for splitting in D quarks",
+ &PartonSplitter::_splitPwtDquark, 1, 0.0, 1.0,
+ false, false, Interface::limited);
+ static Parameter<PartonSplitter,double> interfaceSplitPwtSquark
+ ("SplitPwtSquark",
+ "Weight for splitting in S quarks",
+ &PartonSplitter::_splitPwtSquark, 0.5, 0.0, 1.0,
+ false, false, Interface::limited);
+
}
void PartonSplitter::split(PVector & tagged) {
// set the gluon c tau once and for all
static bool first = true;
if(first) {
_gluonDistance = hbarc*getParticleData(ParticleID::g)->constituentMass()/
ClusterHadronizationHandler::currentHandler()->minVirtuality2();
first = false;
}
PVector newtag;
Energy2 Q02 = 0.99*sqr(getParticleData(ParticleID::g)->constituentMass());
// Loop over all of the particles in the event.
for(PVector::iterator pit = tagged.begin(); pit!=tagged.end(); ++pit) {
// only considering gluons so add other particles to list of particles
if( (**pit).data().id() != ParticleID::g ) {
newtag.push_back(*pit);
continue;
}
// should not have been called for massless or space-like gluons
if((**pit).momentum().m2() <= 0.0*sqr(MeV) ) {
throw Exception()
<< "Spacelike or massless gluon m2= " << (**pit).momentum().m2()/GeV2
<< "GeV2 in PartonSplitter::split()"
<< Exception::eventerror;
}
// time like gluon gets split
PPtr ptrQ = PPtr();
PPtr ptrQbar = PPtr();
splitTimeLikeGluon(*pit,ptrQ,ptrQbar);
ptrQ->scale(Q02);
ptrQbar->scale(Q02);
(*pit)->colourLine()->addColoured(ptrQ);
(*pit)->addChild(ptrQ);
newtag.push_back(ptrQ);
(*pit)->antiColourLine()->addAntiColoured(ptrQbar);
(*pit)->addChild(ptrQbar);
newtag.push_back(ptrQbar);
// set the life length of gluon
Length distance = UseRandom::rndExp(_gluonDistance);
(**pit).setLifeLength((distance/(**pit).mass())*(**pit).momentum());
// assume quarks same position as gluon
ptrQ ->setVertex((**pit).decayVertex());
ptrQ ->setLifeLength(Lorentz5Distance());
ptrQbar->setVertex((**pit).decayVertex());
ptrQbar->setLifeLength(Lorentz5Distance());
}
swap(tagged,newtag);
}
void PartonSplitter::splitTimeLikeGluon(tcPPtr ptrGluon,
PPtr & ptrQ,
PPtr & ptrQbar){
// select the quark flavour
- tPDPtr quark = _quarkSelector.select(UseRandom::rnd());
+ tPDPtr quark;
+ long idNew=0;
+
+ switch(_splitGluon){
+ case 0:
+ quark = _quarkSelector.select(UseRandom::rnd());
+ break;
+ case 1:
+ if ( ptrGluon->momentum().m() <
+ 2.0 *getParticle(ThePEG::ParticleID::s)->data().constituentMass() ) {
+ throw Exception() << "Impossible Kinematics in PartonSplitter::splitTimeLikeGluon()"
+ << Exception::runerror;
+ }
+ // Only allow light quarks u,d,s with the probabilities
+ double prob_d = _splitPwtDquark;
+ double prob_u = _splitPwtUquark;
+ double prob_s = _splitPwtSquark;
+
+ int choice = UseRandom::rnd3(prob_u, prob_d, prob_s);
+ switch(choice) {
+ case 0: idNew = ThePEG::ParticleID::u; break;
+ case 1: idNew = ThePEG::ParticleID::d; break;
+ case 2: idNew = ThePEG::ParticleID::s; break;
+ }
+ ptrQ = getParticle(idNew);
+ ptrQbar = getParticle(-idNew);
+ break;
+ }
// Solve the kinematics of the two body decay G --> Q + Qbar
Lorentz5Momentum momentumQ;
Lorentz5Momentum momentumQbar;
double cosThetaStar = UseRandom::rnd( -1.0 , 1.0 );
using Constants::pi;
double phiStar = UseRandom::rnd( -pi , pi );
- Energy constituentQmass = quark->constituentMass();
- if (ptrGluon->momentum().m() < 2.0*constituentQmass) {
+ Energy constituentQmass;
+ if(_splitGluon==0) {
+ constituentQmass = quark->constituentMass();
+ }else{
+ constituentQmass = ptrQ->data().constituentMass();
+ }
+
+ if (ptrGluon->momentum().m() < 2.0*constituentQmass) {
throw Exception() << "Impossible Kinematics in PartonSplitter::splitTimeLikeGluon()"
<< Exception::eventerror;
}
Kinematics::twoBodyDecay(ptrGluon->momentum(), constituentQmass,
constituentQmass, cosThetaStar, phiStar, momentumQ,
momentumQbar );
// Create quark and anti-quark particles of the chosen flavour
// and set they 5-momentum (the mass is the constituent one).
- ptrQ = new_ptr(Particle(quark ));
- ptrQbar = new_ptr(Particle(quark->CC()));
+ if(_splitGluon==0) {
+ ptrQ = new_ptr(Particle(quark ));
+ ptrQbar = new_ptr(Particle(quark->CC()));
+ }
+
ptrQ ->set5Momentum( momentumQ );
ptrQbar ->set5Momentum( momentumQbar );
}
void PartonSplitter::doinit() {
Interfaced::doinit();
// calculate the probabilties for the gluon to branch into each quark type
// based on the available phase-space, as in fortran.
Energy mg=getParticleData(ParticleID::g)->constituentMass();
for( int ix=1; ix<6; ++ix ) {
PDPtr quark = getParticleData(ix);
Energy pcm = Kinematics::pstarTwoBodyDecay(mg,quark->constituentMass(),
quark->constituentMass());
if(pcm>ZERO) _quarkSelector.insert(pcm/GeV,quark);
}
if(_quarkSelector.empty())
throw InitException() << "At least one quark must have constituent mass less "
<< "then the constituent mass of the gluon in "
<< "PartonSplitter::doinit()" << Exception::runerror;
}
diff --git a/Hadronization/PartonSplitter.h b/Hadronization/PartonSplitter.h
--- a/Hadronization/PartonSplitter.h
+++ b/Hadronization/PartonSplitter.h
@@ -1,144 +1,172 @@
// -*- C++ -*-
//
// PartonSplitter.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_PartonSplitter_H
#define HERWIG_PartonSplitter_H
#include "CluHadConfig.h"
#include <ThePEG/Interface/Interfaced.h>
#include <ThePEG/Utilities/Selector.h>
#include "PartonSplitter.fh"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Hadronization
* \class PartonSplitter
* \brief This class splits the gluons from the end of the shower.
* \author Philip Stephens
* \author Alberto Ribon
*
* This class does all of the nonperturbative parton splittings needed
* immediately after the end of the showering (both initial and final),
* as very first step of the cluster hadronization.
*
- * \todo change so quark weights can be varied and quarks other
- * than u and d can be produced
+ * the quarks are attributed with different weights for the splitting
+ * by default only the splitting in u and d quarks is allowed
+ * the option "set /Herwig/Hadronization/PartonSplitter:Split 1"
+ * allows for additional splitting into s quarks based on some weight
+ * in order for that to work the mass of the strange quark has to be changed
+ * from the default value s.t. m_g > 2m_s
+ *
*
* * @see \ref PartonSplitterInterfaces "The interfaces"
* defined for PartonSplitter.
*/
class PartonSplitter: public Interfaced {
public:
/**
* Default constructor
*/
- PartonSplitter() : _gluonDistance(ZERO)
+ PartonSplitter() :
+ _splitPwtUquark(1),
+ _splitPwtDquark(1),
+ _splitPwtSquark(0.5),
+ _gluonDistance(ZERO),
+ _splitGluon(0)
{}
/**
* This method does the nonperturbative splitting of:
* time-like gluons. At the end of the shower the gluons should be
* on a "physical" mass shell and should therefore be time-like.
* @param tagged The tagged particles to be split
* @return The particles which were not split and the products of splitting.
*/
void split(PVector & tagged);
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:
/**
* Private and non-existent assignment operator.
*/
PartonSplitter & operator=(const PartonSplitter &);
/**
* Non-perturbatively split a time-like gluon,
* if something goes wrong null pointers are returned.
* @param gluon The gluon to be split
* @param quark The quark produced in the splitting
* @param anti The antiquark produced in the splitting
*/
void splitTimeLikeGluon(tcPPtr gluon, PPtr & quark, PPtr & anti);
+ // probabilities for the different quark types
+ double _splitPwtUquark;
+ double _splitPwtDquark;
+ double _splitPwtSquark;
+
+
private:
/**
* The selector to pick the type of quark
*/
Selector<PDPtr,double> _quarkSelector;
/**
+ * A pointer to a Herwig::HadronSelector object for generating hadrons.
+ */
+
+ /**
* c tau for gluon decays
*/
Length _gluonDistance;
+
+ /**
+ * Flag used to determine between normal gluon splitting and alternative gluon splitting
+ */
+ int _splitGluon;
+
+
};
}
#endif /* HERWIG_PartonSplitter_H */
diff --git a/MatrixElement/DIS/MEChargedCurrentDIS.cc b/MatrixElement/DIS/MEChargedCurrentDIS.cc
--- a/MatrixElement/DIS/MEChargedCurrentDIS.cc
+++ b/MatrixElement/DIS/MEChargedCurrentDIS.cc
@@ -1,307 +1,312 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEChargedCurrentDIS class.
//
#include "MEChargedCurrentDIS.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Cuts/Cuts.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/PDF/PolarizedBeamParticleData.h"
using namespace Herwig;
MEChargedCurrentDIS::MEChargedCurrentDIS()
: _maxflavour(5), _massopt(0) {
vector<unsigned int> mopt(2,1);
mopt[1] = _massopt;
massOption(mopt);
}
void MEChargedCurrentDIS::doinit() {
DISBase::doinit();
_wp = getParticleData(ThePEG::ParticleID::Wplus );
_wm = getParticleData(ThePEG::ParticleID::Wminus);
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm) throw InitException()
<< "Must be the Herwig StandardModel class in "
<< "MEChargedCurrentDIS::doinit" << Exception::abortnow;
// vertices
_theFFWVertex = hwsm->vertexFFW();
}
void MEChargedCurrentDIS::getDiagrams() const {
// possible quarks
typedef std::vector<pair<long,long> > Pairvector;
Pairvector quarkpair;
quarkpair.reserve(6);
// don't even think of putting 'break' in here!
switch(_maxflavour) {
case 6:
quarkpair.push_back(make_pair(ParticleID::s, ParticleID::t));
quarkpair.push_back(make_pair(ParticleID::d, ParticleID::t));
quarkpair.push_back(make_pair(ParticleID::b, ParticleID::t));
+ [[fallthrough]];
case 5:
quarkpair.push_back(make_pair(ParticleID::b, ParticleID::c));
quarkpair.push_back(make_pair(ParticleID::b, ParticleID::u));
+ [[fallthrough]];
case 4:
quarkpair.push_back(make_pair(ParticleID::s, ParticleID::c));
quarkpair.push_back(make_pair(ParticleID::d, ParticleID::c));
+ [[fallthrough]];
case 3:
quarkpair.push_back(make_pair(ParticleID::s, ParticleID::u));
+ [[fallthrough]];
case 2:
quarkpair.push_back(make_pair(ParticleID::d, ParticleID::u));
+ [[fallthrough]];
default:
;
}
// create the diagrams
for(int il1=11;il1<=14;++il1) {
int il2 = il1%2==0 ? il1-1 : il1+1;
for(unsigned int iz=0;iz<2;++iz) {
tcPDPtr lepin = iz==1 ? getParticleData(il1) : getParticleData(-il1);
tcPDPtr lepout = iz==1 ? getParticleData(il2) : getParticleData(-il2);
tcPDPtr inter = lepin->iCharge()-lepout->iCharge()==3 ? _wp : _wm;
for(unsigned int iq=0;iq<quarkpair.size();++iq) {
tcPDPtr first = getParticleData(quarkpair[iq].first );
tcPDPtr second = getParticleData(quarkpair[iq].second);
if(inter==_wp) {
add(new_ptr((Tree2toNDiagram(3), lepin, inter, first ,
1, lepout, 2, second , -1)));
add(new_ptr((Tree2toNDiagram(3), lepin, inter, second->CC(),
1, lepout, 2, first->CC(), -2)));
}
else {
add(new_ptr((Tree2toNDiagram(3), lepin, inter, second ,
1, lepout, 2, first , -1)));
add(new_ptr((Tree2toNDiagram(3), lepin, inter, first->CC(),
1, lepout, 2, second->CC(), -2)));
}
}
}
}
}
unsigned int MEChargedCurrentDIS::orderInAlphaS() const {
return 0;
}
unsigned int MEChargedCurrentDIS::orderInAlphaEW() const {
return 2;
}
Selector<const ColourLines *>
MEChargedCurrentDIS::colourGeometries(tcDiagPtr diag) const {
static ColourLines c1("3 5");
static ColourLines c2("-3 -5");
Selector<const ColourLines *> sel;
if ( diag->id() == -1 )
sel.insert(1.0, &c1);
else
sel.insert(1.0, &c2);
return sel;
}
void MEChargedCurrentDIS::persistentOutput(PersistentOStream & os) const {
os << _theFFWVertex << _maxflavour << _wp << _wm << _massopt;
}
void MEChargedCurrentDIS::persistentInput(PersistentIStream & is, int) {
is >> _theFFWVertex >> _maxflavour >> _wp >> _wm >> _massopt;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEChargedCurrentDIS,DISBase>
describeHerwigMEChargedCurrentDIS("Herwig::MEChargedCurrentDIS", "HwMEDIS.so");
void MEChargedCurrentDIS::Init() {
static ClassDocumentation<MEChargedCurrentDIS> documentation
("The MEChargedCurrentDIS class implements the matrix elements "
"for leading-order charged current deep inelastic scattering");
static Parameter<MEChargedCurrentDIS,unsigned int> interfaceMaxFlavour
( "MaxFlavour",
"The heaviest incoming quark flavour this matrix element is allowed to handle "
"(if applicable).",
&MEChargedCurrentDIS::_maxflavour, 5, 2, 6, false, false, true);
static Switch<MEChargedCurrentDIS,unsigned int> interfaceMassOption
("MassOption",
"Option for the treatment of the mass of the outgoing quarks",
&MEChargedCurrentDIS::_massopt, 0, false, false);
static SwitchOption interfaceMassOptionMassless
(interfaceMassOption,
"Massless",
"Treat the outgoing quarks as massless",
0);
static SwitchOption interfaceMassOptionMassive
(interfaceMassOption,
"Massive",
"Treat the outgoing quarks as massive",
1);
}
Selector<MEBase::DiagramIndex>
MEChargedCurrentDIS::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) sel.insert(1., i);
return sel;
}
double MEChargedCurrentDIS::helicityME(vector<SpinorWaveFunction> & f1,
vector<SpinorWaveFunction> & f2,
vector<SpinorBarWaveFunction> & a1,
vector<SpinorBarWaveFunction> & a2,
bool lorder, bool qorder, bool calc) const {
// scale
Energy2 mb2(scale());
// matrix element to be stored
ProductionMatrixElement menew(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// pick a W boson
tcPDPtr ipart = (mePartonData()[0]->iCharge()-mePartonData()[1]->iCharge())==3 ?
_wp : _wm;
// declare the variables we need
VectorWaveFunction inter;
double me(0.);
Complex diag;
// sum over helicities to get the matrix element
unsigned int hel[4];
unsigned int lhel1,lhel2,qhel1,qhel2;
for(lhel1=0;lhel1<2;++lhel1) {
for(lhel2=0;lhel2<2;++lhel2) {
// intermediate W
inter = _theFFWVertex->evaluate(mb2,3,ipart,f1[lhel1],a1[lhel2]);
for(qhel1=0;qhel1<2;++qhel1) {
for(qhel2=0;qhel2<2;++qhel2) {
hel[0] = lhel1;
hel[1] = qhel1;
hel[2] = lhel2;
hel[3] = qhel2;
if(!lorder) swap(hel[0],hel[2]);
if(!qorder) swap(hel[1],hel[3]);
diag = _theFFWVertex->evaluate(mb2,f2[qhel1],a2[qhel2],inter);
me += norm(diag);
menew(hel[0],hel[1],hel[2],hel[3]) = diag;
}
}
}
}
// spin and colour factor
me *= 0.25;
tcPolarizedBeamPDPtr beam[2] =
{dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[0]),
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[1])};
if( beam[0] || beam[1] ) {
RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()),
beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())};
me = menew.average(rho[0],rho[1]);
}
if(calc) _me.reset(menew);
return me;
}
double MEChargedCurrentDIS::me2() const {
vector<SpinorWaveFunction> f1,f2;
vector<SpinorBarWaveFunction> a1,a2;
bool lorder,qorder;
SpinorWaveFunction l1,q1;
SpinorBarWaveFunction l2,q2;
// lepton wave functions
if(mePartonData()[0]->id()>0) {
lorder=true;
l1 = SpinorWaveFunction (meMomenta()[0],mePartonData()[0],incoming);
l2 = SpinorBarWaveFunction(meMomenta()[2],mePartonData()[2],outgoing);
}
else {
lorder=false;
l1 = SpinorWaveFunction (meMomenta()[2],mePartonData()[2],outgoing);
l2 = SpinorBarWaveFunction(meMomenta()[0],mePartonData()[0],incoming);
}
// quark wave functions
if(mePartonData()[1]->id()>0) {
qorder = true;
q1 = SpinorWaveFunction (meMomenta()[1],mePartonData()[1],incoming);
q2 = SpinorBarWaveFunction(meMomenta()[3],mePartonData()[3],outgoing);
}
else {
qorder = false;
q1 = SpinorWaveFunction (meMomenta()[3],mePartonData()[3],outgoing);
q2 = SpinorBarWaveFunction(meMomenta()[1],mePartonData()[1],incoming);
}
// wavefunctions for various helicities
for(unsigned int ix=0;ix<2;++ix) {
l1.reset(ix); f1.push_back(l1);
l2.reset(ix); a1.push_back(l2);
q1.reset(ix); f2.push_back(q1);
q2.reset(ix); a2.push_back(q2);
}
return helicityME(f1,f2,a1,a2,lorder,qorder,false);
}
void MEChargedCurrentDIS::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);
hard.push_back(sub->outgoing()[1]);
// sort out the ordering
unsigned int order[4]={0,1,2,3};
bool lorder(true),qorder(true);
if(abs(hard[0]->id())<6) swap(hard[0],hard[1]);
if(abs(hard[2]->id())<6) swap(hard[2],hard[3]);
if(hard[0]->id()<0) {
swap(order[0],order[2]);
lorder = false;
}
if(hard[1]->id()<0) {
swap(order[1],order[3]);
qorder = false;
}
vector<SpinorWaveFunction> f1,f2;
vector<SpinorBarWaveFunction> a1,a2;
SpinorWaveFunction (f1,hard[order[0]], lorder ? incoming : outgoing, !lorder,true);
SpinorWaveFunction (f2,hard[order[1]], qorder ? incoming : outgoing, !qorder,true);
SpinorBarWaveFunction(a1,hard[order[2]], lorder ? outgoing : incoming, lorder,true);
SpinorBarWaveFunction(a2,hard[order[3]], qorder ? outgoing : incoming, qorder,true);
helicityME(f1,f2,a1,a2,lorder,qorder,true);
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix) {
tSpinPtr spin = hard[ix]->spinInfo();
if(ix<2) {
tcPolarizedBeamPDPtr beam =
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(hard[ix]->dataPtr());
if(beam) spin->rhoMatrix() = beam->rhoMatrix();
}
spin->productionVertex(hardvertex);
}
}
double MEChargedCurrentDIS::A(tcPDPtr lin, tcPDPtr,
tcPDPtr qin, tcPDPtr, Energy2) const {
double output = 2.;
if(qin->id()<0) output *= -1.;
if(lin->id()<0) output *= -1;
return output;
}
diff --git a/MatrixElement/DrellYanBase.cc b/MatrixElement/DrellYanBase.cc
--- a/MatrixElement/DrellYanBase.cc
+++ b/MatrixElement/DrellYanBase.cc
@@ -1,914 +1,912 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DrellYanBase class.
//
#include "DrellYanBase.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Shower/RealEmissionProcess.h"
using namespace Herwig;
DrellYanBase::DrellYanBase()
: _channelwgtA(0.12), _channelwgtB(2.00), _nover(0), _maxwgt(0.),
_power(2.0),_preqqbar(6.5),_preqg(4.0),_pregqbar(4.0),
_min_pt(2.*GeV) {}
void DrellYanBase::persistentOutput(PersistentOStream & os) const {
os << _channelwgtA << _channelwgtB << _channelweights << _alpha
<< _power << _preqqbar << _preqg << _pregqbar << ounit( _min_pt, GeV )
<< _prefactor;
}
void DrellYanBase::persistentInput(PersistentIStream & is, int) {
is >> _channelwgtA >> _channelwgtB >> _channelweights >> _alpha
>> _power >> _preqqbar >> _preqg >> _pregqbar >> iunit( _min_pt, GeV )
>> _prefactor;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeAbstractClass<DrellYanBase,HwMEBase>
describeHerwigDrellYanBase("Herwig::DrellYanBase", "Herwig.so");
void DrellYanBase::Init() {
static ClassDocumentation<DrellYanBase> documentation
("The DrellYanBase class provides a base class for the"
" corrections to Drell-Yan type processes");
static Parameter<DrellYanBase,double> interfaceQQbarChannelWeight
("QQbarChannelWeight",
"The relative weights of the q qbar abd q g channels for selection."
" This is a technical parameter for the phase-space generation and "
"should not affect the results only the efficiency and fraction"
" of events with weight > 1.",
&DrellYanBase::_channelwgtA, 0.12, 0.01, 100.,
false, false, Interface::limited);
static Parameter<DrellYanBase,double> interfaceQGChannelWeight
("QGChannelWeight",
"The relative weights of the qg abd qbar g channels for selection."
" This is a technical parameter for the phase-space generation and "
"should not affect the results only the efficiency and fraction",
&DrellYanBase::_channelwgtB, 2., 0.01, 100.,
false, false, Interface::limited);
static Reference<DrellYanBase,ShowerAlpha> interfaceCoupling
("Coupling",
"Pointer to the object to calculate the coupling for the correction",
&DrellYanBase::_alpha, false, false, true, false, false);
static Parameter<DrellYanBase,double> interfacePower
("Power",
"The power for the sampling of the matrix elements",
&DrellYanBase::_power, 2.0, 1.0, 10.0,
false, false, Interface::limited);
static Parameter<DrellYanBase,double> interfacePrefactorqqbar
("Prefactorqqbar",
"The prefactor for the sampling of the q qbar channel",
&DrellYanBase::_preqqbar, 5.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<DrellYanBase,double> interfacePrefactorqg
("Prefactorqg",
"The prefactor for the sampling of the q g channel",
&DrellYanBase::_preqg, 3.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<DrellYanBase,double> interfacePrefactorgqbar
("Prefactorgqbar",
"The prefactor for the sampling of the g qbar channel",
&DrellYanBase::_pregqbar, 3.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<DrellYanBase, Energy> interfacePtMin
("minPt",
"The pt cut on hardest emision generation"
"2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)",
&DrellYanBase::_min_pt, GeV, 2.*GeV, ZERO, 100000.0*GeV,
false, false, Interface::limited);
}
void DrellYanBase::doinit() {
HwMEBase::doinit();
_channelweights.push_back(_channelwgtA/(1.+_channelwgtA));
_channelweights.push_back(_channelweights[0]+1./(1.+_channelwgtA)/(1+_channelwgtB));
_channelweights.push_back(1.0);
_prefactor.push_back(_preqqbar);
_prefactor.push_back(_preqg);
_prefactor.push_back(_pregqbar);
}
void DrellYanBase::dofinish() {
HwMEBase::dofinish();
if(_nover==0) return;
generator()->log() << "DrellYanBase when applying the hard correction "
<< _nover << " weights larger than one were generated of which"
<< " the largest was " << _maxwgt << "\n";
}
RealEmissionProcessPtr DrellYanBase::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) {
// get the quark,antiquark
ParticleVector incoming;
vector<tcBeamPtr> beams;
+ Lorentz5Momentum phadron;
for(unsigned int ix=0;ix<born->bornIncoming().size();++ix) {
incoming.push_back(born->bornIncoming()[ix]);
tPPtr beam = born->hadrons()[ix];
+ phadron+=beam->momentum();
beams.push_back(dynamic_ptr_cast<tcBeamPtr>(beam->dataPtr()));
}
+ Energy2 shad = phadron.m2();
pair<double,double> xnew = born->x();
// ensure that the quark is first
if(incoming[0]->id()<incoming[1]->id()) {
swap(incoming[0],incoming[1]);
swap(beams[0],beams[1]);
swap(xnew.first,xnew.second);
}
// and the gauge boson
Lorentz5Momentum pboson;
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
pboson += born->bornOutgoing()[ix]->momentum();
}
pboson.rescaleMass();
// calculate the momenta
unsigned int iemit,itype;
vector<Lorentz5Momentum> pnew;
LorentzRotation trans;
// if not accepted return
- if(!applyHard(incoming,beams,pboson,iemit,itype,pnew,trans,xnew)) return RealEmissionProcessPtr();
+ if(!applyHard(incoming,beams,pboson,iemit,itype,pnew,trans,xnew,shad))
+ return RealEmissionProcessPtr();
// if applying ME correction create the new particles
// first the final-state particles
Boost boostv=pboson.findBoostToCM();
trans *=LorentzRotation(boostv);
born->transformation(trans);
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
Lorentz5Momentum pnew = trans*(born->bornOutgoing()[ix]->momentum());
born->outgoing().push_back(born->bornOutgoing()[ix]->dataPtr()->produceParticle(pnew));
}
// then emitter, spectator and emitted
// emission of a final-state gluon
if(itype==0) {
// get the momenta of the new particles
Lorentz5Momentum pquark(pnew[0]),panti(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pquark,panti);
// ensure gluon can be put on shell
Lorentz5Momentum ptest(pgluon);
if(ptest.boost(-(pquark+panti).boostVector()).e() <
getParticleData(ParticleID::g)->constituentMass()) return RealEmissionProcessPtr();
// outgoing gluon
born->outgoing().push_back(getParticleData(ParticleID::g)->produceParticle(pgluon));
// incoming particles
if(born->bornIncoming()[0]->id()>0) {
if(iemit==1) {
born->emitter(0);
born->spectator(1);
}
else {
born->emitter(1);
born->spectator(0);
}
born->incoming().push_back(born->bornIncoming()[0]->dataPtr()->produceParticle(pquark));
born->incoming().push_back(born->bornIncoming()[1]->dataPtr()->produceParticle(panti));
born->outgoing().back()->incomingColour(born->incoming()[0]);
born->outgoing().back()->incomingAntiColour(born->incoming()[1]);
}
else {
if(iemit==1) {
born->emitter(1);
born->spectator(0);
}
else {
born->emitter(0);
born->spectator(1);
}
born->incoming().push_back(born->bornIncoming()[0]->dataPtr()->produceParticle(panti));
born->incoming().push_back(born->bornIncoming()[1]->dataPtr()->produceParticle(pquark));
born->outgoing().back()->incomingColour(born->incoming()[1]);
born->outgoing().back()->incomingAntiColour(born->incoming()[0]);
}
}
else if(itype==1) {
Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pin,pout);
// ensure outgoing quark can be put on-shell
Lorentz5Momentum ptest(pout);
if(ptest.boost(-(pin+pgluon).boostVector()).e() <
incoming[1]->dataPtr()->constituentMass()) return RealEmissionProcessPtr();
// create the new gluon
PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon);
// create the new outgoing quark
PPtr newout= incoming[1]->dataPtr()->CC()->produceParticle(pout);
// create the new incoming quark
PPtr newin = incoming[0]->dataPtr()->produceParticle(pin);
// colours
newout->incomingColour(newg);
newin->antiColourNeighbour(newg);
if(born->bornIncoming()[0]->id()>0) {
born->emitter (1);
born->spectator(0);
born->incoming().push_back(newin);
born->incoming().push_back(newg );
}
else {
born->emitter (0);
born->spectator(1);
born->incoming().push_back(newg );
born->incoming().push_back(newin);
}
born->outgoing().push_back(newout);
}
else if(itype==2) {
Lorentz5Momentum pin(pnew[0]),pout(pnew[1]),pgluon(pnew[2]);
if(iemit==2) swap(pin,pout);
// ensure outgoing antiquark can be put on-shell
Lorentz5Momentum ptest(pout);
if(ptest.boost(-(pin+pgluon).boostVector()).e() <
incoming[0]->dataPtr()->constituentMass()) return RealEmissionProcessPtr();
// create the new gluon
PPtr newg = getParticleData(ParticleID::g)->produceParticle(pgluon);
// create the new outgoing antiquark
PPtr newout= incoming[0]->dataPtr()->CC()->produceParticle(pout);
// create the new incoming antiquark
PPtr newin = incoming[1]->dataPtr()->produceParticle(pin);
// colours
newout->incomingAntiColour(newg);
newin->colourNeighbour(newg);
if(born->bornIncoming()[0]->id()>0) {
born->emitter (0);
born->spectator(1);
born->incoming().push_back(newg );
born->incoming().push_back(newin);
}
else {
born->emitter (1);
born->spectator(0);
born->incoming().push_back(newin);
born->incoming().push_back(newg );
}
born->outgoing().push_back(newout);
}
else
assert(false);
born->emitted(born->outgoing().size()+1);
if(born->bornIncoming()[0]->id()<0) {
swap(xnew.first,xnew.second);
}
born->x(xnew);
born->interaction(ShowerInteraction::QCD);
return born;
}
bool DrellYanBase::applyHard(ParticleVector & quarks,
vector<tcBeamPtr> beams, Lorentz5Momentum boson,
unsigned int & iemit,unsigned int & itype,
vector<Lorentz5Momentum> & pnew,
LorentzRotation & trans,
- pair<double,double> & xout) {
+ pair<double,double> & xout,
+ Energy2 shad) {
// check that quark along +z and qbar along -z
bool quarkplus=quarks[0]->momentum().z()>quarks[1]->momentum().z();
// calculate the limits on s
Energy mb = sqrt(mb2_);
Energy2 smin=mb2_;
- Energy2 s=
- (generator()->currentEvent()->incoming().first ->momentum()+
- generator()->currentEvent()->incoming().second->momentum()).m2();
- Energy2 smax(s);
+ Energy2 smax(shad);
// calculate the rapidity of the boson
double yB=0.5*log((boson.e()+boson.z())/
(boson.e()-boson.z()));
if(!quarkplus) yB=-yB;
// if no phase-space return
if(smax<smin) return false;
// get the evolution scales (this needs improving)
double kappa[2]={1.,1.};
// get the momentum fractions for the leading order process
// and the values of the PDF's
double x[2]={-99.99e99,-99.99e99}, fx[2]={-99.99e99,-99.99e99};
tcPDFPtr pdf[2];
x[0] = xout. first;
x[1] = xout.second;
for(unsigned int ix=0;ix<quarks.size();++ix) {
assert(beams[ix]);
pdf[ix]=beams[ix]->pdf();
assert(pdf[ix]);
fx[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),mb2_,x[ix]);
}
// select the type of process and generate the kinematics
double rn(UseRandom::rnd());
Energy2 shat(ZERO),uhat(ZERO),that(ZERO);
double weight(0.),xnew[2]={1.,1.};
// generate the value of s according to 1/s^2
shat = smax*smin/(smin+UseRandom::rnd()*(smax-smin));
Energy2 jacobian = sqr(shat)*(1./smin-1./smax);
double sbar=shat/mb2_;
// calculate limits on that
Energy2 tmax=mb2_*kappa[0]*(1.-sbar)/(kappa[0]+sbar);
Energy2 tmin=shat*(1.-sbar)/(kappa[1]+sbar);
// calculate the limits on uhat
Energy2 umax(mb2_-shat-tmin),umin(mb2_-shat-tmax);
// check inside phase space
if(tmax<tmin||umax<umin) return false;
// q qbar -> g V
if(rn<_channelweights[0]) {
// generate t and u according to 1/t+1/u
// generate in 1/t
if(UseRandom::rndbool(0.5)) {
that=tmax*pow(tmin/tmax,UseRandom::rnd());
uhat=mb2_-shat-that;
jacobian *=log(tmin/tmax);
}
// generate in 1/u
else {
uhat=umax*pow(umin/umax,UseRandom::rnd());
that=mb2_-shat-uhat;
jacobian *=log(umin/umax);
}
Energy4 jacobian2 = jacobian * 2.*uhat*that/(shat-mb2_);
// new scale (this is mt^2=pt^2+mb^2)
Energy2 scale(uhat*that/shat+mb2_);
// the PDF's with the emitted gluon
double fxnew[2];
- xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-uhat)/(mb2_-that));
- xnew[1]=shat/(s*xnew[0]);
- for(unsigned int ix=0;ix<2;++ix)
- {fxnew[ix]=pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),scale,xnew[ix]);}
+ xnew[0]=exp(yB)/sqrt(shad)*sqrt(shat*(mb2_-uhat)/(mb2_-that));
+ xnew[1]=shat/(shad*xnew[0]);
+ for(unsigned int ix=0;ix<2;++ix) {
+ fxnew[ix] = xnew[ix]<=1. ? pdf[ix]->xfx(beams[ix],quarks[ix]->dataPtr(),scale,xnew[ix]) : 0.;
+ }
// jacobian and me parts of the weight
weight=jacobian2*(sqr(mb2_-that)+sqr(mb2_-uhat))/(sqr(shat)*that*uhat);
// pdf part of the weight
weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]);
// finally coupling, colour factor and different channel pieces
weight *= 2./3./Constants::pi/_channelweights[0]*_alpha->value(scale);
// select the emiting particle
iemit=1;
if(UseRandom::rnd()<sqr(mb2_-uhat)/(sqr(mb2_-uhat)+sqr(mb2_-that))) iemit=2;
itype=0;
}
// incoming gluon
else {
// generate t
if(rn>_channelweights[1]) {
swap(tmax,tmin);
tmax=mb2_-shat-tmax;
tmin=mb2_-shat-tmin;
}
that=tmax*pow(tmin/tmax,UseRandom::rnd());
uhat=mb2_-shat-that;
Energy4 jacobian2 = jacobian * that*log(tmax/tmin);
// new scale (this is mt^2=pt^2+mb^2)
Energy2 scale(uhat*that/shat+mb2_);
// g qbar -> qbar V
double fxnew[2];
if(rn<_channelweights[1]) {
itype=2;
- xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-uhat)/(mb2_-that));
- xnew[1]=shat/(s*xnew[0]);
- fxnew[0]=pdf[0]->xfx(beams[0],getParticleData(ParticleID::g),scale,xnew[0]);
- fxnew[1]=pdf[1]->xfx(beams[1],quarks[1]->dataPtr(),scale,xnew[1]);
+ xnew[0]=exp(yB)/sqrt(shad)*sqrt(shat*(mb2_-uhat)/(mb2_-that));
+ xnew[1]=shat/(shad*xnew[0]);
+ fxnew[0] = xnew[0] <=1. ? pdf[0]->xfx(beams[0],getParticleData(ParticleID::g),scale,xnew[0]) : 0.;
+ fxnew[1] = xnew[1] <=1. ? pdf[1]->xfx(beams[1],quarks[1]->dataPtr() ,scale,xnew[1]) : 0.;
jacobian2/=(_channelweights[1]-_channelweights[0]);
}
// q g -> q V
else {
itype=1;
- xnew[0]=exp(yB)/sqrt(s)*sqrt(shat*(mb2_-that)/(mb2_-uhat));
- xnew[1]=shat/(s*xnew[0]);
- fxnew[0]=pdf[0]->xfx(beams[0],quarks[0]->dataPtr(),scale,xnew[0]);
- fxnew[1]=pdf[1]->xfx(beams[1],getParticleData(ParticleID::g),scale,xnew[1]);
+ xnew[0]=exp(yB)/sqrt(shad)*sqrt(shat*(mb2_-that)/(mb2_-uhat));
+ xnew[1]=shat/(shad*xnew[0]);
+ fxnew[0] = xnew[0] <=1. ? pdf[0]->xfx(beams[0],quarks[0]->dataPtr(),scale,xnew[0]) : 0.;
+ fxnew[1] = xnew[1] <=1. ? pdf[1]->xfx(beams[1],getParticleData(ParticleID::g),scale,xnew[1]) : 0.;
jacobian2/=(_channelweights[2]-_channelweights[1]);
}
// jacobian and me parts of the weight
weight=-jacobian2*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat)*shat*that);
// pdf part of the weight
weight *=fxnew[0]*fxnew[1]*x[0]*x[1]/(fx[0]*fx[1]*xnew[0]*xnew[1]);
// finally coupling, colour factor and different channel pieces
weight *= 0.25/Constants::pi*_alpha->value(scale);
// select the emiting particle
iemit=1;
if(UseRandom::rnd()<sqr(mb2_-that)/(sqr(mb2_-that)+sqr(mb2_-shat))) iemit=2;
}
// if me correction should be applied
if(weight>1.) {
++_nover;
_maxwgt=max(_maxwgt,weight);
weight=1.;
}
if(UseRandom::rnd()>weight) return false;
// construct the momenta in the rest frame of the boson
Lorentz5Momentum pb(ZERO,ZERO,ZERO,mb,mb),pspect,pg,pemit;
double cos3 = 0.0;
- if(itype==0)
- {
- pg = Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(shat-mb2_)/mb,ZERO);
- Energy2 tp(that),up(uhat);
- double zsign(quarkplus ? -1. : 1.);
- if(iemit==2)
- {
- tp=uhat;
- up=that;
- zsign *= -1.;
- }
- pspect = Lorentz5Momentum(ZERO,ZERO,zsign*0.5*(mb2_-tp)/mb,
- 0.5*(mb2_-tp)/mb,ZERO);
- Energy eemit=0.5*(mb2_-up)/mb;
+ if(itype==0) {
+ pg = Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(shat-mb2_)/mb,ZERO);
+ Energy2 tp(that),up(uhat);
+ double zsign(quarkplus ? -1. : 1.);
+ if(iemit==2) {
+ tp=uhat;
+ up=that;
+ zsign *= -1.;
+ }
+ pspect = Lorentz5Momentum(ZERO,ZERO,zsign*0.5*(mb2_-tp)/mb,
+ 0.5*(mb2_-tp)/mb,ZERO);
+ Energy eemit=0.5*(mb2_-up)/mb;
+ cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
+ }
+ else {
+ pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(mb2_-uhat)/mb,ZERO);
+ double zsign(quarkplus ? 1. : -1.);
+ if(iemit==1) {
+ if(itype==1) zsign *= -1.;
+ pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(shat-mb2_)/mb,
+ 0.5*(shat-mb2_)/mb);
+ Energy eemit=0.5*(mb2_-that)/mb;
cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
}
- else
- {
- pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(mb2_-uhat)/mb,ZERO);
- double zsign(quarkplus ? 1. : -1.);
- if(iemit==1)
- {
- if(itype==1) zsign *= -1.;
- pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(shat-mb2_)/mb,
- 0.5*(shat-mb2_)/mb);
- Energy eemit=0.5*(mb2_-that)/mb;
- cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
- }
- else
- {
- if(itype==2) zsign *= -1.;
- pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(mb2_-that)/mb,
- 0.5*(mb2_-that)/mb);
- Energy eemit=0.5*(shat-mb2_)/mb;
- cos3 = 0.5/pspect.z()/pg.e()*(-sqr(pspect.e())-sqr(pg.e())+sqr(eemit));
- }
+ else {
+ if(itype==2) zsign *= -1.;
+ pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(mb2_-that)/mb,
+ 0.5*(mb2_-that)/mb);
+ Energy eemit=0.5*(shat-mb2_)/mb;
+ cos3 = 0.5/pspect.z()/pg.e()*(-sqr(pspect.e())-sqr(pg.e())+sqr(eemit));
}
+ }
// rotate the gluon
double sin3(sqrt(1.-sqr(cos3)));
double phi(Constants::twopi*UseRandom::rnd());
pg.setX(pg.e()*sin3*cos(phi));
pg.setY(pg.e()*sin3*sin(phi));
pg.setZ(pg.e()*cos3);
if(itype==0) {
pemit=pb+pg-pspect;
}
else {
if(iemit==1) pemit=pb+pspect-pg;
else pemit=pspect+pg-pb;
}
pemit.rescaleMass();
// find the new CMF
Lorentz5Momentum pp[2];
if(itype==0) {
if(iemit==1) {
pp[0]=pemit;
pp[1]=pspect;
}
else {
pp[0]=pspect;
pp[1]=pemit;
}
}
else if(itype==1) {
pp[1]=pg;
if(iemit==1) pp[0]=pemit;
else pp[0]=pspect;
}
else {
pp[0]=pg;
if(iemit==1) pp[1]=pemit;
else pp[1]=pspect;
}
Lorentz5Momentum pz= quarkplus ? pp[0] : pp[1];
pp[0]/=xnew[0];
pp[1]/=xnew[1];
Lorentz5Momentum plab(pp[0]+pp[1]);
plab.rescaleMass();
// construct the boost to rest frame of plab
trans=LorentzRotation(plab.findBoostToCM());
pz.transform(trans);
// rotate so emitting particle along z axis
// rotate so in x-z plane
trans.rotateZ(-atan2(pz.y(),pz.x()));
// rotate so along
trans.rotateY(-acos(pz.z()/pz.vect().mag()));
// undo azimuthal rotation
trans.rotateZ(atan2(pz.y(),pz.x()));
// perform the transforms
pb .transform(trans);
pspect.transform(trans);
pg .transform(trans);
pemit .transform(trans);
// momenta to be returned
pnew.push_back(pemit);
pnew.push_back(pspect);
pnew.push_back(pg);
pnew.push_back(pb);
xout.first=xnew[0];
xout.second=xnew[1];
return true;
}
bool DrellYanBase::softMatrixElementVeto(PPtr parent,
PPtr progenitor,
const bool & fs,
const Energy & highestpT,
const vector<tcPDPtr> & ids,
const double & z,
const Energy & scale,
const Energy & pT) {
if(fs) return false;
// check if me correction should be applied
long id[2]={progenitor->id(),parent->id()};
if(id[0]!=id[1]||id[1]==ParticleID::g) return false;
// check if hardest so far
if(pT<highestpT) return false;
// compute the invariants
double kappa(sqr(scale)/mb2_);
Energy2 shat(mb2_/z*(1.+(1.-z)*kappa)),that(-(1.-z)*kappa*mb2_),uhat(-(1.-z)*shat);
// check which type of process
// g qbar
double wgt(1.);
if(id[0]>0&&ids[0]->id()==ParticleID::g)
wgt=mb2_/(shat+uhat)*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat+uhat)+sqr(uhat));
else if(id[0]>0&&ids[0]->id()==id[0])
wgt=mb2_/(shat+uhat)*(sqr(mb2_-uhat)+sqr(mb2_-that))/(sqr(shat)+sqr(shat+uhat));
else if(id[0]<0&&ids[0]->id()==ParticleID::g)
wgt=mb2_/(shat+uhat)*(sqr(mb2_-that)+sqr(mb2_-shat))/(sqr(shat+uhat)+sqr(uhat));
else if(id[0]<0&&ids[0]->id()==id[0])
wgt=mb2_/(shat+uhat)*(sqr(mb2_-uhat)+sqr(mb2_-that))/(sqr(shat)+sqr(shat+uhat));
else
return false;
if(wgt<.0||wgt>1.) generator()->log() << "Soft ME correction weight too large or "
<< "negative in DrellYanBase::"
<< "softMatrixElementVeto()soft weight "
<< " sbar = " << shat/mb2_
<< " tbar = " << that/mb2_
<< "weight = " << wgt << "\n";
// return whether or not vetoed
return !UseRandom::rndbool(wgt);
}
RealEmissionProcessPtr DrellYanBase::generateHardest(RealEmissionProcessPtr born,
ShowerInteraction inter) {
// check if generating QCD radiation
if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD &&
inter!=ShowerInteraction::ALL)
return RealEmissionProcessPtr();
useMe();
// get the particles to be showered
_beams.clear();
_partons.clear();
// find the incoming particles
ParticleVector incoming;
_quarkplus = true;
ParticleVector particlesToShower;
// progenitor particles are produced in z direction.
for(unsigned int ix=0;ix<born->bornIncoming().size();++ix) {
incoming.push_back(born->bornIncoming()[ix]);
tPPtr beam = born->hadrons()[ix];
_beams.push_back(dynamic_ptr_cast<tcBeamPtr>(beam->dataPtr()));
_partons.push_back( born->bornIncoming()[ix]->dataPtr() );
// check that quark is along +ve z direction
if(born->bornIncoming()[ix]->id() > 0 &&
born->bornIncoming()[ix]->momentum().z() < ZERO )
_quarkplus = false;
particlesToShower.push_back( born->bornIncoming()[ix] );
}
Lorentz5Momentum pboson;
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
pboson += born->bornOutgoing()[ix]->momentum();
}
pboson.rescaleMass();
// calculate the rapidity of the boson
_yb = 0.5 * log((pboson.e()+pboson.z())/(pboson.e()-pboson.z()));
_yb *= _quarkplus ? 1. : -1.;
_mass = pboson.mass();
// we are assuming quark first, swap order to ensure this
// if antiquark first
bool order = _partons[0]->id()<_partons[1]->id();
if(order) {
swap(_partons[0],_partons[1]);
swap(_beams[0],_beams[1]);
}
vector<Lorentz5Momentum> pnew;
int emission_type(-1);
// generate the hard emission and return if no emission
if(!getEvent(pnew,emission_type)) {
born->pT()[ShowerInteraction::QCD] = _min_pt;
return born;
}
// construct the HardTree object needed to perform the showers
ParticleVector newparticles;
// make the particles for the HardTree
tcPDPtr gluon=getParticleData(ParticleID::g);
// create the partons
int iemit;
// q qbar -> g V
ColinePtr newline[2]={new_ptr(ColourLine()),new_ptr(ColourLine())};
if(emission_type==0) {
newparticles.push_back(_partons[0]->produceParticle(pnew[0]));
newparticles.push_back(_partons[1]->produceParticle(pnew[1]));
newparticles.push_back(gluon ->produceParticle(pnew[2]));
newline[1]->addColoured(newparticles[0]);
newline[1]->addColoured(newparticles[2]);
newline[0]->addAntiColoured(newparticles[1]);
newline[0]->addAntiColoured(newparticles[2]);
iemit = (pnew[0]-pnew[2]).m2()>(pnew[1]-pnew[2]).m2() ? 0 : 1;
}
// q g -> q V
else if(emission_type==1) {
iemit =1;
newparticles.push_back(_partons[0]->produceParticle(pnew[0]));
newparticles.push_back(gluon ->produceParticle(pnew[1]));
newparticles.push_back(_partons[1]->CC()->produceParticle(pnew[2]));
newline[1]->addColoured(newparticles[0]);
newline[1]->addAntiColoured(newparticles[1]);
newline[0]->addColoured(newparticles[1]);
newline[0]->addColoured(newparticles[2]);
}
// g qbar -> qbar V
else {
iemit =0;
newparticles.push_back(gluon ->produceParticle(pnew[0]));
newparticles.push_back(_partons[1]->produceParticle(pnew[1]));
newparticles.push_back(_partons[0]->CC()->produceParticle(pnew[2]));
newline[0]->addAntiColoured(newparticles[1]);
newline[0]->addColoured(newparticles[0]);
newline[1]->addAntiColoured(newparticles[0]);
newline[1]->addAntiColoured(newparticles[2]);
}
int ispect = iemit == 0 ? 1 : 0;
if(iemit==0) newline[0]->addColoured(newparticles.back());
else newline[1]->addAntiColoured(newparticles.back());
// compute the boost for the bosons
LorentzRotation boost(pboson.findBoostToCM());
boost.boost(pnew[3].boostVector());
born->transformation(boost);
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
born->outgoing().push_back(born->bornOutgoing()[ix]->dataPtr()->
produceParticle(born->bornOutgoing()[ix]->momentum()));
born->outgoing().back()->transform(boost);
}
if(!order) {
born->incoming().push_back(newparticles[0]);
born->incoming().push_back(newparticles[1]);
}
else {
born->incoming().push_back(newparticles[1]);
born->incoming().push_back(newparticles[0]);
swap(iemit,ispect);
}
born->outgoing().push_back(newparticles[2]);
born->emitter (iemit );
born->spectator(ispect);
born->emitted(born->bornOutgoing().size()+2);
pair<double,double> xnew;
for(unsigned int ix=0;ix<2;++ix) {
double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho();
if(ix==0) xnew.first = x;
else xnew.second = x;
}
born->x(xnew);
born->pT()[ShowerInteraction::QCD] = _pt;
born->interaction(ShowerInteraction::QCD);
return born;
}
double DrellYanBase::getResult(int emis_type, Energy pt, double yj) {
Energy2 s=sqr(generator()->maximumCMEnergy());
Energy2 m2(sqr(_mass));
Energy2 scale = m2+sqr(pt);
Energy et=sqrt(scale);
// longitudinal real correction fractions
double x = pt*exp( yj)/sqrt(s)+et*exp( _yb)/sqrt(s);
double y = pt*exp(-yj)/sqrt(s)+et*exp(-_yb)/sqrt(s);
// reject if outside region
if(x<0.||x>1.||y<0.||y>1.||x*y<m2/s) return 0.;
// longitudinal born fractions
double x1 = _mass*exp( _yb)/sqrt(s);
double y1 = _mass*exp(-_yb)/sqrt(s);
// mandelstam variables
Energy2 th = -sqrt(s)*x*pt*exp(-yj);
Energy2 uh = -sqrt(s)*y*pt*exp( yj);
Energy2 sh = m2-th-uh;
double res;
// pdf part of the cross section
double pdf[4];
pdf[0]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],m2,x1);
pdf[1]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],m2,y1);
//qqbar2Zg
using Constants::pi;
if(emis_type==0) {
pdf[2]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],scale,x);
pdf[3]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],scale,y);
res = 4./3./pi*(sqr(th-m2)+sqr(uh-m2))*pt/(sh*uh*th)*GeV;
}
//qg2Zq
else if(emis_type==1) {
pdf[2]=_beams[0]->pdf()->xfx(_beams[0],_partons[0],scale,x);
pdf[3]=_beams[1]->pdf()->xfx(_beams[1],getParticleData(ParticleID::g),scale,y);
res = -1./2./pi*(sqr(uh-m2)+sqr(sh-m2))*pt/(sh*sh*uh)*GeV;
}
//qbarg2Zqbar
else {
pdf[2]=_beams[0]->pdf()->xfx(_beams[0],getParticleData(ParticleID::g),scale,x);
pdf[3]=_beams[1]->pdf()->xfx(_beams[1],_partons[1],scale,y);
res =- 1./2./pi*(sqr(th-m2)+sqr(sh-m2))*pt/(sh*sh*th)*GeV;
}
//deals with pdf zero issue at large x
if(pdf[0]<=0.||pdf[1]<=0.||pdf[2]<=0.||pdf[3]<=0.) {
res=0.;
}
else {
res*=pdf[2]*pdf[3]/pdf[0]/pdf[1]*m2/sh;
}
res*=_alpha->ratio(sqr(pt));
return res;
}
bool DrellYanBase::getEvent(vector<Lorentz5Momentum> & pnew,
int & emis_type){
// pt cut-off
// Energy minp = 0.1*GeV;
// maximum pt (half of centre-of-mass energy)
Energy maxp = 0.5*generator()->maximumCMEnergy();
// set pt of emission to zero
_pt=ZERO;
//Working Variables
Energy pt;
double yj;
// limits on the rapidity of the jet
double minyj = -8.0,maxyj = 8.0;
bool reject;
double wgt;
emis_type=-1;
for(int j=0;j<3;j++) {
pt=maxp;
double a = _alpha->overestimateValue()*_prefactor[j]*(maxyj-minyj)/(_power-1.);
do {
// generate next pt
pt=GeV/pow(pow(GeV/pt,_power-1)-log(UseRandom::rnd())/a,1./(_power-1.));
// generate rapidity of the jet
yj=UseRandom::rnd()*(maxyj-minyj)+ minyj;
// calculate rejection weight
wgt=getResult(j,pt,yj);
wgt/= _prefactor[j]*pow(GeV/pt,_power);
reject = UseRandom::rnd()>wgt;
//no emission event if p goes past p min - basically set to outside
//of the histogram bounds (hopefully hist object just ignores it)
if(pt<_min_pt){
pt=ZERO;
reject = false;
}
if(wgt>1.0) {
ostringstream s;
s << "DrellYanBase::getEvent weight for channel " << j
<< "is " << wgt << " which is greater than 1";
generator()->logWarning( Exception(s.str(), Exception::warning) );
}
}
while(reject);
// set pt of emission etc
if(pt>_pt){
emis_type = j;
_pt=pt;
_yj=yj;
}
}
//was this an (overall) no emission event?
if(_pt<_min_pt){
_pt=ZERO;
emis_type = 3;
}
if(emis_type==3) return false;
// generate the momenta of the particles
// hadron-hadron cmf
Energy2 s=sqr(generator()->maximumCMEnergy());
// transverse energy
Energy2 m2(sqr(_mass));
Energy et=sqrt(m2+sqr(_pt));
// first calculate all the kinematic variables
// longitudinal real correction fractions
double x = _pt*exp( _yj)/sqrt(s)+et*exp( _yb)/sqrt(s);
double y = _pt*exp(-_yj)/sqrt(s)+et*exp(-_yb)/sqrt(s);
// that and uhat
Energy2 th = -sqrt(s)*x*_pt*exp(-_yj);
Energy2 uh = -sqrt(s)*y*_pt*exp( _yj);
Energy2 sh = x*y*s;
if(emis_type==1) swap(th,uh);
// decide which was the emitting particle
unsigned int iemit=1;
// from q qbar
if(emis_type==0) {
if(UseRandom::rnd()<sqr(m2-uh)/(sqr(m2-uh)+sqr(m2-th))) iemit=2;
}
else {
if(UseRandom::rnd()<sqr(m2-th)/(sqr(m2-th)+sqr(m2-sh))) iemit=2;
}
// reconstruct the momenta in the rest frame of the gauge boson
Lorentz5Momentum pb(ZERO,ZERO,ZERO,_mass,_mass),pspect,pg,pemit;
double cos3;
if(emis_type==0) {
pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(sh-m2)/_mass,ZERO);
Energy2 tp(th),up(uh);
double zsign(_quarkplus ? -1. : 1.);
if(iemit==2) {
swap(tp,up);
zsign *= -1.;
}
pspect = Lorentz5Momentum(ZERO,ZERO
,zsign*0.5*(m2-tp)/_mass,0.5*(m2-tp)/_mass,
ZERO);
Energy eemit=0.5*(m2-up)/_mass;
cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
}
else {
pg=Lorentz5Momentum(ZERO,ZERO,ZERO,0.5*(m2-uh)/_mass,ZERO);
double zsign(_quarkplus ? 1. : -1.);
if(iemit==1) {
if(emis_type==1) zsign *= -1.;
pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(sh-m2)/_mass,0.5*(sh-m2)/_mass);
Energy eemit=0.5*(m2-th)/_mass;
cos3 = 0.5/pspect.z()/pg.e()*(sqr(pspect.e())+sqr(pg.e())-sqr(eemit));
}
else {
if(emis_type==2) zsign *= -1.;
pspect=Lorentz5Momentum(ZERO,ZERO,0.5*zsign*(m2-th)/_mass,0.5*(m2-th)/_mass);
Energy eemit=0.5*(sh-m2)/_mass;
cos3 = 0.5/pspect.z()/pg.e()*(-sqr(pspect.e())-sqr(pg.e())+sqr(eemit));
}
}
// rotate the gluon
double sin3(sqrt(1.-sqr(cos3))),phi(Constants::twopi*UseRandom::rnd());
pg.setX(pg.e()*sin3*cos(phi));
pg.setY(pg.e()*sin3*sin(phi));
pg.setZ(pg.e()*cos3);
if(emis_type==0) {
pemit=pb+pg-pspect;
}
else {
if(iemit==1) pemit=pb+pspect-pg;
else pemit=pspect+pg-pb;
}
pemit .setMass(ZERO);
pg .setMass(ZERO);
pspect.setMass(ZERO);
// find the new CMF
Lorentz5Momentum pp[2];
if(emis_type==0) {
pp[0]=pemit;
pp[1]=pspect;
if(iemit==2) swap(pp[0],pp[1]);
}
else if(emis_type==1) {
pp[1]=pg;
if(iemit==1) pp[0]=pemit;
else pp[0]=pspect;
}
else {
pp[0]=pg;
if(iemit==1) pp[1]=pemit;
else pp[1]=pspect;
}
Lorentz5Momentum pz= _quarkplus ? pp[0] : pp[1];
pp[0]/=x;
pp[1]/=y;
Lorentz5Momentum plab(pp[0]+pp[1]);
plab.rescaleMass();
// construct the boost to rest frame of plab
LorentzRotation trans=LorentzRotation(plab.findBoostToCM());
pz.transform(trans);
// rotate so emitting particle along z axis
// rotate so in x-z plane
trans.rotateZ(-atan2(pz.y(),pz.x()));
// rotate so along
trans.rotateY(-acos(pz.z()/pz.vect().mag()));
// undo azimuthal rotation
trans.rotateZ(atan2(pz.y(),pz.x()));
// perform the transforms
pb .transform(trans);
pspect.transform(trans);
pg .transform(trans);
pemit .transform(trans);
// copy the momenta for the new particles
pnew.resize(4);
if(emis_type==0) {
pnew[0]=pemit;
pnew[1]=pspect;
if(iemit==2) swap(pnew[0],pnew[1]);
pnew[2]=pg;
}
else if(emis_type==1) {
pnew[0]=pemit;
pnew[2]=pspect;
if(iemit==2) swap(pnew[0],pnew[2]);
pnew[1]=pg;
}
else if(emis_type==2) {
pnew[1]=pspect;
pnew[2]=pemit;
if(iemit==1) swap(pnew[1],pnew[2]);
pnew[0]=pg;
}
pnew[3]=pb;
return true;
}
diff --git a/MatrixElement/DrellYanBase.h b/MatrixElement/DrellYanBase.h
--- a/MatrixElement/DrellYanBase.h
+++ b/MatrixElement/DrellYanBase.h
@@ -1,314 +1,315 @@
// -*- C++ -*-
#ifndef HERWIG_DrellYanBase_H
#define HERWIG_DrellYanBase_H
//
// This is the declaration of the DrellYanBase class.
//
#include "HwMEBase.h"
#include "Herwig/Shower/ShowerAlpha.h"
namespace Herwig {
using namespace ThePEG;
/**
* The DrellYanBase class class provides a base class for the implemented
* of Drell-Yan type processes and provides the matrix element and POWHEG
* style hard corrections
*
* @see \ref DrellYanBaseInterfaces "The interfaces"
* defined for DrellYanBase.
*/
class DrellYanBase: public HwMEBase {
public:
/**
* The default constructor.
*/
DrellYanBase();
/**
* Has a POWHEG style correction
*/
//virtual bool hasPOWHEGCorrection() {return _alpha;}
virtual POWHEGType hasPOWHEGCorrection() {return ISR;}
/**
* Has an old fashioned ME correction
*/
virtual bool hasMECorrection() {return _alpha;}
/**
* Initialize the ME correction
*/
virtual void initializeMECorrection(RealEmissionProcessPtr, double & initial,
double & final) {
final = 1.;
initial = 1.;
}
/**
* Apply the hard matrix element correction to a given hard process or decay
*/
virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(RealEmissionProcessPtr);
/**
* Apply the soft matrix element correction
* @param parent The initial particle in the current branching
* @param progenitor The progenitor particle of the jet
* @param fs Whether the emission is initial or final-state
* @param highestpT The highest pT so far in the shower
* @param ids ids of the particles produced in the branching
* @param z The momentum fraction of the branching
* @param scale the evolution scale of the branching
* @param pT The transverse momentum of the branching
* @return If true the emission should be vetoed
*/
virtual bool softMatrixElementVeto(PPtr parent,
PPtr progenitor,
const bool & fs,
const Energy & highestpT,
const vector<tcPDPtr> & ids,
const double & z,
const Energy & scale,
const Energy & pT);
/**
* Apply the POWHEG style correction
*/
virtual RealEmissionProcessPtr generateHardest(RealEmissionProcessPtr,
ShowerInteraction);
/**
* Set the typed and momenta of the incoming and outgoing partons to
* be used in subsequent calls to me() and colourGeometries()
* according to the associated XComb object.
*/
virtual void setKinematics() {
HwMEBase::setKinematics();
mb2_ = sHat();
}
protected:
/**
* Return the momenta and type of hard matrix element correction
* @param quarks The original incoming particles.
* @param beams The BeamParticleData objects
* @param boson The momentum of the original outgoing gauge boson
* @param iemit Whether the first (0) or second (1) particle emitted
* the radiation
* @param itype The type of radiated particle (0 is gluon, 1 is quark
* and 2 is antiquark)
* @param pnew The momenta of the new particles
* @param trans The LorentzRotation from the boson rest frame to the new lab
* @param xnew The new values of the momentuym fractions
* @return Whether or not the matrix element correction needs to be applied
*/
bool applyHard(ParticleVector & quarks,
vector<tcBeamPtr> beams,
Lorentz5Momentum boson,unsigned int & iemit,
unsigned int & itype,vector<Lorentz5Momentum> & pnew,
- LorentzRotation & trans, pair<double,double> & xnew);
+ LorentzRotation & trans, pair<double,double> & xnew,
+ Energy2 shad);
/**
* Returns the matrix element for a given type of process,
* rapidity of the jet \f$y_j\f$ and transverse momentum \f$p_T\f$
* @param emis_type the type of emission,
* (0 is \f$q\bar{q}\to Vg\f$, 1 is \f$qg\to Vq\f$ and 2 is \f$g\bar{q}\to V\bar{q}\f$)
* @param pt The transverse momentum of the jet
* @param yj The rapidity of the jet
*/
double getResult(int emis_type, Energy pt, double yj);
/**
* generates the hardest emission (yj,p)
* @param pnew The momenta of the new particles
* @param emissiontype The type of emission, as for getResult
* @return Whether not an emission was generated
*/
bool getEvent(vector<Lorentz5Momentum> & pnew,int & emissiontype);
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();
/**
* Finalize this object. Called in the run phase just after a
* run has ended. Used eg. to write out statistics.
*/
virtual void dofinish();
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
DrellYanBase & operator=(const DrellYanBase &);
private:
/**
* Mass squared of the vector boson
*/
Energy2 mb2_;
/**
* Parameters for the old-style ME correction
*/
//@{
/**
* Relative weight for the \f$q\bar{q}\f$ and \f$q/\bar{q}g\f$ channels
*/
double _channelwgtA;
/**
* Relative weight for the \f$qg\f$ and \f$\bar{q}g\f$ channels
*/
double _channelwgtB;
/**
* Weights for the channels as a vector
*/
vector<double> _channelweights;
/**
* Number of weights greater than 1
*/
unsigned int _nover;
/**
* Maximum weight
*/
double _maxwgt;
//@}
/**
* Constants for the sampling. The distribution is assumed to have the
* form \f$\frac{c}{{\rm GeV}}\times\left(\frac{{\rm GeV}}{p_T}\right)^n\f$
*/
//@{
/**
* The power, \f$n\f$, for the sampling
*/
double _power;
/**
* The prefactor, \f$c\f$ for the \f$q\bar{q}\f$ channel
*/
double _preqqbar;
/**
* The prefactor, \f$c\f$ for the \f$qg\f$ channel
*/
double _preqg;
/**
* The prefactor, \f$c\f$ for the \f$g\bar{q}\f$ channel
*/
double _pregqbar;
/**
* The prefactors as a vector for easy use
*/
vector<double> _prefactor;
//@}
/**
* Properties of the incoming particles
*/
//@{
/**
* Pointers to the BeamParticleData objects
*/
vector<tcBeamPtr> _beams;
/**
* Pointers to the ParticleDataObjects for the partons
*/
vector<tcPDPtr> _partons;
//@}
/**
* Properties of the boson and jets
*/
//@{
/**
* The rapidity of the gauge boson
*/
double _yb;
/**
* The mass of the gauge boson
*/
Energy _mass;
/**
* Whether the quark is in the + or - z direction
*/
bool _quarkplus;
/**
* the rapidity of the jet
*/
double _yj;
/**
* The transverse momentum of the jet
*/
Energy _pt;
//@}
/**
* The transverse momentum of the jet
*/
Energy _min_pt;
/**
* Pointer to the object calculating the strong coupling
*/
ShowerAlphaPtr _alpha;
};
}
#endif /* HERWIG_DrellYanBase_H */
diff --git a/MatrixElement/EW/CollinearSudakov.h b/MatrixElement/EW/CollinearSudakov.h
--- a/MatrixElement/EW/CollinearSudakov.h
+++ b/MatrixElement/EW/CollinearSudakov.h
@@ -1,541 +1,546 @@
// -*- C++ -*-
#ifndef Herwig_CollinearSudakov_H
#define Herwig_CollinearSudakov_H
//
// This is the declaration of the CollinearSudakov class.
//
#include "ThePEG/Interface/Interfaced.h"
#include "Herwig/Utilities/GSLIntegrator.h"
+// work around a Boost 1.64 bug where ublas headers would fail otherwise
+#include <boost/version.hpp>
+#if (BOOST_VERSION / 100 >= 1064)
+#include <boost/serialization/array_wrapper.hpp>
+#endif
#include <boost/numeric/ublas/matrix.hpp>
#include "EWProcess.h"
#include "CollinearSudakov.fh"
namespace Herwig {
using namespace ThePEG;
/**
* Struct for the wavefunction corrections
*/
struct WaveFunctionCorrections {
Complex RW;
Complex RA;
Complex RZ;
Complex RAtoZ;
Complex RZtoA;
Complex RPhi;
Complex EW;
Complex EZ;
Complex RPhi3;
Complex RH;
Complex tLuLDiff;
Complex bLdLDiff;
Complex tRuRDiff;
// The following are constants from parameter integrals:
Complex fFW0;
Complex fF0W;
Complex fFZZ;
Complex aHH;
Complex aZZ;
Complex aW0;
Complex a0W;
Complex bHH;
Complex bZZ;
Complex cHH;
Complex cZZ;
Complex cW0;
Complex atHH;
Complex atZZ;
Complex atW0;
Complex at0W;
Complex ctHH;
Complex ctZZ;
Complex ctW0;
Complex btHH;
Complex btZZ;
Complex fs10;
Complex fs1ZW;
Complex fsWZWZ;
Complex fsZW1;
Complex fs01;
Complex fsHW1;
Complex fsHZ1;
Complex fs1HW;
Complex fs1HZ;
};
/**
* Here is the documentation of the CollinearSudakov class.
*
* @see \ref CollinearSudakovInterfaces "The interfaces"
* defined for CollinearSudakov.
*/
class CollinearSudakov: public Interfaced {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
CollinearSudakov();
/**
* The destructor.
*/
virtual ~CollinearSudakov();
//@}
public:
/**
* Evalaute the electroweak matching as a matrix
*/
boost::numeric::ublas::matrix<Complex>
electroWeakMatching(Energy EWScale, Energy2 s,
Herwig::EWProcess::Process process,
bool oneLoop);
/**
* Evalaute the high energy running as a matrix
*/
boost::numeric::ublas::matrix<Complex>
highEnergyRunning(Energy highScale, Energy EWScale, Energy2 s,
Herwig::EWProcess::Process process,
bool fixedOrder);
/**
* Evaluate the low energy running as a matrix
*/
boost::numeric::ublas::matrix<Complex>
lowEnergyRunning(Energy EWScale, Energy lowScale, Energy2 s,
Herwig::EWProcess::Process process);
public:
/**
* Make plots for tests
*/
void makePlots();
protected:
/**
* Evaluate the high scale contributions
*/
void evaluateHighScale(Energy highScale, Energy EWScale, Energy2 S);
/**
* Evaluate the low scale contributions
*/
void evaluateLowScale(Energy EWScale, Energy lowScale, Energy2 S);
/**
* Evaluate the matching
*/
void evaluateMatching(Energy EWScale,Energy2 S);
public:
/**
* The operator to be integrated
*/
InvEnergy operator ()(Energy mu) const {
if(high_) return highScaleIntegrand(mu);
else return lowScaleIntegrand(mu);
}
/** Argument type for GaussianIntegrator */
typedef Energy ArgType;
/** Return type for GaussianIntegrator */
typedef InvEnergy ValType;
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/**
* The integral of the high scale part of the Sudakov
*/
Complex highScaleIntegral(bool SU3, bool SU2, double Y,
Energy2 s, Energy mu_h, Energy mu_l, bool fermion,
bool longitudinal, double yukFactor);
/**
* the integral of the low scale part of the Sudakov
*/
Complex lowScaleIntegral(bool SU3, double Q, Energy2 s,
Energy mu_h, Energy mu_l, bool fermion,
double boostFactor);
protected:
/**
* High-scale integrand
*/
InvEnergy highScaleIntegrand(Energy mu) const;
/**
* Low-scale integrand
*/
InvEnergy lowScaleIntegrand(Energy mu) const;
/**
* Calculate the wavefunction corrections
*/
WaveFunctionCorrections waveFunctionCorrections(Energy EWScale);
/**
* Collinear matiching for W
*/
Complex CollinearDw(Energy2 s, Energy EWScale);
/**
* Collinear matching for Z
*/
Complex CollinearDz(Energy2 s, Energy EWScale);
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
CollinearSudakov & operator=(const CollinearSudakov &);
private:
/**
* Parameters for the integrand
*/
//@{
/**
* Whether high or low scale
*/
bool high_;
/**
* Whether real of imaginary part
*/
bool real_;
/**
* \f$SU(3)\f$
*/
bool SU3_;
/**
*
*/
bool SU2_;
/**
*
*/
double Y_;
/**
*
*/
Energy2 s_;
/**
*
*/
bool fermion_;
/**
*
*/
bool longitudinal_;
/**
*
*/
double yukFactor_;
/**
*
*/
double boostFactor_;
/**
*
*/
double Q_;
//@}
/**
* Parameters
*/
//@{
/**
* Order for the K terms
*/
int K_ORDER_;
/**
* Order for the B terms
*/
int B_ORDER_;
//@}
/**
* Integrator
*/
GSLIntegrator integrator_;
private:
/**
* Storage of the high scale pieces
*/
//@{
/**
*
*/
Complex highColW_;
/**
*
*/
Complex highColB_;
/**
*
*/
Complex highColG_;
/**
*
*/
Complex highColQ_;
/**
*
*/
Complex highColQt_;
/**
*
*/
Complex highColU_;
/**
*
*/
Complex highColtR_;
/**
*
*/
Complex highColD_;
/**
*
*/
Complex highColL_;
/**
*
*/
Complex highColE_;
/**
*
*/
Complex highColPhi_;
//@}
/**
* Storage of the low scale pieces
*/
//@{
/**
*
*/
complex<double> lowColW_;
/**
*
*/
Complex lowColA_;
/**
*
*/
Complex lowColG_;
/**
*
*/
Complex lowColU_;
/**
*
*/
Complex lowColt_;
/**
*
*/
Complex lowColD_;
/**
*
*/
Complex lowColE_;
//@}
/**
* Storage of the matching parameters
*/
//@{
/**
*
*/
Complex ULcollinearCorr_;
/**
*
*/
Complex DLcollinearCorr_;
/**
*
*/
Complex URcollinearCorr_;
/**
*
*/
Complex DRcollinearCorr_;
/**
*
*/
Complex tLcollinearCorr_;
/**
*
*/
Complex tRcollinearCorr_;
/**
*
*/
Complex bLcollinearCorr_;
/**
*
*/
Complex nuLcollinearCorr_;
/**
*
*/
Complex ELcollinearCorr_;
/**
*
*/
Complex ERcollinearCorr_;
/**
*
*/
Complex WtoWcollinearCorr_;
/**
*
*/
Complex WtoZcollinearCorr_;
/**
*
*/
Complex WtoAcollinearCorr_;
/**
*
*/
Complex BtoZcollinearCorr_;
/**
*
*/
Complex BtoAcollinearCorr_;
/**
*
*/
Complex PhitoWcollinearCorr_;
/**
*
*/
Complex PhitoZcollinearCorr_;
/**
*
*/
Complex PhitoHcollinearCorr_;
/**
*
*/
Complex GcollinearCorr_;
//@}
};
}
#endif /* Herwig_CollinearSudakov_H */
diff --git a/MatrixElement/EW/EWCouplings.h b/MatrixElement/EW/EWCouplings.h
--- a/MatrixElement/EW/EWCouplings.h
+++ b/MatrixElement/EW/EWCouplings.h
@@ -1,473 +1,478 @@
// -*- C++ -*-
#ifndef Herwig_EWCouplings_H
#define Herwig_EWCouplings_H
//
// This is the declaration of the EWCouplings class.
//
#include "ThePEG/Interface/Interfaced.h"
+// work around a Boost 1.64 bug where ublas headers would fail otherwise
+#include <boost/version.hpp>
+#if (BOOST_VERSION / 100 >= 1064)
+#include <boost/serialization/array_wrapper.hpp>
+#endif
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include "EWCouplings.fh"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the EWCouplings class.
*
* @see \ref EWCouplingsInterfaces "The interfaces"
* defined for EWCouplings.
*/
class EWCouplings: public Interfaced {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
EWCouplings(unsigned int loops=2, unsigned int steps=200, Energy lowScale=10.*GeV);
/**
* The destructor.
*/
virtual ~EWCouplings();
//@}
/**
* Initialize the running couplings
*/
void initialize();
/**
* Number of dynamical quarks at $\log\mu = x$ (in GeV)
* N.B.Integrate out top quark at Mz, not at Mt.
*/
unsigned int numberOfFlavours(double x) {
return x >= std::log(ewScale_/GeV) ? 6 : 5;
}
public:
/**
* Set whether or not to include \f$SU(3)\f$ running
*/
void SU3(bool includeSU3) {includeSU3_ = includeSU3;}
/**
* Whether or not to include \f$SU(3)\f$ running
*/
bool SU3() { return includeSU3_;}
/**
* Set whether or not to include EW running
*/
void EW(bool includeEW) {includeEW_ = includeEW;}
/**
* Whether or not to include EW running
*/
bool EW() { return includeEW_;}
/**
* alpha for the U1 gauge coupling at energy mu (in GeV):
*/
double a1(Energy mu) {
if (includeEW_) {
if (mu>=ewScale_) {
return (3.0/5.0)*interpolate(log(mu/GeV),1);
}
return interpolateLow(log(mu/GeV),1);
}
else
return 0.0;
}
/**
* alpha for the SU2 gauge coupling at energy mu (in GeV):
*/
double a2(Energy mu) {
if (includeEW_) {
if (mu<ewScale_) {
return 0.0;
}
else
return interpolate(log(mu/GeV),2);
}
else
return 0.0;
}
/**
* alpha for the SU3 gauge coupling at energy mu (in GeV):
*/
double a3(Energy mu) {
if(includeSU3_) {
if (mu>=ewScale_) {
return interpolate(log(mu/GeV),3);
}
else {
return interpolateLow(log(mu/GeV),2);
}
}
else
return 0.0;
}
/**
* alpha for EM
*/
double aEM(Energy mu) {
if (includeEW_) {
if (mu<=ewScale_) {
return interpolateLow(log(mu/GeV),1);
}
else {
double alpha1=a1(mu);
double alpha2=a2(mu);
return alpha1*alpha2/(alpha1+alpha2);
}
}
return 0.0;
}
double aS(Energy mu) {
if(includeSU3_) {
if (mu<=ewScale_) {
return interpolateLow(log(mu/GeV),2);
}
else {
return interpolate(log(mu/GeV),3);
}
}
else return 0.0;
}
/**
* Top quark Yukawa coupling
*/
double y_t(Energy mu) {
if (includeEW_) {
if(mu<ewScale_)
return 0.0;
else
return interpolate(log(mu/GeV),4);
}
else
return 0.0;
}
/**
* Quartic scalar coupling lambda (normalization different, hence factor of 2):
*/
double lambda(Energy mu) {return 2.0*interpolate(log(mu/GeV),5);}
/**
* VEV
*/
Energy vev(Energy mu) {return interpolate(log(mu/GeV),6)*GeV;}
/**
* \f$\lambda_t\f$
*/
double lambda_t(Energy mu) {return y_t(mu);}
/**
* Z couplings
*/
//@{
double g_Lu(Energy mu) {return 0.5-(2.0/3.0)*Sin2thW(mu);}
double g_Ld(Energy mu) {return -0.5+(1.0/3.0)*Sin2thW(mu);}
double g_Le(Energy mu) {return (-1.0/2.0)+Sin2thW(mu);}
double g_Lnu(Energy ) {return (0.5);}
double g_Ru(Energy mu) {return (-2.0/3.0)*Sin2thW(mu);}
double g_Rd(Energy mu) {return (1.0/3.0)*Sin2thW(mu);}
double g_Re(Energy mu) {return Sin2thW(mu);}
double g_W(Energy mu) {return Cos2thW(mu);}
double g_phiPlus(Energy mu) {return 0.5-Sin2thW(mu);}
//@}
/**
* \f\cos^2\theta_W\f$
*/
double Cos2thW(Energy ) {
//\todo why this value?
//return mW()*mW()/(mZ()*mZ());
return (1.-0.2314);
}
/**
* \f\sin^2\theta_W\f$
*/
double Sin2thW(Energy mu) {return 1.-Cos2thW(mu);}
double aW(Energy mu) {return a2(mu);}
double aZ(Energy mu) {
//return a2(mu)/Cos2thW(mu); // Same thing, actually
return a1(mu)+a2(mu);
}
public:
/**
* Masses of the Standard Model particles
*/
//@{
/**
* Z mass
*/
Energy mZ() const { return mZ_;}
/**
* W Mass
*/
Energy mW() const { return mW_;}
/**
* Top quark mass
*/
Energy mT() const {return mT_;}
Energy mTatmZ() { return mT_;}
/**
* Higg boson mass
*/
Energy mH() const {return mH_;}
//@}
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:
/**
* Set the initial value of the couplings
*/
void initializeCouplings(vector<Complex> & y);
/**
* Assigns numerical values to beta functions
* Takes in a point x = log(mu) and the values of y[i] at x and assigns dydx[i] the
* value beta[i](mu). The function Derivs farms out the plugging in to the three
* functions BetaGauge, BetaYukawa, and BetaHiggs, which evaluates the beta functions
* for the gauge couplings, yukawa matrices, and higgs quartic coupling/vev, respectively.
*/
void derivatives(const double x, vector< Complex > &y,
vector< Complex > & dydx);
/**
* Beta function for the gauge interactions
*/
void betaGauge(const double x, vector<Complex> &y, vector<Complex> &dydx);
/**
* Beta function for the gauge interactions at low scales
*/
void lowBetaGauge(const double x, vector<Complex> &y, vector<Complex> &dydx);
/**
* Beta function for the Yukawa interactions
*/
void betaYukawa(const double x, vector<Complex> &y, vector<Complex> &dydx);
/**
* Beta function for the Higgs interactions
*/
void betaHiggs(const double x, vector<Complex> &y, vector<Complex> &dydx);
/**
* Update the couplings using 4-th order RK
* Takes in a vector y[i] of function values at a point x and the values of the
* first derivatives dydx[i] ( = dy[i]/dx ) alon with a step size stepsize. The
* function then defines assigns the value of y[i](x+stepsize) to the variable yout[i].
* (Adapted from sample code in Numerical Recipes in C++ Press, Teukolsky, et. al.)
*/
void RK4(vector<Complex> & y, vector<Complex> &dydx, const double x,
const double stepsize, vector<Complex> &yout);
/**
* Initialize the low energy parameters
*/
void initializeLow();
/**
* Interpolate the table, t = ln(mu)
*/
double interpolate(double t, int paramIndex);
/**
* Interpolate the tabel, t = ln(mu)
*/
double interpolateLow(double t, int paramIndex);
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
EWCouplings & operator=(const EWCouplings &);
private:
/**
* Electoweak Scale
*/
Energy ewScale_;
/**
* High Scale
*/
Energy highScale_;
/**
* Low Scale
*/
Energy lowScale_;
/**
* Whether or not to include SU3
*/
bool includeSU3_;
/**
* Whether or not to include EW
*/
bool includeEW_;
/**
* Whether or not the running couplings have been initialized
*/
bool initialized_;
/**
* Masses of Standard Model particles
*/
//@{
/**
* Mass Choice
*/
bool massChoice_;
/**
* Z mass
*/
Energy mZ_;
/**
* W mass
*/
Energy mW_;
/**
* Top mass
*/
Energy mT_;
/**
* Higgs boson mass
*/
Energy mH_;
//@}
/**
* Number of loops
*/
unsigned int loops_;
/**
* Number of steps for Runga-Kutta (High scale)
*/
unsigned int highSteps_;
/**
* Number of steps for Runga-Kutta (Low scale)
*/
unsigned int lowSteps_;
/**
* Matrix to store the parameters
*/
boost::numeric::ublas::matrix<double> table_;
/**
* Matrix to store the low energy parameters.
* This will hold only aEM and a3 at mu<ewScale
*/
boost::numeric::ublas::matrix<double> lowTable_;
/**
* Input values of the couplings
*/
//@{
/**
* \f%\alpha_1(M_Z)\f$
*/
double a1MZ_;
/**
* \f%\alpha_2(M_Z)\f$
*/
double a2MZ_;
/**
* \f%\alpha_S(M_Z)\f$
*/
double aSMZ_;
/**
* \f$\lambda_t\f$
*/
double lambdat_;
//@}
};
}
#endif /* Herwig_EWCouplings_H */
diff --git a/MatrixElement/EW/ElectroWeakMatching.h b/MatrixElement/EW/ElectroWeakMatching.h
--- a/MatrixElement/EW/ElectroWeakMatching.h
+++ b/MatrixElement/EW/ElectroWeakMatching.h
@@ -1,32 +1,37 @@
// -*- C++ -*-
//
// ElectroWeakMatching.h is a part of Herwig - A multi-purpose Monte Carlo event generator
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
//
#ifndef HERWIG_ElectroWeakMatching_H
#define HERWIG_ElectroWeakMatching_H
#include "ThePEG/Config/ThePEG.h"
#include "ThePEG/Config/Unitsystem.h"
#include "EWProcess.h"
+// work around a Boost 1.64 bug where ublas headers would fail otherwise
+#include <boost/version.hpp>
+#if (BOOST_VERSION / 100 >= 1064)
+#include <boost/serialization/array_wrapper.hpp>
+#endif
#include <boost/numeric/ublas/matrix.hpp>
namespace Herwig {
using namespace ThePEG;
namespace ElectroWeakMatching {
/**
* The high energy matching
*/
boost::numeric::ublas::matrix<Complex>
electroWeakMatching(Energy mu, Energy2 s, Energy2 t, Energy2 u,
Herwig::EWProcess::Process process,
bool oneLoop,unsigned int iswap);
}
}
#endif // HERWIG_ElectroWeakMatching_H
diff --git a/MatrixElement/EW/GroupInvariants.h b/MatrixElement/EW/GroupInvariants.h
--- a/MatrixElement/EW/GroupInvariants.h
+++ b/MatrixElement/EW/GroupInvariants.h
@@ -1,495 +1,500 @@
// -*- C++ -*-
//
// GroupInvariants.h is a part of Herwig - A multi-purpose Monte Carlo event generator
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
//
#ifndef HERWIG_GroupInvariants_H
#define HERWIG_GroupInvariants_H
#include "ThePEG/Config/ThePEG.h"
#include "ThePEG/Config/Unitsystem.h"
#include <cassert>
+// work around a Boost 1.64 bug where ublas headers would fail otherwise
+#include <boost/version.hpp>
+#if (BOOST_VERSION / 100 >= 1064)
+#include <boost/serialization/array_wrapper.hpp>
+#endif
#include <boost/numeric/ublas/matrix.hpp>
namespace Herwig {
using namespace ThePEG;
namespace GroupInvariants {
/**
* Simple struct for storing the different gauge contributions
*/
struct GaugeContributions {
/**
* Default Constructor
*/
GaugeContributions(double inSU3=0.,
double inSU2=0., double inU1=0.)
: SU3(inSU3),SU2(inSU2),U1(inU1)
{}
/**
* \f$SU(3)\f$
*/
double SU3;
/**
* \f$SU(2)\f$
*/
double SU2;
/**
* \f$U(1)\f$
*/
double U1;
};
/**
* The \f$SU(N)\f$ \f$C_A\f$
*/
inline double C_A(unsigned int N) {
return N !=1 ? double(N) : 0.;
}
/**
* The \f$SU(N)\f$ \f$C_F\f$
*/
inline double C_F(unsigned int N) {
return N !=1 ? 0.5*(double(N*N)-1.)/double(N) : 1.;
}
/*
* The \f$SU(N)\f$ \f$C_d\f$
*/
inline double C_d(unsigned int N) {
return (double(N*N)-4.)/double(N);
}
/**
* The \f$SU(N)\f$\f$C_1\f$
*/
inline double C_1(unsigned int N) {
double N2(N*N);
return 0.25*(N2-1.0)/N2;
}
/**
* \f$T_F\f$
*/
inline double T_F(unsigned int N, bool high) {
if(high) {
return N !=1 ? 0.5 : 5.0/3.0;
}
else {
return N !=1 ? 0.5 : 20.0/3.0;
}
}
/**
* \f$t_S\f$
*/
inline double t_S(unsigned int, bool ) {
return 0.5;
}
/**
* / Number of complex scalars in the fundamental rep. of SU(N)/U(1)
*/
inline double n_S(unsigned int N, bool high) {
if(high) {
if(N==2 || N==1) return 1.0;
else if(N==3) return 0.0;
else assert(false);
}
else {
if(N>=1&&N<=3) return 0.;
else assert(false);
}
}
/**
* Number of Dirac Fermions in the fund. rep. of SU(N) (or U(1) for N==1)
*/
inline double n_F(unsigned int N, bool high) {
if(high) {
if(N==1) return 3.0;
else if(N==2 || N==3) return 6.0;
else assert(false);
}
else {
if(N==1) return 1.0;
else if(N==2) return 0.0;
else if(N==3) return 5.0;
else assert(false);
}
}
/**
* Find K_i for gauge group N. high=false for running at mu<mZ
*/
double K_Factor(unsigned int i,unsigned int N, bool high);
/**
* Find B_i for gauge group N, high energy
*/
double B_Factor(int i, int N, bool fermion, bool longitudinal);
/**
* Find B_i for gauge group N, low energy
*/
double B_Factor_Low(int i, int N, bool fermion, double boostFactor);
/**
* Contributions to the Cusps
*/
GaugeContributions cuspContributions(Energy mu, int K_ORDER, bool high);
/**
* Contributions to B, high energy
*/
GaugeContributions BContributions(Energy mu, int B_ORDER,
bool fermion, bool longitudinal);
/**
* Contributions to B, low energy
*/
GaugeContributions BContributionsLow(Energy mu, int B_ORDER,
bool fermion, double boostFactor);
inline Complex PlusLog(double arg) {
static const Complex I(0,1.0);
if (arg>0.0)
return log(arg);
else if (arg<0.0)
return log(-arg)+I*Constants::pi;
else
assert(false);
}
inline Complex MinusLog(double arg) {
static const Complex I(0,1.0);
if (arg>0.0)
return log(arg);
else if (arg<0.0)
return log(-arg)-I*Constants::pi;
else
assert(false);
}
inline Complex getT(Energy2 s, Energy2 t) {
return MinusLog(-t/GeV2) - MinusLog(-s/GeV2);
}
inline Complex getU(Energy2 s, Energy2 u) {
return MinusLog(-u/GeV2) - MinusLog(-s/GeV2);
}
inline boost::numeric::ublas::matrix<Complex> Gamma2(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = (-3.0/2.0)*I*pi + (T+U);
output(1,1) = (-3.0/2.0)*I*pi;
output(0,1) = 2.0*(T-U);
output(1,0) = (3.0/8.0)*(T-U);
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma2ST(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = 3./2.*(T-I*pi) + U -2.*T;
output(1,1) = 3./2.*(T-I*pi);
output(0,1) = -2.0*U;
output(1,0) = -(3.0/8.0)*U;
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma2SU(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = 3./2.*(U-I*pi) + T - 2.*U;
output(1,1) = 3./2.*(U-I*pi);
output(0,1) = 2.0*T;
output(1,0) = (3.0/8.0)*T;
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma2w(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output = boost::numeric::ublas::zero_matrix<Complex>(5,5);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) += -I*pi*11.0/4.0;
output(0,1) += U-T;
output(1,0) += 2.0*(U-T);
output(1,1) += -I*pi*11.0/4.0 + (T+U);
output(2,2) += -7.0/4.0*I*pi + (U+T);
output(3,3) += -7.0/4.0*I*pi + (U+T);
output(4,4) += -3.0/4.0*I*pi;
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma2Singlet() {
using namespace boost::numeric::ublas;
matrix<Complex> output = zero_matrix<Complex>(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = output(1,1) = -0.75*I*pi;
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma2SingletST(Complex T) {
using namespace boost::numeric::ublas;
matrix<Complex> output = zero_matrix<Complex>(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = output(1,1) = 0.75*(T-I*pi);
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma2SingletSU(Complex U) {
using namespace boost::numeric::ublas;
matrix<Complex> output = zero_matrix<Complex>(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = output(1,1) = 0.75*(U-I*pi);
return output;
}
inline Complex Gamma1(double hypercharge) {
Complex I(0,1.0);
return -I*Constants::pi*sqr(hypercharge);
}
inline Complex Gamma1ST(double hypercharge,Complex T) {
Complex I(0,1.0);
return (T-I*Constants::pi)*sqr(hypercharge);
}
inline Complex Gamma1SU(double hypercharge,Complex U) {
Complex I(0,1.0);
return (U-I*Constants::pi)*sqr(hypercharge);
}
inline Complex Gamma1(double y1, double y2, Complex T, Complex U) {
Complex I(0,1.0);
return -I*Constants::pi*(y1*y1+y2*y2) + 2.0*y1*y2*(T-U);
}
inline Complex Gamma1ST(double y1, double y2, Complex T, Complex U) {
Complex I(0,1.0);
return (T-I*Constants::pi)*(y1*y1+y2*y2) - 2.0*y1*y2*U;
}
inline Complex Gamma1SU(double y1, double y2, Complex T, Complex U) {
Complex I(0,1.0);
return (U-I*Constants::pi)*(y1*y1+y2*y2) + 2.0*y1*y2*T;
}
inline Complex Gamma1(double y1, double y2, double y3, double y4,
Complex T, Complex U) {
Complex I(0,1.0);
return -I*Constants::pi*(y1*y1+y2*y2+y3*y3+y4*y4)/2.0 +
(y1*y4+y2*y3)*T - (y1*y3+y2*y4)*U;
}
inline Complex Gamma1ST(double y1, double y2, double y3, double y4,
Complex T, Complex U) {
Complex I(0,1.0);
return (T-I*Constants::pi)*(y1*y1+y2*y2+y3*y3+y4*y4)/2.0 -
(y1*y4+y2*y3)*T - (y1*y3+y2*y4)*(U-T);
}
inline Complex Gamma1SU(double y1, double y2, double y3, double y4,
Complex T, Complex U) {
Complex I(0,1.0);
return (U-I*Constants::pi)*(y1*y1+y2*y2+y3*y3+y4*y4)/2.0 +
(y1*y4+y2*y3)*(T-U) + (y1*y3+y2*y4)*U;
}
inline boost::numeric::ublas::matrix<Complex> Gamma3(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output = boost::numeric::ublas::zero_matrix<Complex>(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = -(8.0/3.0)*I*pi;
output(1,1) = -(8.0/3.0)*I*pi;
output(0,0) += (7.0/3.0)*T + (2.0/3.0)*U;
output(0,1) = 2.0*(T-U);
output(1,0) = (4.0/9.0)*(T-U);
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma3ST(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output = boost::numeric::ublas::zero_matrix<Complex>(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = 8./3.*(T-I*pi);
output(1,1) = 8./3.*(T-I*pi);
output(0,0) += -3.*T + 2./3.*U;
output(0,1) = -2.*U;
output(1,0) = -4./9.*U;
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma3SU(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output = boost::numeric::ublas::zero_matrix<Complex>(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = 8./3.*(U-I*pi);
output(1,1) = 8./3.*(U-I*pi);
output(0,0) += 7./3.*T -3.*U;
output(0,1) = 2.*T;
output(1,0) = 4./9.*T;
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma3g(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output = boost::numeric::ublas::zero_matrix<Complex>(3,3);
static const Complex I(0,1.0);
using Constants::pi;
output(0,2) = U-T;
output(1,1) = 3.0/2.0*(T+U);
output(1,2) = 3.0/2.0*(U-T);
output(2,0) = 2.0*(U-T);
output(2,1) = 5.0/6.0*(U-T);
output(2,2) = 3.0/2.0*(T+U);
for (unsigned int i=0; i<3; i++) {
output(i,i) += -13.0/3.0*I*pi;
}
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma3gST(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output = boost::numeric::ublas::zero_matrix<Complex>(3,3);
static const Complex I(0,1.0);
using Constants::pi;
output(0,2) = U;
output(1,1) = 3.0/2.0*(U-2.*T);
output(1,2) = 3.0/2.0*U;
output(2,0) = 2.0*U;
output(2,1) = 5.0/6.0*U;
output(2,2) = 3.0/2.0*(U-2.*T);
for (unsigned int i=0; i<3; i++) {
output(i,i) += 13.0/3.0*(T-I*pi);
}
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma3gSU(Complex U, Complex T) {
boost::numeric::ublas::matrix<Complex> output = boost::numeric::ublas::zero_matrix<Complex>(3,3);
static const Complex I(0,1.0);
using Constants::pi;
output(0,2) = -T;
output(1,1) = 3./2.*(T-2.*U);
output(1,2) = -3./2.*T;
output(2,0) = -2.0*T;
output(2,1) =-5./6.*T;
output(2,2) = 3./2.*(T-2.*U);
for (unsigned int i=0; i<3; i++) {
output(i,i) += 13./3.*(U-I*pi);
}
return output;
}
inline boost::numeric::ublas::matrix<Complex> Gamma3Singlet() {
boost::numeric::ublas::matrix<Complex> output = boost::numeric::ublas::zero_matrix<Complex>(2,2);
static const Complex I(0,1.0);
using Constants::pi;
output(0,0) = output(1,1) = -4.0/3.0*I*pi;
return output;
}
/**
* Number of fermion generations (only used in gauge boson HighCMatching)
*/
inline double n_g() { return 3.0; }
/**
* Number of complex scalars in the fundamental rep. of SU(N)
*/
inline double nSWeyl(unsigned int N, bool high) {
if(high) {
if(N==2 || N==1) return 1.0;
else if (N==3) return 0.0;
else assert(false);
}
else {
if( N==1 || N==3 ) return 0.0;
else assert(false);
}
}
/**
* Number of Weyl Fermions in the fundamental rep. of SU(N)
*/
inline double nFWeyl(unsigned int N, bool high) {
if(high) {
if(N==2 || N==3) return 12.0;
else assert(false);
}
else {
if(N==3) return 10.0;
else if(N==1) return 2.0;
else assert(false);
}
}
inline double TFWeyl(unsigned int) {
return 0.5;
}
inline double tSWeyl(unsigned int) {
return 0.5;
}
inline Complex WFunction(Energy mu, Energy2 s) {
using Constants::pi;
assert(abs(s)>ZERO);
Complex ln = MinusLog(-s/(mu*mu));
return (-1.0*ln*ln + 3.0*ln+pi*pi/6.0-8.0);
}
/**
* \fX_N\f% function, v is either t or u
*/
inline Complex XNFunction(unsigned int N, Energy mu, Energy2 s, Energy2 v) {
using Constants::pi;
assert(abs(s)>ZERO);
Complex ls = MinusLog(-s/(mu*mu));
return (2.0*C_F(N)*WFunction(mu,s) +
C_A(N)*(2.0*ls*ls - 2.0*MinusLog((s+v)/(mu*mu))*ls -
11.0/3.0*ls + pi*pi + 85.0/9.0) +
(2.0/3.0*ls - 10.0/9.0) * TFWeyl(N) * nFWeyl(N,true) +
(1.0/3.0*ls - 8.0/9.0) * TFWeyl(N) * nSWeyl(N,true));
}
/**
* \f$\Pi_1\f$ function
*/
inline Complex PI1_function(Energy mu, Energy2 s) {
assert(abs(s)>ZERO);
return ((41.0/6.0)*MinusLog(-s/(mu*mu))-104.0/9.0);
}
/**
* \f$\tilde{f}\f$ function, v is either t or u
*/
inline Complex fTildeFunction(Energy mu, Energy2 s, Energy2 v) {
using Constants::pi;
assert(abs(s)>ZERO);
Complex ls = MinusLog(-s/GeV2), lv = MinusLog(-v/GeV2);
Complex lsv = MinusLog((s+v)/GeV2);
return (-2.0*double(s/(s+v))*(lv-ls) +
double(s*(s+2.0*v)/((s+v)*(s+v))) * ((lv-ls)*(lv-ls) + pi*pi) +
4.0*MinusLog(-s/(mu*mu))*(lv-lsv));
}
}
}
#endif // HERWIG_GroupInvariants_H
diff --git a/MatrixElement/EW/HighEnergyMatching.h b/MatrixElement/EW/HighEnergyMatching.h
--- a/MatrixElement/EW/HighEnergyMatching.h
+++ b/MatrixElement/EW/HighEnergyMatching.h
@@ -1,59 +1,64 @@
// -*- C++ -*-
//
// HighEnergyMatching.h is a part of Herwig - A multi-purpose Monte Carlo event generator
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
//
#ifndef HERWIG_HighEnergyMatching_H
#define HERWIG_HighEnergyMatching_H
#include "ThePEG/Config/ThePEG.h"
#include "ThePEG/Config/Unitsystem.h"
#include "EWProcess.h"
+// work around a Boost 1.64 bug where ublas headers would fail otherwise
+#include <boost/version.hpp>
+#if (BOOST_VERSION / 100 >= 1064)
+#include <boost/serialization/array_wrapper.hpp>
+#endif
#include <boost/numeric/ublas/matrix.hpp>
namespace Herwig {
using namespace ThePEG;
namespace HighEnergyMatching {
/**
* The high energy matching
*/
boost::numeric::ublas::matrix<complex<InvEnergy2> >
highEnergyMatching(Energy highScale,
Energy2 s, Energy2 t, Energy2 u,
Herwig::EWProcess::Process process,
bool oneLoop, bool includeAlphaS2);
/**
* Spin\f$\frac12\f$
*/
boost::numeric::ublas::matrix<complex<InvEnergy2> >
SpinHalfMatching(Energy highScale,
Energy2 s, Energy2 t, Energy2 u,
EWProcess::Process process,
bool oneLoop, bool includeAlphaS2);
/**
* Spin\f$1\f$
*/
boost::numeric::ublas::matrix<complex<InvEnergy2> >
Spin1HighMatching(Energy highScale,
Energy2 s, Energy2 t, Energy2 u,
EWProcess::Process process,
bool oneLoop, bool includeAlphaS2);
/**
* Spin\f$0\f$
*/
boost::numeric::ublas::matrix<complex<InvEnergy2> >
Spin0HighMatching(Energy highScale,
Energy2 s, Energy2 t, Energy2 u,
EWProcess::Process process,
bool oneLoop, bool includeAlphaS2);
}
}
#endif // HERWIG_HighEnergyMatching_H
diff --git a/MatrixElement/EW/SoftSudakov.h b/MatrixElement/EW/SoftSudakov.h
--- a/MatrixElement/EW/SoftSudakov.h
+++ b/MatrixElement/EW/SoftSudakov.h
@@ -1,193 +1,198 @@
// -*- C++ -*-
#ifndef Herwig_SoftSudakov_H
#define Herwig_SoftSudakov_H
//
// This is the declaration of the SoftSudakov class.
//
#include "ThePEG/Interface/Interfaced.h"
#include "Herwig/Utilities/GSLIntegrator.h"
+// work around a Boost 1.64 bug where ublas headers would fail otherwise
+#include <boost/version.hpp>
+#if (BOOST_VERSION / 100 >= 1064)
+#include <boost/serialization/array_wrapper.hpp>
+#endif
#include <boost/numeric/ublas/matrix.hpp>
#include "EWProcess.h"
#include "SoftSudakov.fh"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SoftSudakov class.
*
* @see \ref SoftSudakovInterfaces "The interfaces"
* defined for SoftSudakov.
*/
class SoftSudakov: public Interfaced {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
SoftSudakov();
/**
* The destructor.
*/
virtual ~SoftSudakov();
//@}
public:
/**
* Low energy soft evolution
*/
boost::numeric::ublas::matrix<Complex>
lowEnergyRunning(Energy EWScale, Energy lowScale,
Energy2 s, Energy2 t, Energy2 u,
Herwig::EWProcess::Process process,
unsigned int iswap);
/**
* Evalaute the high energy running as a matrix
*/
boost::numeric::ublas::matrix<Complex>
highEnergyRunning(Energy highScale, Energy EWScale,
Energy2 s, Energy2 t, Energy2 u,
Herwig::EWProcess::Process process,
unsigned int iswap);
/**
* Number of operators for the broken theory at low energy
*/
unsigned int numberBrokenGauge(Herwig::EWProcess::Process process);
/**
* Number of operators for the unbroken theory at high energy
*/
unsigned int numberGauge(Herwig::EWProcess::Process process);
protected:
/**
* Evaluate the soft evolution
*/
boost::numeric::ublas::matrix<Complex> evaluateSoft(boost::numeric::ublas::matrix<Complex> & G3,
boost::numeric::ublas::matrix<Complex> & G2,
boost::numeric::ublas::matrix<Complex> & G1,
Energy mu_h, Energy mu_l, bool high);
public:
/**
* The operator to be integrated
*/
InvEnergy operator ()(Energy mu) const;
/** Argument type for GaussianIntegrator */
typedef Energy ArgType;
/** Return type for GaussianIntegrator */
typedef InvEnergy ValType;
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SoftSudakov & operator=(const SoftSudakov &);
private:
/**
* Order for K
*/
unsigned int K_ORDER_;
/**
* Integrator
*/
GSLIntegrator integrator_;
/**
* Whether doing the high or low scale contribution
*/
bool high_;
/**
* Column
*/
unsigned int row_;
/**
* Row
*/
unsigned int col_;
/**
*
*/
bool real_;
/**
*
*/
boost::numeric::ublas::matrix<Complex> G1_;
/**
*
*/
boost::numeric::ublas::matrix<Complex> G2_;
/**
*
*/
boost::numeric::ublas::matrix<Complex> G3_;
};
}
#endif /* Herwig_SoftSudakov_H */
diff --git a/MatrixElement/EW/expm-1.h b/MatrixElement/EW/expm-1.h
--- a/MatrixElement/EW/expm-1.h
+++ b/MatrixElement/EW/expm-1.h
@@ -1,147 +1,148 @@
//
// Copyright (c) 2007
// Tsai, Dung-Bang
// National Taiwan University, Department of Physics
//
// E-Mail : dbtsai (at) gmail.com
// Begine : 2007/11/20
// Last modify : 2007/11/22
// Version : v0.1
//
// EXPGM_PAD computes the matrix exponential exp(H) for general matrixs,
// including complex and real matrixs using the irreducible (p,p) degree
// rational Pade approximation to the exponential
// exp(z) = r(z)=(+/-)( I+2*(Q(z)/P(z))).
//
// Usage :
//
// U = expm_pad(H)
// U = expm_pad(H, p)
//
// where p is internally set to 6 (recommended and gererally satisfactory).
//
// See also MATLAB supplied functions, EXPM and EXPM1.
//
// Reference :
// EXPOKIT, Software Package for Computing Matrix Exponentials.
// ACM - Transactions On Mathematical Software, 24(1):130-156, 1998
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. The authors make no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//
#ifndef _BOOST_UBLAS_EXPM_
#define _BOOST_UBLAS_EXPM_
+#include <boost/throw_exception.hpp>
#include <complex>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/lu.hpp>
namespace boost { namespace numeric { namespace ublas {
template<typename MATRIX> MATRIX expm_pad(const MATRIX &H, const int p = 6) {
typedef typename MATRIX::value_type value_type;
typedef typename MATRIX::size_type size_type;
typedef double real_value_type; // Correct me. Need to modify.
assert(H.size1() == H.size2());
const size_type n = H.size1();
const identity_matrix<value_type> I(n);
matrix<value_type> U(n,n),H2(n,n),P(n,n),Q(n,n);
real_value_type norm = 0.0;
// Calcuate Pade coefficients (1-based instead of 0-based as in the c vector)
vector<real_value_type> c(p+2);
c(1)=1;
for(size_type i = 1; i <= p; ++i)
c(i+1) = c(i) * ((p + 1.0 - i)/(i * (2.0 * p + 1 - i)));
// Calcuate the infinty norm of H, which is defined as the largest row sum of a matrix
for(size_type i=0; i<n; ++i)
{
real_value_type temp = 0.0;
for(size_type j=0;j<n;j++)
temp += std::abs<real_value_type>(H(j,i)); // Correct me, if H is complex, can I use that abs?
norm = std::max<real_value_type>(norm, temp);
}
if (norm == 0.0)
{
boost::throw_exception(boost::numeric::ublas::bad_argument());
std::cerr<<"Error! Null input in the routine EXPM_PAD.\n";
exit(0);
}
// Scaling, seek s such that || H*2^(-s) || < 1/2, and set scale = 2^(-s)
int s = 0;
real_value_type scale = 1.0;
if(norm > 0.5) {
s = std::max<int>(0, static_cast<int>((log(norm) / log(2.0) + 2.0)));
scale /= static_cast<real_value_type>(std::pow(2.0, s));
U.assign(scale * H); // Here U is used as temp value due to that H is const
}
else
U.assign(H);
// Horner evaluation of the irreducible fraction, see the following ref above.
// Initialise P (numerator) and Q (denominator)
H2.assign( prod(U, U) );
Q.assign( c(p+1)*I );
P.assign( c(p)*I );
size_type odd = 1;
for( size_type k = p - 1; k > 0; --k)
{
if( odd == 1)
{
Q = ( prod(Q, H2) + c(k) * I );
}
else
{
P = ( prod(P, H2) + c(k) * I );
}
odd = 1 - odd;
}
if( odd == 1)
{
Q = ( prod(Q, U) );
Q -= P ;
//U.assign( -(I + 2*(Q\P)));
}
else
{
P = (prod(P, U));
Q -= P;
//U.assign( I + 2*(Q\P));
}
// In origine expokit package, they use lapack ZGESV to obtain inverse matrix,
// and in that ZGESV routine, it uses LU decomposition for obtaing inverse matrix.
// Since in ublas, there is no matrix inversion template, I simply use the build-in
// LU decompostion package in ublas, and back substitute by myself.
//
//////////////// Implement Matrix Inversion ///////////////////////
permutation_matrix<size_type> pm(n);
int res = lu_factorize(Q, pm);
if( res != 0)
{
std::cerr << "Error in the matrix inversion in template expm_pad.\n";
exit(0);
}
H2 = I; // H2 is not needed anymore, so it is temporary used as identity matrix for substituting.
lu_substitute(Q, pm, H2);
if( odd == 1)
U.assign( -(I + 2.0 * prod(H2, P)));
else
U.assign( I + 2.0 * prod(H2, P));
// Squaring
for(size_t i = 0; i < s; ++i)
{
U = (prod(U,U));
}
return U;
}
}}}
#endif
diff --git a/MatrixElement/General/GeneralHardME.cc b/MatrixElement/General/GeneralHardME.cc
--- a/MatrixElement/General/GeneralHardME.cc
+++ b/MatrixElement/General/GeneralHardME.cc
@@ -1,1185 +1,1209 @@
// -*- C++ -*-
//
// GeneralHardME.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the GeneralHardME class.
//
#include "GeneralHardME.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Utilities/EnumIO.h"
#include "ThePEG/PDF/PolarizedBeamParticleData.h"
#include "ThePEG/Utilities/Debug.h"
#include <numeric>
using namespace Herwig;
GeneralHardME::GeneralHardME() : incoming_(0, 0), outgoing_(0, 0),
diagrams_(0), numberOfDiagrams_(0),
colour_(0), numberOfFlows_(0) ,
debug_(false), scaleChoice_(0),
scaleFactor_(1.) {
massOption(vector<unsigned int>(2,1));
}
void GeneralHardME::setProcessInfo(const vector<HPDiagram> & alldiagrams,
ColourStructure colour,
bool debug, unsigned int scaleOption,
double scaleFactor) {
// external particles
incoming_ = alldiagrams.at(0).incoming;
outgoing_ = alldiagrams.at(0).outgoing;
diagrams_ = alldiagrams;
numberOfDiagrams_ = alldiagrams.size();
// debug option
debug_ = debug;
// scale choice
scaleChoice_ = scaleOption;
scaleFactor_ = scaleFactor;
// OffShell options
pair<bool, bool> offshell(make_pair(false, false));
vector<unsigned int> mopt(2,1);
if( getParticleData(outgoing_.first )->widthGenerator() ||
getParticleData(outgoing_.first )-> massGenerator()) {
offshell.first = true;
mopt[0] = 2;
}
if( getParticleData(outgoing_.second)->widthGenerator() ||
getParticleData(outgoing_.second)-> massGenerator() ) {
offshell.second = true;
mopt[1] = 2;
}
if(outgoing_.first == incoming_.first ||
outgoing_.first == incoming_.second )
mopt[0] = 0;
if(outgoing_.second == incoming_.first ||
outgoing_.second == incoming_.second )
mopt[1] = 0;
massOption(mopt);
if( offshell.first == true && offshell.second == true &&
abs(outgoing_.first) == abs(outgoing_.second) )
rescalingOption(3);
// colour structure
colourStructure_ = colour;
switch (colour) {
// colour neutral process
case Colour11to11:
colour_ = vector<DVector>(1,DVector(1,1.));
numberOfFlows_ = 1;
break;
// colour neutral -> 3 3bar or swap process
case Colour11to33bar: case Colour33barto11:
colour_ = vector<DVector>(1,DVector(1,3.));
numberOfFlows_ = 1;
break;
// colour neutral -> 8 8 process or swap
case Colour11to88: case Colour88to11 :
colour_ = vector<DVector>(1,DVector(1,8.));
numberOfFlows_ = 1;
break;
// colour 33 -> 33 or 3bar3bar -> 3bar3bar process
// or colour 33bar -> 33bar
case Colour33to33: case Colour3bar3barto3bar3bar:
case Colour33barto33bar:
colour_ = vector<DVector>(4, DVector(4, 0.));
colour_[0][0] = colour_[1][1] = 2.;
colour_[2][2] = colour_[3][3] = 9.;
colour_[0][1] = colour_[1][0] = -2./3.;
colour_[0][2] = colour_[2][0] = 0.;
colour_[0][3] = colour_[3][0] = 4.;
colour_[1][2] = colour_[2][1] = 4.;
colour_[1][3] = colour_[3][1] = 0.;
colour_[2][3] = colour_[3][2] = 3.;
numberOfFlows_ = 4;
break;
// colour 3 3bar -> 6 6bar
case Colour33barto66bar: case Colour33barto6bar6:
colour_ = vector<DVector>(10, DVector(10, 0.));
// diagonals
for(unsigned int ix=0;ix<4;++ix){
colour_[ix][ix] = 1.5;
colour_[ix+4][ix+4] = 27./16.;
}
colour_[8][8]=colour_[9][9]=27./4.;
// 0
colour_[0][1] = colour_[1][0] = 0.5;
colour_[0][2] = colour_[2][0] = 0.5;
colour_[0][3] = colour_[3][0] = 0.;
colour_[0][4] = colour_[4][0] = 3./2.;
colour_[0][5] = colour_[5][0] = 1./2.;
colour_[0][6] = colour_[6][0] = 1./2.;
colour_[0][7] = colour_[7][0] = 0.;
// 1
colour_[1][2] = colour_[2][1] = 0.;
colour_[1][3] = colour_[3][1] = 0.5;
colour_[1][4] = colour_[4][1] = 1./2.;
colour_[1][5] = colour_[5][1] = 3./2.;
colour_[1][6] = colour_[6][1] = 0.;
colour_[1][7] = colour_[7][1] = 1./2.;
// 2
colour_[2][3] = colour_[3][2] = 0.5;
colour_[2][4] = colour_[4][2] = 1./2.;
colour_[2][5] = colour_[5][2] = 0.;
colour_[2][6] = colour_[6][2] = 3./2.;
colour_[2][7] = colour_[7][2] = 1./2.;
// 3
colour_[3][4] = colour_[4][3] = 0.;
colour_[3][5] = colour_[5][3] = 1./2.;
colour_[3][6] = colour_[6][3] = 1./2.;
colour_[3][7] = colour_[7][3] = 3./2.;
// 4
colour_[4][5] = colour_[5][4] = 9./16.;
colour_[4][6] = colour_[6][4] = 9./16.;
colour_[4][7] = colour_[7][4] = 3./16.;
colour_[4][8] = colour_[8][4] = 9./8.;
colour_[4][9] = colour_[9][4] = 3./8.;
// 5
colour_[5][6] = colour_[6][5] = 3./16.;
colour_[5][7] = colour_[7][5] = 9./16.;
colour_[5][8] = colour_[8][5] = 3./8.;
colour_[5][9] = colour_[9][5] = 9./8.;
//6
colour_[6][7] = colour_[7][6] = 9./16.;
colour_[6][8] = colour_[8][6] = 3./8.;
colour_[6][9] = colour_[9][6] = 9./8.;
// 7
colour_[7][8] = colour_[8][7] = 9./8.;
colour_[7][9] = colour_[9][7] = 3./8.;
// 8
colour_[8][9] = colour_[9][8] = 9./4.;
numberOfFlows_ = 10;
break;
// colour 33bar -> 88, 88 -> 33bar
case Colour33barto88: case Colour88to33bar:
case Colour38to83: case Colour38to38:
case Colour3bar8to83bar: case Colour3bar8to3bar8:
colour_ = vector<DVector>(3, DVector(3, 0.));
colour_[0][0] = colour_[1][1] = 16./3.;
colour_[0][1] = colour_[1][0] = -2./3.;
colour_[2][2]=24.;
colour_[0][2] = colour_[2][0] = 4.;
colour_[1][2] = colour_[2][1] = 4.;
numberOfFlows_ = 3;
break;
case Colour88to88: {
colour_ = vector<DVector>(9, DVector(9, 0.));
double on1=19./6.,on2=64.;
double off1=-1./3.,off2=2./3.,off3=8.,off4=16./3.,off5=-2./3.;
// octet exchange
colour_[0][0] = colour_[1][1] = colour_[2][2]=on1;
colour_[3][3] = colour_[4][4] = colour_[5][5]=on1;
colour_[0][1] = colour_[1][0] = off1;
colour_[0][2] = colour_[2][0] = off1;
colour_[0][3] = colour_[3][0] = off1;
colour_[0][4] = colour_[4][0] = off1;
colour_[0][5] = colour_[5][0] = off2;
colour_[1][2] = colour_[2][1] = off1;
colour_[1][3] = colour_[3][1] = off2;
colour_[1][4] = colour_[4][1] = off1;
colour_[1][5] = colour_[5][1] = off1;
colour_[2][3] = colour_[3][2] = off1;
colour_[2][4] = colour_[4][2] = off2;
colour_[2][5] = colour_[5][2] = off1;
colour_[3][4] = colour_[4][3] = off1;
colour_[3][5] = colour_[5][3] = off1;
colour_[4][5] = colour_[5][4] = off1;
// singlet exchange
colour_[6][6] = colour_[7][7] = colour_[8][8] = on2;
colour_[6][7] = colour_[7][6] = off3;
colour_[6][8] = colour_[8][6] = off3;
colour_[7][8] = colour_[8][7] = off3;
// octet singlet interference
colour_[0][6] = colour_[6][0] = off4;
colour_[1][6] = colour_[6][1] = off4;
colour_[2][6] = colour_[6][2] = off5;
colour_[3][6] = colour_[6][3] = off4;
colour_[4][6] = colour_[6][4] = off5;
colour_[5][6] = colour_[6][5] = off4;
colour_[0][7] = colour_[7][0] = off5;
colour_[1][7] = colour_[7][1] = off4;
colour_[2][7] = colour_[7][2] = off4;
colour_[3][7] = colour_[7][3] = off4;
colour_[4][7] = colour_[7][4] = off4;
colour_[5][7] = colour_[7][5] = off5;
colour_[0][8] = colour_[8][0] = off4;
colour_[1][8] = colour_[8][1] = off5;
colour_[2][8] = colour_[8][2] = off4;
colour_[3][8] = colour_[8][3] = off5;
colour_[4][8] = colour_[8][4] = off4;
colour_[5][8] = colour_[8][5] = off4;
numberOfFlows_ = 9;
break;
}
case Colour33barto18 : case Colour33barto81 :
case Colour38to13 : case Colour38to31 :
case Colour3bar8to13bar: case Colour3bar8to3bar1:
colour_ = vector<DVector>(1,DVector(1,4.));
numberOfFlows_ = 1;
break;
case Colour88to18 : case Colour88to81:
colour_ = vector<DVector>(1,DVector(1,24.));
numberOfFlows_ = 1;
break;
case Colour88to66bar:
colour_ = vector<DVector>(12, DVector(12, 0.));
// diagonals
for(unsigned int ix=0;ix<12;++ix) colour_[ix][ix] = 4.;
// 1 1 block
colour_[ 0][ 1] = colour_[ 1][ 0] = 4./3.;
colour_[ 0][ 2] = colour_[ 2][ 0] = 4./3.;
colour_[ 0][ 3] = colour_[ 3][ 0] = 0.5 ;
colour_[ 1][ 2] = colour_[ 2][ 1] = 0.5 ;
colour_[ 1][ 3] = colour_[ 3][ 1] = 4./3.;
colour_[ 2][ 3] = colour_[ 3][2] = 4./3.;
// 1 2 and 2 1 blocks
colour_[ 0][ 4] = colour_[ 4][ 0] = 4./3.;
colour_[ 1][ 5] = colour_[ 5][ 1] = 4./3.;
colour_[ 2][ 6] = colour_[ 6][ 2] = 4./3.;
colour_[ 3][ 7] = colour_[ 7][ 3] = 4./3.;
colour_[ 0][ 7] = colour_[ 7][ 0] = -1./6.;
colour_[ 1][ 6] = colour_[ 6][ 1] = -1./6.;
colour_[ 2][ 5] = colour_[ 5][ 2] = -1./6.;
colour_[ 3][ 4] = colour_[ 4][ 3] = -1./6.;
// 1 3 and 3 1 blocks
colour_[ 0][11] = colour_[11][ 0] = 4./3.;
colour_[ 1][10] = colour_[10][ 1] = 4./3.;
colour_[ 2][ 9] = colour_[ 9][ 2] = 4./3.;
colour_[ 3][ 8] = colour_[ 8][ 3] = 4./3.;
colour_[ 0][ 8] = colour_[ 8][ 0] = -1./6.;
colour_[ 1][ 9] = colour_[ 9][ 1] = -1./6.;
colour_[ 2][10] = colour_[10][ 2] = -1./6.;
colour_[ 3][11] = colour_[11][ 3] = -1./6.;
// 2 2 block
colour_[ 4][ 5] = colour_[ 5][ 4] = 4./3.;
colour_[ 4][ 6] = colour_[ 6][ 4] = 4./3.;
colour_[ 4][ 7] = colour_[ 7][ 4] = 0.5 ;
colour_[ 5][ 6] = colour_[ 6][ 5] = 0.5 ;
colour_[ 5][ 7] = colour_[ 7][ 5] = 4./3.;
colour_[ 6][ 7] = colour_[ 7][ 6] = 4./3.;
// 2 3 and 3 2 blocks
colour_[ 4][ 8] = colour_[ 8][ 4] = -0.5 ;
colour_[ 4][ 9] = colour_[ 9][ 4] = -1./6.;
colour_[ 4][10] = colour_[10][ 4] = -1./6.;
colour_[ 4][11] = colour_[11][ 4] = 0.5 ;
colour_[ 5][ 8] = colour_[ 8][ 5] = -1./6.;
colour_[ 5][ 9] = colour_[ 9][ 5] = -0.5 ;
colour_[ 5][10] = colour_[10][ 5] = 0.5 ;
colour_[ 5][11] = colour_[11][ 5] = -1./6.;
colour_[ 6][ 8] = colour_[ 8][ 6] = -1./6.;
colour_[ 6][ 9] = colour_[ 9][ 6] = 0.5 ;
colour_[ 6][10] = colour_[10][ 6] = -0.5 ;
colour_[ 6][11] = colour_[11][ 6] = -1./6.;
colour_[ 7][ 8] = colour_[ 8][ 7] = 0.5 ;
colour_[ 7][ 9] = colour_[ 9][ 7] = -1./6.;
colour_[ 7][10] = colour_[10][ 7] = -1./6.;
colour_[ 7][11] = colour_[11][ 7] = -0.5 ;
// 3 3 block
colour_[ 8][ 9] = colour_[ 9][ 8] = 4./3.;
colour_[ 8][10] = colour_[10][ 8] = 4./3.;
colour_[ 8][11] = colour_[11][ 8] = 0.5 ;
colour_[ 9][10] = colour_[10][ 9] = 0.5 ;
colour_[ 9][11] = colour_[11][ 9] = 4./3.;
colour_[10][11] = colour_[11][10] = 4./3.;
numberOfFlows_ = 12;
break;
case Colour33to61: case Colour33to16:
case Colour3bar3barto6bar1: case Colour3bar3barto16bar:
colour_ = vector<DVector>(2, DVector(2, 0.));
colour_[1][1] = colour_[0][0] = 9./4.;
colour_[0][1] = colour_[1][0] = 3./4.;
numberOfFlows_ = 2;
break;
case Colour38to3bar6: case Colour38to63bar:
colour_ = vector<DVector>(8, DVector(8, 0.));
// diagonals
for(unsigned int ix=0;ix<8;++ix) colour_[ix][ix] = 3.;
colour_[0][1] = colour_[1][0] = 1.;
colour_[0][2] = colour_[2][0] = 1.;
colour_[0][3] = colour_[3][0] = 0.;
colour_[0][4] = colour_[4][0] = 1.;
colour_[0][5] = colour_[5][0] = 3.;
colour_[0][6] = colour_[6][0] = 1.;
colour_[0][7] = colour_[7][0] = 0.;
// 1
colour_[1][2] = colour_[2][1] = 0.;
colour_[1][3] = colour_[3][1] = 1.;
colour_[1][4] = colour_[4][1] = 3.;
colour_[1][5] = colour_[5][1] = 1.;
colour_[1][6] = colour_[6][1] = 0.;
colour_[1][7] = colour_[7][1] = 1.;
// 2
colour_[2][3] = colour_[3][2] = 1.;
colour_[2][4] = colour_[4][2] = 0.;
colour_[2][5] = colour_[5][2] = 1.;
colour_[2][6] = colour_[6][2] = 3.;
colour_[2][7] = colour_[7][2] = 1.;
// 3
colour_[3][4] = colour_[4][3] = 1.;
colour_[3][5] = colour_[5][3] = 0.;
colour_[3][6] = colour_[6][3] = 1.;
colour_[3][7] = colour_[7][3] = 3.;
// 4
colour_[4][5] = colour_[5][4] = 1.;
colour_[4][6] = colour_[6][4] = 0.;
colour_[4][7] = colour_[7][4] = 1.;
// 5
colour_[5][6] = colour_[6][5] = 1.;
colour_[5][7] = colour_[7][5] = 0.;
//6
colour_[6][7] = colour_[7][6] = 1.;
numberOfFlows_ = 8;
break;
case Colour33to13bar: case Colour33to3bar1:
case Colour3bar3barto13: case Colour3bar3barto31:
colour_ = vector<DVector>(1, DVector(1, 6.));
numberOfFlows_ = 1;
break;
case Colour33to83bar: case Colour33to3bar8:
case Colour3bar3barto83: case Colour3bar3barto38:
case Colour38to3bar3bar: case Colour3bar8to33:
colour_ = vector<DVector>(3, DVector(3, 0.));
colour_[0][0]=colour_[1][1]=colour_[2][2]=8.;
colour_[0][1]=colour_[1][0]=-4.;
colour_[0][2]=colour_[2][0]=-4.;
colour_[1][2]=colour_[2][1]=-4.;
numberOfFlows_ = 3;
break;
default:
assert(false);
}
if(Debug::level > 1 ) {
generator()->log() << "Set up 2->2 ME for "
<< getParticleData(incoming_.first )->PDGName() << " "
<< getParticleData(incoming_.second)->PDGName() << " -> "
<< getParticleData(outgoing_.first )->PDGName() << " "
<< getParticleData(outgoing_.second)->PDGName() << "\n";
for(unsigned int ix=0;ix<alldiagrams.size();++ix) {
generator()->log() << "Diagram " << ix << " has "
<< alldiagrams[ix].incoming.first << " "
<< alldiagrams[ix].incoming.second << " -> "
<< alldiagrams[ix].outgoing.first << " "
<< alldiagrams[ix].outgoing.second << "\n";
generator()->log() << "Type " << alldiagrams[ix].channelType << " "
<< alldiagrams[ix].ordered.first << " "
<< alldiagrams[ix].ordered.second << "\n";
if(alldiagrams[ix].intermediate)
generator()->log() << "Intermediate " << alldiagrams[ix].intermediate->PDGName() << "\n";
generator()->log() << "vertices "
<< alldiagrams[ix].vertices.first ->fullName() << " "
<< alldiagrams[ix].vertices.second->fullName() << "\n";
}
}
}
void GeneralHardME::getDiagrams() const {
//get ParticleData pointers for external particles
tcPDPtr ina = getParticleData(getIncoming().first);
tcPDPtr inb = getParticleData(getIncoming().second);
tcPDPtr outa = getParticleData(getOutgoing().first);
tcPDPtr outb = getParticleData(getOutgoing().second);
-
+
+ bool hasThreePoints = false;
for(HPCount idx = 0; idx < numberOfDiagrams_; ++idx) {
const HPDiagram & current = getProcessInfo()[idx];
tcPDPtr offshell = current.intermediate;
if(!offshell) continue;
//t-channel
if(current.channelType == HPDiagram::tChannel) {
+ hasThreePoints = true;
if(offshell->id() < 0) offshell = offshell->CC();
if(current.ordered.second)
add(new_ptr((Tree2toNDiagram(3), ina, offshell,
inb, 1, outa, 2, outb, -(idx+1))));
else
add(new_ptr((Tree2toNDiagram(3), ina, offshell,
inb, 2, outa, 1, outb, -(idx+1))));
}
//s-channel
- else if(current.channelType == HPDiagram::sChannel)
+ else if(current.channelType == HPDiagram::sChannel) {
+ hasThreePoints = true;
add(new_ptr((Tree2toNDiagram(2), ina, inb, 1, offshell,
3, outa, 3, outb, -(idx+1))));
+ }
else
throw MEException() << "getDiagrams() - Unknown diagram in matrix element "
<< fullName() << Exception::runerror;
}
+ if(!hasThreePoints) {
+ add(new_ptr((Tree2toNDiagram(2), ina, inb, 1, outa,
+ 3, outa, 3, outb, -1)));
+ }
}
unsigned int GeneralHardME::orderInAlphaS() const {
unsigned int order(0);
for(HPCount idx = 0; idx < numberOfDiagrams_; ++idx) {
unsigned int tOrder = diagrams_[idx].vertices.first->orderInGs() +
diagrams_[idx].vertices.second->orderInGs();
if(tOrder > order) order = tOrder;
}
return order;
}
unsigned int GeneralHardME::orderInAlphaEW() const {
unsigned int order(0);
for(HPCount idx = 0; idx < numberOfDiagrams_; ++idx) {
unsigned int tOrder = diagrams_[idx].vertices.first->orderInGem() +
diagrams_[idx].vertices.second->orderInGem();
if(tOrder > order) order = tOrder;
}
return order;
}
Selector<MEBase::DiagramIndex>
GeneralHardME::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if(abs(diags[i]->id()) == int(diagram_+1)) sel.insert(1., i);
}
return sel;
}
void GeneralHardME::persistentOutput(PersistentOStream & os) const {
os << incoming_ << outgoing_ << diagrams_ << colour_ << oenum(colourStructure_)
<< numberOfDiagrams_ << numberOfFlows_ << debug_
<< scaleChoice_ << scaleFactor_;
}
void GeneralHardME::persistentInput(PersistentIStream & is, int) {
is >> incoming_ >> outgoing_ >> diagrams_ >> colour_ >> ienum(colourStructure_)
>> numberOfDiagrams_ >> numberOfFlows_ >> debug_
>> scaleChoice_ >> scaleFactor_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeAbstractClass<GeneralHardME,HwMEBase>
describeHerwigGeneralHardME("Herwig::GeneralHardME", "Herwig.so");
void GeneralHardME::Init() {
static ClassDocumentation<GeneralHardME> documentation
("This class is designed to be a base class for a specific spin "
"configuration where no matrix element exists, i.e. when processes "
"are created automaticlly for a different model.");
}
Selector<const ColourLines *>
GeneralHardME::colourGeometries(tcDiagPtr diag) const {
// get the current diagram
const HPDiagram & current = getProcessInfo()[abs(diag->id()) - 1];
Selector<const ColourLines *> sel;
switch(colourStructure_) {
case Colour11to11:
static ColourLines f11to11("");
sel.insert(1.,&f11to11);
break;
case Colour11to33bar:
static ColourLines f11to33bar[2]={ColourLines("4 -5"),
ColourLines("4 2 -5")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,&f11to33bar[1]);
else
sel.insert(1.,&f11to33bar[0]);
break;
case Colour11to88:
static ColourLines f11to88[2]={ColourLines("4 -5, 5 -4"),
ColourLines("4 2 -5,5 -2 4")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,&f11to88[1]);
else
sel.insert(1.,&f11to88[0]);
break;
case Colour33to33:
static ColourLines f33to33[4]={ColourLines("1 2 5, 3 -2 4"),
ColourLines("1 2 4, 3 -2 5"),
ColourLines("1 4, 3 5"),
ColourLines("1 5, 3 4")};
static ColourLines f33to33s[4]={ColourLines("1 3:1 4, 2 3:2 5"),
ColourLines("1 3:2 4, 2 3:1 5"),
ColourLines("1 3:1 5, 2 3:2 4"),
ColourLines("1 3:2 5, 2 3:1 4")};
static ColourLines f33to33t[2]={ColourLines("1 4, 2 5"),
ColourLines("1 5, 2 4")};
if(current.intermediate->iColour() == PDT::Colour8)
sel.insert(1.,current.ordered.second ? &f33to33[0] : &f33to33[1]);
else if(current.intermediate->iColour() == PDT::Colour6) {
sel.insert(1., &f33to33s[2*(flow_-2)+UseRandom::irnd(0,2)]);
}
else if(current.intermediate->iColour() == PDT::Colour3bar) {
sel.insert(1., &f33to33t[flow_-2]);
}
else
sel.insert(1.,current.ordered.second ? &f33to33[2] : &f33to33[3]);
break;
case Colour3bar3barto3bar3bar:
static ColourLines
f3bar3barto3bar3bar[4]={ColourLines("-1 -2 -5, -3 2 -4"),
ColourLines("-1 -2 -4, -3 2 -5"),
ColourLines("-1 -4, -3 -5"),
ColourLines("-1 -5, -3 -4")};
static ColourLines f3bar3barto3bar3bars[4]=
{ColourLines("-1 -3:1 -4, -2 -3:2 -5"),
ColourLines("-1 -3:2 -4, -2 -3:1 -5"),
ColourLines("-1 -3:1 -5, -2 -3:2 -4"),
ColourLines("-1 -3:2 -5, -2 -3:1 -4")};
static ColourLines f3bar3barto3bar3bart[2]=
{ColourLines("-1 -4, -2 -5"),
ColourLines("-1 -5, -2 -4")};
if(current.intermediate->iColour() == PDT::Colour8) {
sel.insert(1.,current.ordered.second ?
&f3bar3barto3bar3bar[0] : &f3bar3barto3bar3bar[1]);
}
else if(current.intermediate->iColour() == PDT::Colour6bar) {
sel.insert(1., &f3bar3barto3bar3bars[2*(flow_-2)+UseRandom::irnd(0,2)]);
}
else if(current.intermediate->iColour() == PDT::Colour3) {
sel.insert(1., &f3bar3barto3bar3bart[flow_-2]);
}
else
sel.insert(1.,current.ordered.second ?
&f3bar3barto3bar3bar[2] : &f3bar3barto3bar3bar[3]);
break;
case Colour33barto33bar:
static ColourLines
- f33barto33bar[4]={ColourLines("1 2 -3, 4 -2 -5"),
+ f33barto33bar[5]={ColourLines("1 2 -3, 4 -2 -5"),
ColourLines("1 3 4, -2 -3 -5"),
ColourLines("1 4, -3 -5"),
- ColourLines("1 -2, 4 -5")};
- if(current.channelType == HPDiagram::tChannel)
- sel.insert(1.,current.intermediate->iColour() == PDT::Colour8 ?
- &f33barto33bar[0] : &f33barto33bar[2]);
+ ColourLines("1 -2, 4 -5"),
+ ColourLines("1 -3, 4 -5")};
+ if(current.channelType == HPDiagram::tChannel) {
+ if(current.ordered.second) {
+ sel.insert(1.,current.intermediate->iColour() == PDT::Colour8 ?
+ &f33barto33bar[0] : &f33barto33bar[2]);
+ }
+ else {
+ sel.insert(1.,&f33barto33bar[2*(flow_-2)+2]);
+ }
+ }
else
sel.insert(1.,current.intermediate->iColour() == PDT::Colour8 ?
&f33barto33bar[1] : &f33barto33bar[3]);
break;
case Colour33barto11:
static ColourLines f33barto11[2]={ColourLines("1 -2"),
ColourLines("1 2 -3")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,&f33barto11[1]);
else
sel.insert(1.,&f33barto11[0]);
break;
case Colour33barto88:
static ColourLines f33barto88[5]={ColourLines("1 4, -4 2 5, -5 -3"),
ColourLines("1 5, -5 2 4, -4 -3"),
ColourLines("1 3 4, -5 -3 -2, -4 5"),
ColourLines("1 3 5, -4 -3 -2, -5 4"),
ColourLines("1 -2,4 -5, 5 -4")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,current.ordered.second ? &f33barto88[0] : &f33barto88[1]);
else if(current.intermediate->iColour() == PDT::Colour8)
sel.insert(1.,&f33barto88[flow_+2]);
else
sel.insert(1.,&f33barto88[4]);
break;
case Colour33barto18:
static ColourLines f33barto18[3]={ColourLines("1 2 5, -3 -5"),
ColourLines("1 5, -5 2 -3"),
ColourLines("1 3 5,-2 -3 -5")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,current.ordered.second ? &f33barto18[0] : &f33barto18[1]);
else
sel.insert(1.,&f33barto18[2]);
break;
case Colour33barto81:
static ColourLines f33barto81[3]={ColourLines("1 4, -4 2 -3"),
ColourLines("-3 -4, 1 2 4"),
ColourLines("1 3 4,-2 -3 -4")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,current.ordered.second ? &f33barto81[0] : &f33barto81[1]);
else
sel.insert(1.,&f33barto81[2]);
break;
case Colour88to11:
static ColourLines f88barto11[2]={ColourLines("1 -2, 2 -1"),
ColourLines("1 -2 -3, 3 2 -1")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,&f88barto11[1]);
else
sel.insert(1.,&f88barto11[0]);
break;
case Colour88to33bar:
static ColourLines f88to33bar[5]={ColourLines("1 4, -3 -5, 3 2 -1"),
ColourLines("-1 -5, 1 2 -3, 3 4"),
ColourLines("2 -1, 1 3 4, -2 -3 -5"),
ColourLines("1 -2, -1 -3 -5, 2 3 4"),
ColourLines("1 -2, 2 -1, 4 -5")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,current.ordered.second ? &f88to33bar[0] : &f88to33bar[1]);
else if(current.intermediate->iColour() == PDT::Colour8 )
sel.insert(1.,&f88to33bar[flow_+2]);
else
sel.insert(1.,&f88to33bar[4]);
break;
case Colour88to88:
static ColourLines f88to88s[9]={ColourLines("-1 2, 1 3 5, -5 4, -2 -3 -4"),
ColourLines("-1 2, 1 3 4, -4 5, -2 -3 -5"),
ColourLines(""),
ColourLines("1 -2, -1 -3 -4, 4 -5, 2 3 5"),
ColourLines(""),
ColourLines("1 -2, -1 -3 -5, 5 -4, 2 3 4"),
ColourLines("1 -2, 2 -1, 4 -5, 5 -4"),
ColourLines(""),
ColourLines("")};
static ColourLines f88to88t[9]={ColourLines(""),
ColourLines("1 4, -1 -2 3, -2 -5, -3 2 5"),
ColourLines("-1 -4, 1 2 5, -3 -5, 3 -2 4"),
ColourLines("-1 -4, 1 2 -3, 3 5, 4 -2 -5"),
ColourLines("1 4, -1 -2 -5, 3 5, -3 2 -4"),
ColourLines(""),
ColourLines(""),
ColourLines("1 4, -1 -4, 3 5, -5 -3"),
ColourLines("")};
static ColourLines f88to88u[9]={ColourLines("1 4, -1 -2 3, -3 -5, -4 2 5"),
ColourLines(""),
ColourLines("1 5, -1 -2 -4, 3 4, -3 2 -5"),
ColourLines(""),
ColourLines("-1 -5, 1 2 4, -3 -4, 3 -2 5"),
ColourLines("-1 -5, 1 2 -3, 3 4, 5 -2 -4"),
ColourLines(""),
ColourLines(""),
ColourLines("1 5, -1 -5, 3 4, -3 -4")};
if(current.channelType == HPDiagram::sChannel) {
sel.insert(1., &f88to88s[flow_]);
}
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second) {
sel.insert(1., &f88to88t[flow_]);
}
else {
sel.insert(1., &f88to88u[flow_]);
}
}
break;
case Colour38to13:
static ColourLines f38to13[2]={ColourLines("1 2 -3, 3 5"),
ColourLines("1 -2, 2 3 5")};
if(current.channelType == HPDiagram::tChannel) {
sel.insert(1.,&f38to13[0]);
}
else {
sel.insert(1.,&f38to13[1]);
}
break;
case Colour38to31:
static ColourLines f38to31[2]={ColourLines("1 2 -3, 3 4"),
ColourLines("1 -2, 2 3 4 ")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,&f38to31[0]);
else
sel.insert(1.,&f38to31[1]);
break;
case Colour3bar8to13bar:
static ColourLines f3bar8to13bar[2]={ColourLines("-1 2 3, -3 -5 "),
ColourLines("-1 2, -5 -3 -2")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,&f3bar8to13bar[0]);
else
sel.insert(1.,&f3bar8to13bar[1]);
break;
case Colour3bar8to3bar1:
static ColourLines f3bar8to3bar1[2]={ColourLines("-1 2 3, -3 -4 "),
ColourLines("-1 2, -4 -3 -2")};
if(current.channelType == HPDiagram::tChannel)
sel.insert(1.,&f3bar8to3bar1[0]);
else
sel.insert(1.,&f3bar8to3bar1[1]);
break;
case Colour38to83:
- static ColourLines f38to83[4]={ColourLines("1 4, -4 2 -3, 3 5"),
+ static ColourLines f38to83[5]={ColourLines("1 4, -4 2 -3, 3 5"),
ColourLines("1 -2, 2 3 4, 5 -4"),
ColourLines("1 2 4, -4 -3, 3 -2 5"),
- ColourLines("1 2 -3, -4 -2 5, 3 4")};
+ ColourLines("1 2 -3, -4 -2 5, 3 4"),
+ ColourLines("1 5, 3 4, -3 -4")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1.,&f38to83[1]);
else {
if(current.intermediate->iColour() == PDT::Colour8)
sel.insert(1.,&f38to83[flow_+2]);
+ else if(current.intermediate->iColour() == PDT::Colour0)
+ sel.insert(1.,&f38to83[4]);
else
sel.insert(1.,&f38to83[0]);
}
break;
case Colour38to38:
- static ColourLines f38to38[4]={ColourLines("1 5, -5 2 -3, 3 4"),
+ static ColourLines f38to38[5]={ColourLines("1 5, -5 2 -3, 3 4"),
ColourLines("1 -2, 2 3 5, 4 -5"),
ColourLines("1 2 5, -5 -3, 3 -2 4"),
- ColourLines("1 2 -3, -5 -2 4, 3 5")};
+ ColourLines("1 2 -3, -5 -2 4, 3 5"),
+ ColourLines("1 4, 3 5, -3 -5")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1.,&f38to38[1]);
else {
if(current.intermediate->iColour() == PDT::Colour8)
sel.insert(1.,&f38to38[flow_+2]);
+ else if(current.intermediate->iColour() == PDT::Colour0)
+ sel.insert(1.,&f38to38[4]);
else
sel.insert(1.,&f38to38[0]);
}
break;
case Colour3bar8to83bar:
- static ColourLines f3bar8to83bar[4]={ColourLines("-1 -4, 3 2 4, -3 -5"),
+ static ColourLines f3bar8to83bar[5]={ColourLines("-1 -4, 3 2 4, -3 -5"),
ColourLines("-1 2, -4 -3 -2, 4 -5"),
ColourLines("-1 -2 -4,-3 2 -5,3 4"),
- ColourLines("-1 -2 3, -5 2 4, -3 -4")};
+ ColourLines("-1 -2 3, -5 2 4, -3 -4"),
+ ColourLines("-1 -5, -3 -4, 3 4")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1.,&f3bar8to83bar[1]);
else {
if(current.intermediate->iColour() == PDT::Colour8)
sel.insert(1.,&f3bar8to83bar[flow_+2]);
+ else if(current.intermediate->iColour() == PDT::Colour0)
+ sel.insert(1.,&f3bar8to83bar[4]);
else
sel.insert(1.,&f3bar8to83bar[0]);
}
break;
case Colour3bar8to3bar8:
static ColourLines f3bar8to3bar8[4]={ColourLines("-1 -5, 3 2 5, -3 -4"),
ColourLines("-1 2, -5 -3 -2, 5 -4"),
ColourLines("-1 -2 -5,-3 2 -4,3 5"),
ColourLines("-1 -2 3, -4 2 5, -3 -5")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1.,&f3bar8to3bar8[1]);
else {
if(current.intermediate->iColour() == PDT::Colour8)
sel.insert(1.,&f3bar8to3bar8[flow_+2]);
else
sel.insert(1.,&f3bar8to3bar8[0]);
}
break;
case Colour88to18:
static ColourLines f88to18[6]={ColourLines(" 1 3 5, -1 2, -2 -3 -5"),
ColourLines(" -1 -3 -5, 1 -2, 2 3 5"),
ColourLines(" 1 2 -3, -1 -2 -5, 3 5"),
ColourLines("-1 -2 3, 1 2 5, -3 -5"),
ColourLines(" 1 5, -1 2 3, -3 -2 -5"),
ColourLines("-1 -5, 1 -2 -3, 3 2 5")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1.,&f88to18[UseRandom::irnd(0,2)]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1.,&f88to18[UseRandom::irnd(2,4)]);
else
sel.insert(1.,&f88to18[UseRandom::irnd(4,6)]);
}
break;
case Colour88to81:
static ColourLines f88to81[6]={ColourLines(" 1 3 4, -1 2, -2 -3 -4"),
ColourLines(" -1 -3 -4, 1 -2, 2 3 4"),
ColourLines(" 1 4, -1 2 3, -3 -2 -4"),
ColourLines(" -1 -4, 1 -2 -3, 3 2 4"),
ColourLines(" 1 2 -3, -1 -2 -4, 3 4"),
ColourLines(" -1 -2 3, 1 2 4, -3 -4")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1.,&f88to81[UseRandom::irnd(0,2)]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1.,&f88to81[UseRandom::irnd(2,4)]);
else
sel.insert(1.,&f88to81[UseRandom::irnd(4,6)]);
}
break;
case Colour33barto66bar:
static ColourLines f33barto66bars[10]
={ColourLines("1 3 4:1, -2 -3 -5:1, 4:2 -5:2"),
ColourLines("1 3 4:1, -2 -3 -5:2, 4:2 -5:1"),
ColourLines("1 3 4:2, -2 -3 -5:1, 4:1 -5:2"),
ColourLines("1 3 4:2, -2 -3 -5:2, 4:1 -5:1"),
ColourLines(""), ColourLines(""),
ColourLines(""), ColourLines(""),
ColourLines("1 -2, 4:1 -5:1, 4:2 -5:2"),
ColourLines("1 -2, 4:1 -5:2, 4:2 -5:1")};
static ColourLines f33barto66bart[10]
={ColourLines(""), ColourLines(""),
ColourLines(""), ColourLines(""),
ColourLines("1 4:1, 4:2 2 -5:2, -3 -5:1"),
ColourLines("1 4:1, 4:2 2 -5:1, -3 -5:2"),
ColourLines("1 4:2, 4:1 2 -5:2, -3 -5:1"),
ColourLines("1 4:2, 4:1 2 -5:1, -3 -5:2"),
ColourLines(""), ColourLines("")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1.,&f33barto66bars[flow_]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1.,&f33barto66bart[flow_]);
else
assert(false);
}
break;
case Colour33barto6bar6:
static ColourLines f33barto6bar6s[8]
={ColourLines("1 3 5:1, -2 -3 -4:1, -4:2 5:2"),
ColourLines("1 3 5:1, -2 -3 -4:2, -4:1 5:2"),
ColourLines("1 3 5:2, -2 -3 -4:1, -4:2 5:1"),
ColourLines("1 3 5:2, -2 -3 -4:2, -4:1 5:1"),
ColourLines(""), ColourLines(""),
ColourLines(""), ColourLines("")};
static ColourLines f33barto6bar6u[8]
={ColourLines(""), ColourLines(""),
ColourLines(""), ColourLines(""),
ColourLines("1 5:1, 5:2 2 -4:1, -3 -4:2"),
ColourLines("1 5:1, 5:2 2 -4:2, -3 -4:1"),
ColourLines("1 5:2, 5:1 2 -4:1, -3 -4:2"),
ColourLines("1 5:2, 5:1 2 -4:2, -3 -4:1")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1.,&f33barto6bar6s[flow_]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
assert(false);
else
sel.insert(1.,&f33barto6bar6u[flow_]);
}
break;
case Colour88to66bar:
static ColourLines f88to66t[12]=
{ColourLines("1 4:2, 4:1 2:1 3, -1 2:2 -5:2, -3 -5:1"),
ColourLines("1 4:1, 4:2 2:2 3, -1 2:1 -5:2, -3 -5:1"),
ColourLines("1 4:2, 4:1 2:1 3, -1 2:2 -5:1, -3 -5:2"),
ColourLines("1 4:1, 4:2 2:2 3, -1 2:1 -5:1, -3 -5:2"),
ColourLines("1 4:2, 4:1 2:2 -5:2, -1 2:1 3, -3 -5:1"),
ColourLines("1 4:1, 4:2 2:2 -5:2, -1 2:1 3, -3 -5:1"),
ColourLines("1 4:2, 4:1 2:2 -5:1, -1 2:1 3, -3 -5:2"),
ColourLines("1 4:1, 4:2 2:2 -5:1, -1 2:1 3, -3 -5:2"),
ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines("")};
static ColourLines f88to66u[12]=
{ColourLines("1 2:2 4:2, 4:1 3, -1 -5:2, -3 2:1 -5:1"),
ColourLines("1 2:1 4:1, 4:2 3, -1 -5:2, -3 2:2 -5:1"),
ColourLines("1 2:2 4:2, 4:1 3, -1 -5:1, -3 2:1 -5:2"),
ColourLines("1 2:1 4:1, 4:2 3, -1 -5:1, -3 2:2 -5:2"),
ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines(""),
ColourLines("-1 -5:1, -5:2 2:2 4:1, 1 2:1 -3, 3 4:2"),
ColourLines("-1 -5:1, -5:2 2:2 4:2, 1 2:1 -3, 3 4:1"),
ColourLines("-1 -5:2, -5:1 2:2 4:1, 1 2:1 -3, 3 4:2"),
ColourLines("-1 -5:2, -5:1 2:2 4:2, 1 2:1 -3, 3 4:1")};
static ColourLines f88to66s[12]=
{ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines(""),
ColourLines("1 3 4:2, 4:1 -5:2, -1 2, -2 -3 -5:1"),
ColourLines("1 3 4:1, 4:2 -5:2, -1 2, -2 -3 -5:1"),
ColourLines("1 3 4:2, 4:1 -5:1, -1 2, -2 -3 -5:2"),
ColourLines("1 3 4:1, 4:2 -5:1, -1 2, -2 -3 -5:2"),
ColourLines("-1 -3 -5:1, -5:2 4:1, 1 -2, 2 3 4:2"),
ColourLines("-1 -3 -5:1, -5:2 4:2, 1 -2, 2 3 4:1"),
ColourLines("-1 -3 -5:2, -5:1 4:1, 1 -2, 2 3 4:2"),
ColourLines("-1 -3 -5:2, -5:1 4:2, 1 -2, 2 3 4:1")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1., &f88to66s[flow_]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second) {
sel.insert(1., &f88to66t[flow_]);
}
else {
sel.insert(1., &f88to66u[flow_]);
}
}
break;
case Colour33to61:
static ColourLines f33to61t[2]
={ColourLines("1 4:1, 3 2 4:2"),
ColourLines("1 4:2, 3 2 4:1")};
static ColourLines f33to61u[2]
={ColourLines("1 2 4:1, 3 4:2"),
ColourLines("1 2 4:2, 3 4:1")};
static ColourLines f33to61s[2]
={ColourLines("1 3:1 4:1, 2 3:2 4:2"),
ColourLines("1 3:2 4:2, 2 3:1 4:1")};
if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f33to61t[flow_]);
else
sel.insert(1., &f33to61u[flow_]);
}
else {
sel.insert(1., &f33to61s[flow_]);
}
break;
case Colour33to16:
static ColourLines f33to16t[2]
={ColourLines("1 2 5:1, 3 5:2"),
ColourLines("1 2 5:2, 3 5:1")};
static ColourLines f33to16u[2]
={ColourLines("1 5:1, 3 2 5:2"),
ColourLines("1 5:2, 3 2 5:1")};
static ColourLines f33to16s[2]
={ColourLines("1 3:1 5:1, 2 3:2 5:2"),
ColourLines("1 3:2 5:2, 2 3:1 5:1")};
if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f33to16t[flow_]);
else
sel.insert(1., &f33to16u[flow_]);
}
else {
sel.insert(1., &f33to16s[flow_]);
}
break;
case Colour3bar3barto6bar1:
static ColourLines f3bar3barto6bar1t[2]
={ColourLines("-1 -4:1, -3 -2 -4:2"),
ColourLines("-1 -4:2, -3 -2 -4:1")};
static ColourLines f3bar3barto6bar1u[2]
={ColourLines("-1 -2 -4:1, -3 -4:2"),
ColourLines("-1 -2 -4:2, -3 -4:1")};
static ColourLines f3bar3barto6bar1s[2]
={ColourLines("-1 -3:1 -4:1, -2 -3:2 -4:2"),
ColourLines("-1 -3:2 -4:2, -2 -3:1 -4:1")};
if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f3bar3barto6bar1t[flow_]);
else
sel.insert(1., &f3bar3barto6bar1u[flow_]);
}
else {
sel.insert(1., &f3bar3barto6bar1s[flow_]);
}
break;
case Colour3bar3barto16bar:
static ColourLines f3bar3barto16bart[2]
={ColourLines("-1 -2 -5:1, -3 -5:2"),
ColourLines("-1 -2 -5:2, -3 -5:1")};
static ColourLines f3bar3barto16baru[2]
={ColourLines("-1 -5:1, -3 -2 -5:2"),
ColourLines("-1 -5:2, -3 -2 -5:1")};
static ColourLines f3bar3barto16bars[2]
={ColourLines("-1 -3:1 -5:1, -2 -3:2 -5:2"),
ColourLines("-1 -3:2 -5:2, -2 -3:1 -5:1")};
if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f3bar3barto16bart[flow_]);
else
sel.insert(1., &f3bar3barto16baru[flow_]);
}
else {
sel.insert(1., &f3bar3barto16bars[flow_]);
}
break;
case Colour38to3bar6:
static ColourLines f38to3bar6t[8]
={ColourLines("1 2:1 -3, -4 2:2 5:1, 3 5:2"),
ColourLines("1 2:1 -3, -4 2:2 5:2, 3 5:1"),
ColourLines("1 2:1 5:1, -4 2:2 -3, 3 5:2"),
ColourLines("1 2:1 5:2, -4 2:2 -3, 3 5:1"),
ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines("")};
static ColourLines f38to3bar6u[8]
={ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines(""),
ColourLines("1 5:1, 3 2 5:2, -4 -3"),
ColourLines("1 5:2, 3 2 5:1, -4 -3"),
ColourLines(""),ColourLines("")};
static ColourLines f38to3bar6s[8]
={ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines(""),
ColourLines("1 -2, 2 3 5:1, -4 5:2"),
ColourLines("1 -2, 2 3 5:2, -4 5:1")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1., &f38to3bar6s[flow_]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f38to3bar6t[flow_]);
else
sel.insert(1., &f38to3bar6u[flow_]);
}
break;
case Colour38to63bar:
static ColourLines f38to63baru[8]
={ColourLines("1 2:1 -3, -5 2:2 4:1, 3 4:2"),
ColourLines("1 2:1 -3, -5 2:2 4:2, 3 4:1"),
ColourLines("1 2:1 4:1, -5 2:2 -3, 3 4:2"),
ColourLines("1 2:1 4:2, -5 2:2 -3, 3 4:1"),
ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines("")};
static ColourLines f38to63bart[8]
={ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines(""),
ColourLines("1 4:1, 3 2 4:2, -5 -3"),
ColourLines("1 4:2, 3 2 4:1, -5 -3"),
ColourLines(""),ColourLines("")};
static ColourLines f38to63bars[8]
={ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines(""),
ColourLines(""),ColourLines(""),
ColourLines("1 -2, 2 3 4:1, -5 4:2"),
ColourLines("1 -2, 2 3 4:2, -5 4:1")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1., &f38to63bars[flow_]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f38to63bart[flow_]);
else
sel.insert(1., &f38to63baru[flow_]);
}
break;
case Colour33to13bar:
static ColourLines f33to13bar[3]={ColourLines("1 -6, 2 -6, -5 -3 -6"),
ColourLines("1 2 -6, 3 -6, -5 -6"),
ColourLines("1 -6, 3 2 -6, -5 -6")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1., &f33to13bar[0]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f33to13bar[1]);
else
sel.insert(1., &f33to13bar[2]);
}
break;
case Colour33to3bar1:
static ColourLines f33to3bar1[3]={ColourLines("1 -6, 2 -6, -4 -3 -6"),
ColourLines("1 -6, 3 2 -6, -4 -6"),
ColourLines("1 2 -6, 3 -6, -4 -6")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1., &f33to3bar1[0]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f33to3bar1[1]);
else
sel.insert(1., &f33to3bar1[2]);
}
break;
case Colour3bar3barto13:
static ColourLines f3bar3barto13[3]={ColourLines("-1 6, -2 6, 5 3 6"),
ColourLines("-1 2 6, -3 6, 5 6"),
ColourLines("-1 6, -3 2 6, 5 6")};
if(current.channelType == HPDiagram::sChannel) {
sel.insert(1., &f3bar3barto13[0]);
}
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second) {
sel.insert(1., &f3bar3barto13[1]);
}
else {
sel.insert(1., &f3bar3barto13[2]);
}
}
break;
case Colour3bar3barto31:
static ColourLines f3bar3barto31[3]={ColourLines("-1 6, -2 6, 4 3 6"),
- ColourLines("-1 6, -3 -2 6, 4 6"),
- ColourLines("-1 -2 6, -3 6, 4 6")};
+ ColourLines("-1 6, -3 2 6, 4 6"),
+ ColourLines("-1 2 6, -3 6, 4 6")};
if(current.channelType == HPDiagram::sChannel)
sel.insert(1., &f3bar3barto31[0]);
else if(current.channelType == HPDiagram::tChannel) {
if(current.ordered.second)
sel.insert(1., &f3bar3barto31[1]);
else
sel.insert(1., &f3bar3barto31[2]);
}
break;
case Colour33to83bar:
static ColourLines f33to83bar[3]={ColourLines("1 -6, 2 -6, -5 4, -4 -3 -6"),
ColourLines("1 4, -4 2 -6, 3 -6, -5 -6"),
ColourLines("1 -6, 3 4, -4 2 -6, -5 -6")};
sel.insert(1., &f33to83bar[flow_]);
break;
case Colour33to3bar8:
static ColourLines f33to3bar8[3]={ColourLines("1 -6, 2 -6, -4 5, -5 -3 -6"),
ColourLines("1 -6, 3 5, -5 2 -6, -4 -6"),
ColourLines("1 5, -5 2 -6, 3 -6, -4 -6")};
sel.insert(1., &f33to3bar8[flow_]);
break;
case Colour3bar3barto83:
static ColourLines f3bar3barto83[3]={ColourLines("-1 6, -2 6, 5 -4, 4 3 6"),
ColourLines("-1 -4, 4 2 6, -3 6, 5 6"),
ColourLines("-1 6, -3 -4, 4 2 6, 5 6")};
sel.insert(1., &f3bar3barto83[flow_]);
break;
case Colour3bar3barto38:
static ColourLines f3bar3barto38[3]={ColourLines("-1 6, -2 6, 4 -5, 5 3 6"),
ColourLines("-1 6, -3 -5, 5 -2 6, 4 6"),
ColourLines("-1 -5, 5 -2 6, -3 6, 4 6")};
sel.insert(1., &f3bar3barto38[flow_]);
break;
case Colour38to3bar3bar:
static ColourLines f38to3bar3bar[3]={ColourLines("1 -2, 2 3 -6, -4 -6, -5 -6"),
ColourLines("1 -6, 3 2 -6, -3 -5, -4 -6"),
ColourLines("1 -6, 3 2 -6, -3 -4, -5 -6")};
sel.insert(1., &f38to3bar3bar[flow_]);
break;
case Colour3bar8to33:
static ColourLines f3bar8to33[3]={ColourLines("-1 2, -2 -3 6, 4 6, 5 6"),
ColourLines("-1 6, -3 2 6, 3 5, 4 6"),
ColourLines("-1 6, -3 2 6, 3 4, 5 6")};
sel.insert(1., &f3bar8to33[flow_]);
break;
default:
assert(false);
}
return sel;
}
double GeneralHardME::
selectColourFlow(vector<double> & flow,vector<double> & me,
double average) const {
// spin average
double output = 0.25*average;
// special for beam polarization
tcPolarizedBeamPDPtr beam[2] =
{dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[0]),
dynamic_ptr_cast<tcPolarizedBeamPDPtr>(mePartonData()[1])};
if( beam[0] || beam[1] ) {
RhoDMatrix rho[2] =
{beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()),
beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())};
for(unsigned int ix = 0;ix<numberOfFlows();++ix)
flow[ix] = flowME_[ix].average(rho[0],rho[1]);
for(unsigned int ix = 0;ix<numberOfDiags();++ix)
me [ix] = diagramME_[ix].average(rho[0],rho[1]);
output = 0.;
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii)
for(unsigned int ij = 0; ij < numberOfFlows(); ++ij)
output += real(getColourFactors()[ii][ij]*
flowME_[ii].average(flowME_[ij],rho[0],rho[1]));
// correction for photons and gluons
if(mePartonData()[0]->id()==ParticleID::g ||
mePartonData()[0]->id()==ParticleID::gamma) output *= 1.5;
if(mePartonData()[1]->id()==ParticleID::g ||
mePartonData()[1]->id()==ParticleID::gamma) output *= 1.5;
}
// select the colour flow
double maxWgt = UseRandom::rnd()*std::accumulate(flow.begin(),flow.end(),0.);
flow_ = flow.size();
for(unsigned int ix=0;ix<flow.size();++ix) {
if(flow[ix]>=maxWgt) {
flow_=ix;
break;
}
maxWgt -= flow[ix];
}
assert(flow_<flow.size());
// select the diagram
for(unsigned int ix=0;ix<numberOfDiags();++ix) {
const HPDiagram & current = getProcessInfo()[ix];
bool found=false;
for(unsigned int iy = 0; iy < current.colourFlow.size(); ++iy) {
if(current.colourFlow[iy].first==flow_) {
me[ix] *= sqr(current.colourFlow[iy].second);
found = true;
}
}
// set to zero if four point diagram or doesn't contribute to colour flow
if(!found || current.channelType == HPDiagram::fourPoint) me[ix]=0.;
}
maxWgt = UseRandom::rnd()*std::accumulate(me.begin(),me.end(),0.);
for(unsigned int ix=0;ix<me.size();++ix) {
if(me[ix]>maxWgt) {
diagram_=ix;
break;
}
maxWgt -= me[ix];
}
// colour factors
output /= max(1,abs(int(mePartonData()[0]->iColour())));
output /= max(1,abs(int(mePartonData()[1]->iColour())));
// identical particle factor
output *= mePartonData()[2]->id() == mePartonData()[3]->id() ? 0.5 : 1;
// return the answer
return output;
}
void GeneralHardME::doinitrun() {
HwMEBase::doinitrun();
for(unsigned int ix=0;ix<diagrams_.size();++ix) {
diagrams_[ix].vertices.first ->initrun();
diagrams_[ix].vertices.second->initrun();
}
}
diff --git a/MatrixElement/General/GeneralfftoffH.cc b/MatrixElement/General/GeneralfftoffH.cc
--- a/MatrixElement/General/GeneralfftoffH.cc
+++ b/MatrixElement/General/GeneralfftoffH.cc
@@ -1,174 +1,178 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the GeneralfftoffH class.
//
#include "GeneralfftoffH.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include"ThePEG/Utilities/EnumIO.h"
using namespace Herwig;
GeneralfftoffH::GeneralfftoffH() {}
IBPtr GeneralfftoffH::clone() const {
return new_ptr(*this);
}
IBPtr GeneralfftoffH::fullclone() const {
return new_ptr(*this);
}
void GeneralfftoffH::persistentOutput(PersistentOStream & os) const {
os << oenum(_proc);
}
void GeneralfftoffH::persistentInput(PersistentIStream & is, int) {
is >> ienum(_proc);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<GeneralfftoffH,MEfftoffH>
describeHerwigGeneralfftoffH("Herwig::GeneralfftoffH", "Herwig.so");
void GeneralfftoffH::Init() {
static ClassDocumentation<GeneralfftoffH> documentation
("There is no documentation for the GeneralfftoffH class");
}
void GeneralfftoffH::getDiagrams() const {
if(_proc==Lepton) {
for(long ix=11;ix<=13;ix+=1) {
tcPDPtr em(getParticleData(ix));
tcPDPtr ep(em->CC());
// WW processes
if(process()==0||process()==1) {
tcPDPtr nue(getParticleData(ix+1));
tcPDPtr nueb(nue->CC());
add(new_ptr((Tree2toNDiagram(4), em, WMinus(), WPlus(), ep,
1, nue, 4, nueb, 2, higgs(),-1)));
}
// ZZ processes
if(process()==0||process()==2) {
add(new_ptr((Tree2toNDiagram(4), em, Z0(), Z0(), ep,
1, em, 4, ep, 2, higgs(),-2)));
}
}
}
else {
// WW processes
if(process()==0||process()==1) {
std::vector<pair<tcPDPtr,tcPDPtr> > parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxFlavour()) {
case 5:
if (minFlavour()<=4)
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::c)));
if (minFlavour()<=2)
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::u)));
+ [[fallthrough]];
case 4:
if (minFlavour()<=3)
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::c)));
if (minFlavour()<=1)
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::c)));
+ [[fallthrough]];
case 3:
if (minFlavour()<=2)
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::u)));
+ [[fallthrough]];
case 2:
if (minFlavour()<=1)
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::u)));
+ [[fallthrough]];
default:
;
}
for(unsigned int ix=0;ix<parentpair.size();++ix) {
for(unsigned int iy=0;iy<parentpair.size();++iy) {
// q1 q2 -> q1' q2' h
if(parentpair[ix].first->id()<parentpair[iy].second->id()) {
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(),
parentpair[iy].second, 1, parentpair[ix].second, 4,
parentpair[iy].first, 2, higgs(),-1)));
}
else {
add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second, WPlus(), WMinus(),
parentpair[ix].first, 1, parentpair[iy].first, 4,
parentpair[ix].second, 2, higgs(),-1)));
}
// q1 qbar2 -> q1' qbar2' h
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(),
parentpair[iy].first->CC(), 1,
parentpair[ix].second, 4, parentpair[iy].second->CC(),
2, higgs(),-1)));
add(new_ptr((Tree2toNDiagram(4),parentpair[iy].second, WPlus(), WMinus(),
parentpair[ix].second->CC(), 1, parentpair[iy].first,
4, parentpair[ix].first->CC(),
2, higgs(),-1)));
// qbar1 qbar2 -> qbar1' qbar2' h
if(parentpair[ix].first->id()<parentpair[ix].second->id()) {
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first->CC(),
WPlus(), WMinus(),
parentpair[iy].second->CC(), 1,
parentpair[ix].second->CC(), 4, parentpair[iy].first->CC(),
2, higgs(),-1)));
}
else {
add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second->CC(),
WMinus(), WPlus(),
parentpair[ix].first->CC(), 1,
parentpair[iy].first->CC(), 4, parentpair[ix].second->CC(),
2, higgs(),-1)));
}
}
}
}
// ZZ processes
if(process()==0||process()==2) {
// get the quark particle data objects as we'll be using them
tcPDPtr q[6],qbar[6];
for ( int ix=0; ix<5; ++ix ) {
q [ix] = getParticleData(ix+1);
qbar[ix] = q[ix]->CC();
}
for(unsigned int ix=minFlavour()-1;ix<maxFlavour();++ix) {
for(unsigned int iy=ix;iy<maxFlavour();++iy) {
// q q -> q q H
add(new_ptr((Tree2toNDiagram(4), q[ix], Z0(), Z0(), q[iy],
1, q[ix], 4, q[iy], 2, higgs(),-2)));
// qbar qbar -> qbar qbar H
add(new_ptr((Tree2toNDiagram(4), qbar[ix], Z0(), Z0(), qbar[iy],
1, qbar[ix], 4, qbar[iy], 2, higgs(),-2)));
}
// q qbar -> q qbar H
for(unsigned int iy=minFlavour()-1;iy<maxFlavour();++iy) {
add(new_ptr((Tree2toNDiagram(4), q[ix], Z0(), Z0(), qbar[iy],
1, q[ix], 4, qbar[iy], 2, higgs(),-2)));
}
}
}
}
}
void GeneralfftoffH::setProcessInfo(Process proc, PDPtr hin,
AbstractVVSVertexPtr vertex,
unsigned int shapeOpt,
unsigned int iproc) {
higgs(hin);
_proc = proc;
setWWHVertex(vertex);
lineShape(shapeOpt);
process(iproc);
}
diff --git a/MatrixElement/General/MEff2ff.cc b/MatrixElement/General/MEff2ff.cc
--- a/MatrixElement/General/MEff2ff.cc
+++ b/MatrixElement/General/MEff2ff.cc
@@ -1,611 +1,616 @@
// -*- C++ -*-
//
// MEff2ff.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEff2ff class.
//
#include "MEff2ff.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using ThePEG::Helicity::VectorWaveFunction;
using ThePEG::Helicity::ScalarWaveFunction;
using ThePEG::Helicity::TensorWaveFunction;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
void MEff2ff::doinit() {
GeneralHardME::doinit();
scalar_.resize(numberOfDiags());
vector_.resize(numberOfDiags());
tensor_.resize(numberOfDiags());
+ four_ .resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
PDT::Spin1Half, PDT::Spin1Half);
for(size_t ix = 0;ix < numberOfDiags(); ++ix) {
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
- if(offshell->iSpin() == PDT::Spin0) {
+ if(!offshell) {
+ four_[ix] = dynamic_ptr_cast<AbstractFFFFVertexPtr>
+ (current.vertices.first);
+ }
+ else if(offshell->iSpin() == PDT::Spin0) {
AbstractFFSVertexPtr vert1 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.first);
AbstractFFSVertexPtr vert2 = dynamic_ptr_cast<AbstractFFSVertexPtr>
(current.vertices.second);
scalar_[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);
vector_[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);
tensor_[ix] = make_pair(vert1, vert2);
}
}
}
double MEff2ff::me2() const {
- tcPDPtr ina (mePartonData()[0]), inb (mePartonData()[1]);
- tcPDPtr outa(mePartonData()[2]), outb(mePartonData()[3]);
for(unsigned int ix=0;ix<4;++ix) {
spin_[ix].clear();
sbar_[ix].clear();
for(unsigned int ih=0;ih<2;++ih) {
spin_[ix].push_back(SpinorWaveFunction (rescaledMomenta()[ix],
mePartonData()[ix],
ih, ix<2 ? incoming : outgoing));
sbar_[ix].push_back(SpinorBarWaveFunction(rescaledMomenta()[ix],
mePartonData()[ix],
ih, ix<2 ? incoming : outgoing));
}
}
double full_me(0.);
- if( ina->id() > 0 && inb->id() < 0) {
+ if( mePartonData()[0]->id() > 0 && mePartonData()[1]->id() < 0) {
ffb2ffbHeME (full_me,true);
}
- else if( ina->id() > 0 && inb->id() > 0 )
+ else if( mePartonData()[0]->id() > 0 && mePartonData()[1]->id() > 0 )
ff2ffHeME(full_me,true);
- else if( ina->id() < 0 && inb->id() < 0 )
+ else if( mePartonData()[0]->id() < 0 && mePartonData()[1]->id() < 0 )
fbfb2fbfbHeME(full_me,true);
- else
- throw MEException()
- << "MEff2ff::me2() - Cannot find correct function to deal with process "
- << ina->PDGName() << "," << inb->PDGName() << "->" << outa->PDGName()
- << "," << outb->PDGName() << "\n";
+ else
+ assert(false);
#ifndef NDEBUG
if( debugME() ) debug(full_me);
#endif
return full_me;
}
ProductionMatrixElement
MEff2ff::ffb2ffbHeME(double & me2, bool first) const {
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
// flow over the helicities and diagrams
for(unsigned int ifhel1 = 0; ifhel1 < 2; ++ifhel1) {
for(unsigned int ifhel2 = 0; ifhel2 < 2; ++ifhel2) {
for(unsigned int ofhel1 = 0; ofhel1 < 2; ++ofhel1) {
for(unsigned int ofhel2 = 0; ofhel2 < 2; ++ofhel2) {
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if(current.channelType == HPDiagram::tChannel) {
+ if(offshell->CC()) offshell=offshell->CC();
if(offshell->iSpin() == PDT::Spin0) {
if(current.ordered.second) {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 3, offshell,spin_[3][ofhel2],sbar_[1][ifhel2]);
diag = -scalar_[ix].first->
evaluate(q2, spin_[0][ifhel1],sbar_[2][ofhel1],interS);
}
else {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 3, offshell,spin_[2][ofhel1],sbar_[1][ifhel2]);
diag = scalar_[ix].first->
evaluate(q2, spin_[0][ifhel1],sbar_[3][ofhel2],interS);
}
}
else if(offshell->iSpin() == PDT::Spin1) {
if(current.ordered.second) {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 3, offshell,spin_[3][ofhel2],sbar_[1][ifhel2]);
diag = -vector_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[2][ofhel1], interV);
}
else {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 3, offshell,spin_[2][ofhel1],sbar_[1][ifhel2]);
diag = vector_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[3][ofhel2], interV);
}
}
else if(offshell->iSpin() == PDT::Spin2) {
if(current.ordered.second) {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 3, offshell,spin_[3][ofhel2],sbar_[1][ifhel2]);
diag = -tensor_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[2][ofhel1], interT);
}
else {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 3, offshell,spin_[2][ofhel1],sbar_[1][ifhel2]);
diag = tensor_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[3][ofhel2], interT);
}
}
}
else if(current.channelType == HPDiagram::sChannel) {
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = scalar_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interS);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = vector_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interV);
}
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = tensor_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interT);
}
}
- else assert(false);
+ else {
+ diag = four_[ix]->evaluate(q2,spin_[0][ifhel1], sbar_[1][ifhel2],
+ spin_[3][ofhel2],sbar_[2][ofhel1]);
+ }
me[ix] += norm(diag);
diagramME()[ix](ifhel1, ifhel2, ofhel1, ofhel2) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](ifhel1, ifhel2, ofhel1, ofhel2) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii) {
for(size_t ij = 0; ij < numberOfFlows(); ++ij) {
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
}
}
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
ProductionMatrixElement
MEff2ff:: ff2ffHeME(double & me2, bool first) const {
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
// flow over the helicities and diagrams
for(unsigned int ifhel1 = 0; ifhel1 < 2; ++ifhel1) {
for(unsigned int ifhel2 = 0; ifhel2 < 2; ++ifhel2) {
for(unsigned int ofhel1 = 0; ofhel1 < 2; ++ofhel1) {
for(unsigned int ofhel2 = 0; ofhel2 < 2; ++ofhel2) {
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
+ if(offshell->CC()) offshell=offshell->CC();
if(current.channelType == HPDiagram::tChannel) {
if(offshell->iSpin() == PDT::Spin0) {
if(current.ordered.second) {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 3, offshell,spin_[1][ifhel2],sbar_[3][ofhel2]);
diag = scalar_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[2][ofhel1], interS);
}
else {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 3, offshell,spin_[1][ifhel2],sbar_[2][ofhel1]);
diag = -scalar_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[3][ofhel2], interS);
}
}
else if(offshell->iSpin() == PDT::Spin1) {
if(current.ordered.second) {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 3, offshell,spin_[1][ifhel2],sbar_[3][ofhel2]);
diag = vector_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[2][ofhel1], interV);
}
else {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 3, offshell,spin_[1][ifhel2],sbar_[2][ofhel1]);
diag = -vector_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[3][ofhel2], interV);
}
}
else if(offshell->iSpin() == PDT::Spin2) {
if(current.ordered.second) {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 3, offshell,spin_[1][ifhel2],sbar_[3][ofhel2]);
diag = tensor_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[2][ofhel1], interT);
}
else {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 3, offshell,spin_[1][ifhel2],sbar_[2][ofhel1]);
diag = -tensor_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[3][ofhel2], interT);
}
}
}
else if(current.channelType == HPDiagram::sChannel) {
- if(offshell->CC()) offshell=offshell->CC();
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = scalar_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interS);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = vector_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interV);
}
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = tensor_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interT);
}
}
- else
- assert(false);
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag= four_[ix]->evaluate(q2,spin_[0][ifhel1],sbar_[2][ofhel1],
+ spin_[1][ifhel2],sbar_[3][ofhel2]);
+ }
me[ix] += norm(diag);
diagramME()[ix](ifhel1, ifhel2, ofhel1, ofhel2) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](ifhel1, ifhel2, ofhel1, ofhel2) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
ProductionMatrixElement
MEff2ff::fbfb2fbfbHeME(double & me2, bool first) const {
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
// flow over the helicities and diagrams
for(unsigned int ifhel1 = 0; ifhel1 < 2; ++ifhel1) {
for(unsigned int ifhel2 = 0; ifhel2 < 2; ++ifhel2) {
for(unsigned int ofhel1 = 0; ofhel1 < 2; ++ofhel1) {
for(unsigned int ofhel2 = 0; ofhel2 < 2; ++ofhel2) {
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
+ if(offshell->CC()) offshell=offshell->CC();
if(current.channelType == HPDiagram::tChannel) {
if(offshell->iSpin() == PDT::Spin0) {
if(current.ordered.second) {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 3, offshell,spin_[3][ofhel2],sbar_[1][ifhel2]);
diag = scalar_[ix].first->
evaluate(q2, spin_[2][ofhel1], sbar_[0][ifhel1], interS);
}
else {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 3, offshell,spin_[2][ofhel1],sbar_[1][ifhel2]);
diag = -scalar_[ix].first->
evaluate(q2, spin_[3][ofhel2], sbar_[0][ifhel1], interS);
}
}
else if(offshell->iSpin() == PDT::Spin1) {
if(current.ordered.second) {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 3, offshell,spin_[3][ofhel2],sbar_[1][ifhel2]);
diag = vector_[ix].first->
evaluate(q2, spin_[2][ofhel1], sbar_[0][ifhel1], interV);
}
else {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 3, offshell,spin_[2][ofhel1],sbar_[1][ifhel2]);
diag = -vector_[ix].first->
evaluate(q2, spin_[3][ofhel2], sbar_[0][ifhel1], interV);
}
}
else if(offshell->iSpin() == PDT::Spin2) {
if(current.ordered.second) {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 3, offshell,spin_[3][ofhel2],sbar_[1][ifhel2]);
diag = tensor_[ix].first->
evaluate(q2, spin_[2][ofhel1], sbar_[0][ifhel1], interT);
}
else {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 3, offshell,spin_[2][ofhel1],sbar_[1][ifhel2]);
diag = -tensor_[ix].first->
evaluate(q2, spin_[3][ofhel2], sbar_[0][ifhel1], interT);
}
}
}
else if(current.channelType == HPDiagram::sChannel) {
- if(offshell->CC()) offshell=offshell->CC();
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction interS = scalar_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = scalar_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interS);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = vector_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interV);
}
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction interT = tensor_[ix].second->
evaluate(q2, 1, offshell,spin_[3][ofhel2],sbar_[2][ofhel1]);
diag = tensor_[ix].first->
evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interT);
}
}
- else {
- assert(false);
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag= four_[ix]->evaluate(q2,spin_[2][ofhel1],sbar_[0][ifhel1],
+ spin_[3][ofhel2],sbar_[1][ifhel2]);
}
me[ix] += norm(diag);
diagramME()[ix](ifhel1, ifhel2, ofhel1, ofhel2) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](ifhel1, ifhel2, ofhel1, ofhel2) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEff2ff::constructVertex(tSubProPtr subp) {
// Hard process external particles
ParticleVector hardpro = hardParticles(subp);
//Need to use rescale momenta to calculate matrix element
setRescaledMomenta(hardpro);
for(unsigned int ix=0;ix<4;++ix) {
spin_[ix].clear();
sbar_[ix].clear();
- for(unsigned int ih=0;ih<2;++ih) {
- SpinorWaveFunction (spin_[ix],hardpro[ix],
- ix<2 ? incoming : outgoing,ix>1);
- SpinorBarWaveFunction(sbar_[ix],hardpro[ix],
- ix<2 ? incoming : outgoing,ix>1);
- }
+ SpinorWaveFunction (spin_[ix],hardpro[ix],
+ ix<2 ? incoming : outgoing,ix>1);
+ SpinorBarWaveFunction(sbar_[ix],hardpro[ix],
+ ix<2 ? incoming : outgoing,ix>1);
}
double dummy(0.);
//pick which process we are doing
if( hardpro[0]->id() > 0) {
//ffbar->ffbar
if( hardpro[1]->id() < 0 ) {
ProductionMatrixElement prodME = ffb2ffbHeME(dummy,false);
createVertex(prodME,hardpro);
}
//ff2ff
else {
ProductionMatrixElement prodME = ff2ffHeME(dummy,false);
createVertex(prodME,hardpro);
}
}
//fbarfbar->fbarfbar
else {
ProductionMatrixElement prodME = fbfb2fbfbHeME(dummy,false);
createVertex(prodME,hardpro);
}
#ifndef NDEBUG
if( debugME() ) debug(dummy);
#endif
}
void MEff2ff::persistentOutput(PersistentOStream & os) const {
- os << scalar_ << vector_ << tensor_;
+ os << scalar_ << vector_ << tensor_ << four_;
}
void MEff2ff::persistentInput(PersistentIStream & is, int) {
- is >> scalar_ >> vector_ >> tensor_;
+ is >> scalar_ >> vector_ >> tensor_ >> four_;
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
PDT::Spin1Half, PDT::Spin1Half);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEff2ff,GeneralHardME>
describeHerwigMEff2ff("Herwig::MEff2ff", "Herwig.so");
void MEff2ff::Init() {
static ClassDocumentation<MEff2ff> documentation
("This is the implementation of the matrix element for fermion-"
"antifermion -> fermion-antifermion.");
}
void MEff2ff::debug(double me2) const {
if( !generator()->logfile().is_open() ) return;
long id1 = mePartonData()[0]->id();
long id2 = mePartonData()[1]->id();
long id3 = mePartonData()[2]->id();
long id4 = mePartonData()[3]->id();
long aid1 = abs(mePartonData()[0]->id());
long aid2 = abs(mePartonData()[1]->id());
long aid3 = abs(mePartonData()[2]->id());
long aid4 = abs(mePartonData()[3]->id());
if( (aid1 != 1 && aid1 != 2) || (aid2 != 1 && aid2 != 2) ) return;
double analytic(0.);
if( id3 == id4 && id3 == 1000021 ) {
tcSMPtr sm = generator()->standardModel();
double gs4 = sqr( 4.*Constants::pi*sm->alphaS(scale()) );
int Nc = sm->Nc();
double Cf = (sqr(Nc) - 1.)/2./Nc;
Energy2 mgo2 = meMomenta()[3].m2();
long squark = (aid1 == 1) ? 1000001 : 1000002;
Energy2 muL2 = sqr(getParticleData(squark)->mass());
Energy2 deltaL = muL2 - mgo2;
Energy2 muR2 = sqr(getParticleData(squark + 1000000)->mass());
Energy2 deltaR = muR2 - mgo2;
Energy2 s(sHat());
Energy2 m3s = meMomenta()[2].m2();
Energy2 m4s = meMomenta()[3].m2();
Energy4 spt2 = uHat()*tHat() - m3s*m4s;
Energy2 t3(tHat() - m3s), u4(uHat() - m4s);
double Cl = 2.*spt2*( (u4*u4 - deltaL*deltaL) + (t3*t3 - deltaL*deltaL)
- (s*s/Nc/Nc) )/s/s/(u4 - deltaL)/(t3 - deltaL);
Cl += deltaL*deltaL*( (1./sqr(t3 - deltaL)) + (1./sqr(u4 - deltaL))
- ( sqr( (1./(t3 - deltaL)) -
(1./(u4 - deltaL)) )/Nc/Nc ) );
double Cr = 2.*spt2*( (u4*u4 - deltaR*deltaR) + (t3*t3 - deltaR*deltaR)
- (s*s/Nc/Nc) )/s/s/(u4 - deltaR)/(t3 - deltaR);
Cr += deltaR*deltaR*( (1./sqr(t3 - deltaR)) + (1./sqr(u4 - deltaR))
- ( sqr( (1./(t3 - deltaR))
- (1./(u4 - deltaR)) )/Nc/Nc ) );
analytic = gs4*Cf*(Cl + Cr)/4.;
}
else if( (aid3 == 5100001 || aid3 == 5100002 ||
aid3 == 6100001 || aid3 == 6100002) &&
(aid4 == 5100001 || aid4 == 5100002 ||
aid4 == 6100001 || aid4 == 6100002) ) {
tcSMPtr sm = generator()->standardModel();
double gs4 = sqr( 4.*Constants::pi*sm->alphaS(scale()) );
Energy2 s(sHat());
Energy2 mf2 = meMomenta()[2].m2();
Energy2 t3(tHat() - mf2), u4(uHat() - mf2);
Energy4 s2(sqr(s)), t3s(sqr(t3)), u4s(sqr(u4));
bool iflav = (aid2 - aid1 == 0);
int alpha(aid3/1000000), beta(aid4/1000000);
bool oflav = ((aid3 - aid1) % 10 == 0);
if( alpha != beta ) {
if( ( id1 > 0 && id2 > 0) ||
( id1 < 0 && id2 < 0) ) {
if( iflav )
analytic = gs4*( mf2*(2.*s2*s/t3s/u4s - 4.*s/t3/u4)
+ 2.*sqr(s2)/t3s/u4s - 8.*s2/t3/u4 + 5. )/9.;
else
analytic = gs4*( -2.*mf2*(1./t3 + u4/t3s) + 0.5 + 2.*u4s/t3s)/9.;
}
else
analytic = gs4*( 2.*mf2*(1./t3 + u4/t3s) + 5./2. + 4.*u4/t3
+ 2.*u4s/t3s)/9.;
}
else {
if( ( id1 > 0 && id2 > 0) ||
( id1 < 0 && id2 < 0) ) {
if( iflav ) {
analytic = gs4*( mf2*(6.*t3/u4s + 6.*u4/t3s - s/t3/u4)
+ 2.*(3.*t3s/u4s + 3.*u4s/t3s
+ 4.*s2/t3/u4 - 5.) )/27.;
}
else
analytic = 2.*gs4*( -mf2*s/t3s + 0.25 + s2/t3s )/9.;
}
else {
if( iflav ) {
if( oflav )
analytic = gs4*( 2.*mf2*(4./s + s/t3s - 1./t3) + 23./6.+ 2.*s2/t3s
+ 8.*s/3./t3 + 6.*t3/s + 8.*t3s/s2 )/9.;
else
analytic = 4.*gs4*( 2.*mf2/s + (t3s + u4s)/s2)/9.;
}
else
analytic = gs4*(4.*mf2*s/t3s + 5. + 4.*s2/t3s + 8.*s/t3 )/18.;
}
}
if( id3 == id4 ) analytic /= 2.;
}
else return;
double diff = abs(analytic - me2);
if( diff > 1e-4 ) {
generator()->log()
<< mePartonData()[0]->PDGName() << ","
<< mePartonData()[1]->PDGName() << "->"
<< mePartonData()[2]->PDGName() << ","
<< mePartonData()[3]->PDGName() << " difference: "
<< setprecision(10) << diff << " ratio: " << analytic/me2
<< '\n';
}
}
diff --git a/MatrixElement/General/MEff2ff.h b/MatrixElement/General/MEff2ff.h
--- a/MatrixElement/General/MEff2ff.h
+++ b/MatrixElement/General/MEff2ff.h
@@ -1,224 +1,220 @@
// -*- C++ -*-
//
// MEff2ff.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_MEff2ff_H
#define HERWIG_MEff2ff_H
//
// This is the declaration of the MEff2ff class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFFFVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::SpinorWaveFunction;
using Helicity::SpinorBarWaveFunction;
/**
* This is the implementation of the \f$ 2\to 2\f$ matrix element for
* a \f$ \Psi \Psi \to \Psi \Psi\f$ process. It inherits from
* GeneralHardME and implements the appropriate virtual functions.
*
- * @see \ref MEff2ffInterfaces "The Interfaces"
- * defined for MEff2ff.
* @see GeneralHardME
*/
class MEff2ff: public GeneralHardME {
public:
/** Vector of SpinorWaveFunctions. */
typedef vector<SpinorWaveFunction> SpinorVector;
/** Vector of SpinorBarWaveFunctions. */
typedef vector<SpinorBarWaveFunction> SpinorBarVector;
public:
- /**
- * The default constructor.
- */
- MEff2ff() : scalar_(0), vector_(0), tensor_(0), spin_(4), sbar_(4)
- {}
-
-public:
-
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
private:
/** @name Functions to compute the ProductionMatrixElement. */
//@{
/**
* Compute the matrix element for \f$\Psi\bar{\Psi}\to\Psi\bar{\Psi}\f$
* @param me2 colour averaged, spin summed ME
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @return ProductionMatrixElement containing results of
* helicity calculations
*/
ProductionMatrixElement
ffb2ffbHeME(double & me2, bool first) const;
/**
* Compute the matrix element for \f$\Psi\Psi\to\Psi\Psi\f$
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @return ProductionMatrixElement containing results of
* helicity calculations
*/
ProductionMatrixElement ff2ffHeME(double & me2, bool first) const;
/**
* Compute the matrix element for
* \f$\bar{\Psi}\bar{\Psi}\to\bar{\Psi}\bar{\Psi}\f$
* @param me2 colour averaged, spin summed ME
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @return ProductionMatrixElement containing results of
* helicity calculations
*/
ProductionMatrixElement fbfb2fbfbHeME(double & me2, bool first) const;
/**
* Compute the matrix element for \f$\Psi\bar{\Psi}\to\lambda\lambda\f$
* @param me2 colour averaged, spin summed ME
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @return ProductionMatrixElement containing results of
* helicity calculations
*/
ProductionMatrixElement
ffb2mfmfHeME(double & me2, bool first) const;
//@}
/**
* Construct the vertex information for the spin correlations
* @param sub Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr sub);
protected:
/**
* A debugging function to test the value of me2 against an
* analytic function.
* @param me2 The value of the \f$ |\bar{\mathcal{M}}|^2 \f$
*/
virtual void debug(double me2) 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 Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEff2ff & operator=(const MEff2ff &);
private:
/**
* Store the vector of FFSVertex pairs
*/
vector<pair<AbstractFFSVertexPtr, AbstractFFSVertexPtr> > scalar_;
/**
* Store the vector of FFVVertex pairs
*/
vector<pair<AbstractFFVVertexPtr, AbstractFFVVertexPtr> > vector_;
/**
* Store the vector of FFTVertex pairs
*/
vector<pair<AbstractFFTVertexPtr, AbstractFFTVertexPtr> > tensor_;
/**
+ * Store any 4-point vertices
+ */
+ vector<AbstractFFFFVertexPtr> four_;
+
+ /**
* Spinors
*/
- mutable vector<vector<SpinorWaveFunction> > spin_;
+ mutable std::array<SpinorVector,4> spin_;
/**
* Barred spinors
*/
- mutable vector<vector<SpinorBarWaveFunction> > sbar_;
+ mutable std::array<SpinorBarVector,4> sbar_;
};
}
#endif /* HERWIG_MEff2ff_H */
diff --git a/MatrixElement/General/MEff2rf.cc b/MatrixElement/General/MEff2rf.cc
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEff2rf.cc
@@ -0,0 +1,580 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the MEff2rf class.
+//
+
+#include "MEff2rf.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Utilities/DescribeClass.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+
+using namespace Herwig;
+
+
+double MEff2rf::me2() const {
+ // calculate the fermion spinors
+ for(unsigned int ix=0;ix<3;++ix) {
+ spin_[ix].clear();
+ sbar_[ix].clear();
+ unsigned int iy(ix);
+ if(ix==2) ++iy;
+ for(unsigned int ih=0;ih<2;++ih) {
+ spin_[ix].push_back(SpinorWaveFunction (rescaledMomenta()[iy],
+ mePartonData()[iy],
+ ih, ix<2 ? incoming : outgoing));
+ sbar_[ix].push_back(SpinorBarWaveFunction(rescaledMomenta()[iy],
+ mePartonData()[iy],
+ ih, ix<2 ? incoming : outgoing));
+ }
+ }
+ rs_ .clear();
+ rsbar_.clear();
+ // calculate the rs spinors
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ for(unsigned int ih=0;ih<4;++ih) {
+ if(massless && (ih==1 || ih==2) ) continue;
+ rs_ .push_back(RSSpinorWaveFunction(rescaledMomenta()[2],
+ mePartonData()[2],ih, outgoing));
+ rsbar_.push_back(RSSpinorBarWaveFunction(rescaledMomenta()[2],
+ mePartonData()[2],ih,outgoing));
+ }
+ double full_me(0.);
+ if( mePartonData()[0]->id() > 0 && mePartonData()[1]->id() < 0) {
+ if(mePartonData()[2]->id()>0)
+ ffb2rfbHeME (full_me,true);
+ else
+ ffb2rbfHeME (full_me,true);
+ }
+ else if( mePartonData()[0]->id() > 0 && mePartonData()[1]->id() > 0 )
+ ff2rfHeME(full_me,true);
+ else if( mePartonData()[0]->id() < 0 && mePartonData()[1]->id() < 0 )
+ fbfb2rbfbHeME(full_me,true);
+ else
+ assert(false);
+ return full_me;
+}
+
+IBPtr MEff2rf::clone() const {
+ return new_ptr(*this);
+}
+
+IBPtr MEff2rf::fullclone() const {
+ return new_ptr(*this);
+}
+
+void MEff2rf::doinit() {
+ GeneralHardME::doinit();
+ scalar_.resize(numberOfDiags());
+ vector_.resize(numberOfDiags());
+ initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
+ PDT::Spin3Half, PDT::Spin1Half);
+ for(size_t ix = 0;ix < numberOfDiags(); ++ix) {
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if(offshell->iSpin() == PDT::Spin0) {
+ if(current.channelType == HPDiagram::sChannel ||
+ (current.channelType == HPDiagram::tChannel &&
+ !current.ordered.second)) {
+ AbstractFFSVertexPtr vert1 = dynamic_ptr_cast<AbstractFFSVertexPtr>
+ (current.vertices.first);
+ AbstractRFSVertexPtr vert2 = dynamic_ptr_cast<AbstractRFSVertexPtr>
+ (current.vertices.second);
+ scalar_[ix] = make_pair(vert1, vert2);
+ }
+ else {
+ AbstractFFSVertexPtr vert1 = dynamic_ptr_cast<AbstractFFSVertexPtr>
+ (current.vertices.second);
+ AbstractRFSVertexPtr vert2 = dynamic_ptr_cast<AbstractRFSVertexPtr>
+ (current.vertices.first );
+ scalar_[ix] = make_pair(vert1, vert2);
+ }
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ if(current.channelType == HPDiagram::sChannel ||
+ (current.channelType == HPDiagram::tChannel &&
+ !current.ordered.second)) {
+ AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
+ (current.vertices.first);
+ AbstractRFVVertexPtr vert2 = dynamic_ptr_cast<AbstractRFVVertexPtr>
+ (current.vertices.second);
+ vector_[ix] = make_pair(vert1, vert2);
+ }
+ else {
+ AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
+ (current.vertices.second);
+ AbstractRFVVertexPtr vert2 = dynamic_ptr_cast<AbstractRFVVertexPtr>
+ (current.vertices.first );
+ vector_[ix] = make_pair(vert1, vert2);
+ }
+ }
+ }
+}
+
+void MEff2rf::persistentOutput(PersistentOStream & os) const {
+ os << scalar_ << vector_;
+}
+
+void MEff2rf::persistentInput(PersistentIStream & is, int) {
+ is >> scalar_ >> vector_;
+ initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
+ PDT::Spin3Half, PDT::Spin1Half);
+}
+
+
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEff2rf,GeneralHardME>
+ describeHerwigMEff2rf("Herwig::MEff2rf", "Herwig.so");
+
+void MEff2rf::Init() {
+
+ static ClassDocumentation<MEff2rf> documentation
+ ("There is no documentation for the MEff2rf class");
+
+}
+
+ProductionMatrixElement
+MEff2rf::ffb2rfbHeME(double & me2, bool first) const {
+ const Energy2 q2(scale());
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ // flow over the helicities and diagrams
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ for(unsigned int ifhel1 = 0; ifhel1 < 2; ++ifhel1) {
+ for(unsigned int ifhel2 = 0; ifhel2 < 2; ++ifhel2) {
+ for(unsigned int ofhel1 = 0; ofhel1 < 4; ++ofhel1) {
+ if(massless && (ofhel1==1 || ofhel1==2)) continue;
+ for(unsigned int ofhel2 = 0; ofhel2 < 2; ++ofhel2) {
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if(current.channelType == HPDiagram::tChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ if(current.ordered.second) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 3, offshell,spin_[2][ofhel2],sbar_[1][ifhel2]);
+ diag = -scalar_[ix].second->
+ evaluate(q2, spin_[0][ifhel1],rsbar_[ofhel1],interS);
+ }
+ else {
+ ScalarWaveFunction interS = scalar_[ix].second->
+ evaluate(q2, 3, offshell,rs_[ofhel1],sbar_[1][ifhel2]);
+ diag = scalar_[ix].first->
+ evaluate(q2, spin_[0][ifhel1],sbar_[2][ofhel2],interS);
+ }
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ if(current.ordered.second) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 3, offshell,spin_[2][ofhel2],sbar_[1][ifhel2]);
+ diag = -vector_[ix].second->
+ evaluate(q2, spin_[0][ifhel1], rsbar_[ofhel1], interV);
+ }
+ else {
+ VectorWaveFunction interV = vector_[ix].second->
+ evaluate(q2, 3, offshell,rs_[ofhel1],sbar_[1][ifhel2]);
+ diag = vector_[ix].first->
+ evaluate(q2, spin_[0][ifhel1], sbar_[2][ofhel2], interV);
+ }
+ }
+ else
+ assert(false);
+ }
+ else if(current.channelType == HPDiagram::sChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 1, offshell, spin_[0][ifhel1], sbar_[1][ifhel2]);
+ diag = scalar_[ix].second->
+ evaluate(q2,spin_[2][ofhel2],rsbar_[ofhel1], interS);
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 1, offshell,spin_[0][ifhel1], sbar_[1][ifhel2]);
+ diag = vector_[ix].second->
+ evaluate(q2, spin_[2][ofhel2],rsbar_[ofhel1] , interV);
+ }
+ else
+ assert(false);
+ }
+ else
+ assert(false);
+ me[ix] += norm(diag);
+ diagramME()[ix](ifhel1, ifhel2, ofhel1, ofhel2) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](ifhel1, ifhel2, ofhel1, ofhel2) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii) {
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij) {
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ }
+ }
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+ProductionMatrixElement
+MEff2rf::ffb2rbfHeME(double & me2, bool first) const {
+ const Energy2 q2(scale());
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ // flow over the helicities and diagrams
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ for(unsigned int ifhel1 = 0; ifhel1 < 2; ++ifhel1) {
+ for(unsigned int ifhel2 = 0; ifhel2 < 2; ++ifhel2) {
+ for(unsigned int ofhel1 = 0; ofhel1 < 4; ++ofhel1) {
+ if(massless && (ofhel1==1 || ofhel1==2)) continue;
+ for(unsigned int ofhel2 = 0; ofhel2 < 2; ++ofhel2) {
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if(current.channelType == HPDiagram::tChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ if(current.ordered.second) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 3, offshell,spin_[2][ofhel2],sbar_[1][ifhel2]);
+ diag = -scalar_[ix].second->
+ evaluate(q2, spin_[0][ifhel1],rsbar_[ofhel1],interS);
+ }
+ else {
+ ScalarWaveFunction interS = scalar_[ix].second->
+ evaluate(q2, 3, offshell,rs_[ofhel1],sbar_[1][ifhel2]);
+ diag = scalar_[ix].first->
+ evaluate(q2, spin_[0][ifhel1],sbar_[2][ofhel2],interS);
+ }
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ if(current.ordered.second) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 3, offshell,spin_[2][ofhel2],sbar_[1][ifhel2]);
+ diag = -vector_[ix].second->
+ evaluate(q2, spin_[0][ifhel1], rsbar_[ofhel1], interV);
+ }
+ else {
+ VectorWaveFunction interV = vector_[ix].second->
+ evaluate(q2, 3, offshell,rs_[ofhel1],sbar_[1][ifhel2]);
+ diag = vector_[ix].first->
+ evaluate(q2, spin_[0][ifhel1], sbar_[3][ofhel2], interV);
+ }
+ }
+ else
+ assert(false);
+ }
+ else if(current.channelType == HPDiagram::sChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ ScalarWaveFunction interS = scalar_[ix].second->
+ evaluate(q2, 1, offshell,rs_[ofhel1],sbar_[2][ofhel2]);
+ diag = -scalar_[ix].first->
+ evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interS);
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ VectorWaveFunction interV = vector_[ix].second->
+ evaluate(q2, 1, offshell,rs_[ofhel1],sbar_[2][ofhel2]);
+ diag = -vector_[ix].first->
+ evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interV);
+ }
+ else
+ assert(false);
+ }
+ else
+ assert(false);
+ me[ix] += norm(diag);
+ diagramME()[ix](ifhel1, ifhel2, ofhel1, ofhel2) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](ifhel1, ifhel2, ofhel1, ofhel2) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii) {
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij) {
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ }
+ }
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+ProductionMatrixElement
+MEff2rf:: ff2rfHeME(double & me2, bool first) const {
+ const Energy2 q2(scale());
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ // flow over the helicities and diagrams
+ for(unsigned int ifhel1 = 0; ifhel1 < 2; ++ifhel1) {
+ for(unsigned int ifhel2 = 0; ifhel2 < 2; ++ifhel2) {
+ for(unsigned int ofhel1 = 0; ofhel1 < 4; ++ofhel1) {
+ if(massless && (ofhel1==1 || ofhel1==2)) continue;
+ for(unsigned int ofhel2 = 0; ofhel2 < 2; ++ofhel2) {
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if(current.channelType == HPDiagram::tChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ if(current.ordered.second) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 3, offshell,spin_[1][ifhel2],sbar_[2][ofhel2]);
+ diag = scalar_[ix].second->
+ evaluate(q2, spin_[0][ifhel1], rsbar_[ofhel1], interS);
+ }
+ else {
+ ScalarWaveFunction interS = scalar_[ix].second->
+ evaluate(q2, 3, offshell,spin_[1][ifhel2],rsbar_[ofhel1]);
+ diag = -scalar_[ix].first->
+ evaluate(q2, spin_[0][ifhel1], sbar_[2][ofhel2], interS);
+ }
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ if(current.ordered.second) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 3, offshell,spin_[1][ifhel2],sbar_[2][ofhel2]);
+ diag = vector_[ix].second->
+ evaluate(q2, spin_[0][ifhel1], rsbar_[ofhel1], interV);
+ }
+ else {
+ VectorWaveFunction interV = vector_[ix].second->
+ evaluate(q2, 3, offshell,spin_[1][ifhel2],rsbar_[ofhel1]);
+ diag = -vector_[ix].first->
+ evaluate(q2, spin_[0][ifhel1], sbar_[2][ofhel2], interV);
+ }
+ }
+ else
+ assert(false);
+ }
+ else if(current.channelType == HPDiagram::sChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ ScalarWaveFunction interS =
+ scalar_[ix].first->evaluate(q2, 1, offshell, spin_[0][ifhel1], sbar_[1][ifhel2]);
+ diag = scalar_[ix].second->evaluate(q2, spin_[2][ofhel2],rsbar_[ofhel1],interS);
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 1, offshell,spin_[0][ifhel1], sbar_[1][ifhel2]);
+ diag = vector_[ix].second->evaluate(q2,spin_[2][ofhel2],rsbar_[ofhel1],interV);
+ }
+ else
+ assert(false);
+ }
+ else
+ assert(false);
+ me[ix] += norm(diag);
+ diagramME()[ix](ifhel1, ifhel2, ofhel1, ofhel2) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](ifhel1, ifhel2, ofhel1, ofhel2) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii)
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+ProductionMatrixElement
+MEff2rf::fbfb2rbfbHeME(double & me2, bool first) const {
+ const Energy2 q2(scale());
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ // flow over the helicities and diagrams
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ // flow over the helicities and diagrams
+ for(unsigned int ifhel1 = 0; ifhel1 < 2; ++ifhel1) {
+ for(unsigned int ifhel2 = 0; ifhel2 < 2; ++ifhel2) {
+ for(unsigned int ofhel1 = 0; ofhel1 < 4; ++ofhel1) {
+ if(massless && (ofhel1==1 || ofhel1==2)) continue;
+ for(unsigned int ofhel2 = 0; ofhel2 < 2; ++ofhel2) {
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if(current.channelType == HPDiagram::tChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ if(current.ordered.second) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 3, offshell,spin_[2][ofhel2],sbar_[1][ifhel2]);
+ diag = scalar_[ix].second->
+ evaluate(q2, rs_[ofhel1], sbar_[0][ifhel1], interS);
+ }
+ else {
+ ScalarWaveFunction interS = scalar_[ix].second->
+ evaluate(q2, 3, offshell,rs_[ofhel1],sbar_[1][ifhel2]);
+ diag = -scalar_[ix].first->
+ evaluate(q2, spin_[2][ofhel2], sbar_[0][ifhel1], interS);
+ }
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ if(current.ordered.second) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 3, offshell,spin_[2][ofhel2],sbar_[1][ifhel2]);
+ diag = vector_[ix].second->
+ evaluate(q2, rs_[ofhel1], sbar_[0][ifhel1], interV);
+ }
+ else {
+ VectorWaveFunction interV = vector_[ix].second->
+ evaluate(q2, 3, offshell,rs_[ofhel1],sbar_[1][ifhel2]);
+ diag = -vector_[ix].first->
+ evaluate(q2, spin_[2][ofhel2], sbar_[0][ifhel1], interV);
+ }
+ }
+ else
+ assert(false);
+ }
+ else if(current.channelType == HPDiagram::sChannel) {
+ if(offshell->CC()) offshell=offshell->CC();
+ if(offshell->iSpin() == PDT::Spin0) {
+ ScalarWaveFunction interS = scalar_[ix].second->
+ evaluate(q2, 1, offshell,spin_[2][ofhel2],rsbar_[ofhel1]);
+ diag = scalar_[ix].first->
+ evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interS);
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ VectorWaveFunction interV = vector_[ix].second->
+ evaluate(q2, 1, offshell,spin_[2][ofhel2],rsbar_[ofhel1]);
+ diag = vector_[ix].first->
+ evaluate(q2, spin_[0][ifhel1], sbar_[1][ifhel2], interV);
+ }
+ else
+ assert(false);
+ }
+ else
+ assert(false);
+ me[ix] += norm(diag);
+ diagramME()[ix](ifhel1, ifhel2, ofhel1, ofhel2) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](ifhel1, ifhel2, ofhel1, ofhel2) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii)
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+void MEff2rf::constructVertex(tSubProPtr subp) {
+ // Hard process external particles
+ ParticleVector hardpro = hardParticles(subp);
+ //Need to use rescale momenta to calculate matrix element
+ setRescaledMomenta(hardpro);
+ // calculate the fermion spinors
+ for(unsigned int ix=0;ix<3;++ix) {
+ spin_[ix].clear();
+ sbar_[ix].clear();
+ unsigned int iy(ix);
+ if(ix==2) ++iy;
+ SpinorWaveFunction (spin_[ix],hardpro[iy],
+ ix<2 ? incoming : outgoing,ix>1);
+ SpinorBarWaveFunction(sbar_[ix],hardpro[iy],
+ ix<2 ? incoming : outgoing,ix>1);
+ }
+ rs_ .clear();
+ rsbar_.clear();
+ // calculate the rs spinors
+ RSSpinorWaveFunction (rs_ , hardpro[2], outgoing, true);
+ RSSpinorBarWaveFunction(rsbar_, hardpro[2], outgoing, true);
+ double dummy(0.);
+ if( mePartonData()[0]->id() > 0 && mePartonData()[1]->id() < 0) {
+ if(mePartonData()[2]->id()>0) {
+ ProductionMatrixElement prodME = ffb2rfbHeME (dummy,true);
+ createVertex(prodME,hardpro);
+ }
+ else {
+ ProductionMatrixElement prodME = ffb2rbfHeME (dummy,true);
+ createVertex(prodME,hardpro);
+ }
+ }
+ else if( mePartonData()[0]->id() > 0 && mePartonData()[1]->id() > 0 ) {
+ ProductionMatrixElement prodME = ff2rfHeME(dummy,true);
+ createVertex(prodME,hardpro);
+ }
+ else if( mePartonData()[0]->id() < 0 && mePartonData()[1]->id() < 0 ) {
+ ProductionMatrixElement prodME = fbfb2rbfbHeME(dummy,true);
+ createVertex(prodME,hardpro);
+ }
+ else
+ assert(false);
+}
diff --git a/MatrixElement/General/MEff2rf.h b/MatrixElement/General/MEff2rf.h
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEff2rf.h
@@ -0,0 +1,219 @@
+// -*- C++ -*-
+#ifndef Herwig_MEff2rf_H
+#define Herwig_MEff2rf_H
+//
+// This is the declaration of the MEff2rf class.
+//
+
+#include "GeneralHardME.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/RSSpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/RSSpinorBarWaveFunction.h"
+#include "Herwig/MatrixElement/ProductionMatrixElement.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.h"
+
+namespace Herwig {
+
+using namespace ThePEG;
+using Helicity::SpinorWaveFunction;
+using Helicity::SpinorBarWaveFunction;
+using Helicity::RSSpinorWaveFunction;
+using Helicity::RSSpinorBarWaveFunction;
+
+/**
+ * This is the implementation of the \f$ 2\to 2\f$ matrix element for
+ * a fermion-fermion to fermion RS fermion process. It inherits from
+ * GeneralHardME and implements the appropriate virtual functions.
+ *
+ * @see GeneralHardME
+ */
+class MEff2rf: public GeneralHardME {
+
+public:
+
+ /** Vector of SpinorWaveFunctions. */
+ typedef vector<SpinorWaveFunction> SpinorVector;
+
+ /** Vector of SpinorBarWaveFunctions. */
+ typedef vector<SpinorBarWaveFunction> SpinorBarVector;
+
+ /** Vector of RSSpinorWaveFunctions. */
+ typedef vector<RSSpinorWaveFunction> RSSpinorVector;
+
+ /** Vector of RSSpinorBarWaveFunctions. */
+ typedef vector<RSSpinorBarWaveFunction> RSSpinorBarVector;
+
+public:
+
+ /** @name Virtual functions required by the MEBase class. */
+ //@{
+ /**
+ * The matrix element for the kinematical configuration
+ * previously provided by the last call to setKinematics(), suitably
+ * scaled by sHat() to give a dimension-less number.
+ * @return the matrix element scaled with sHat() to give a
+ * dimensionless number.
+ */
+ virtual double me2() const;
+ //@}
+
+private:
+
+ /** @name Functions to compute the ProductionMatrixElement. */
+ //@{
+ /**
+ * Compute the matrix element for \f$\Psi\bar{\Psi}\to\Psi\bar{\Psi}\f$
+ * @param me2 colour averaged, spin summed ME
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @return ProductionMatrixElement containing results of
+ * helicity calculations
+ */
+ ProductionMatrixElement
+ ffb2rfbHeME(double & me2, bool first) const;
+
+ /**
+ * Compute the matrix element for \f$\Psi\bar{\Psi}\to\Psi\bar{\Psi}\f$
+ * @param me2 colour averaged, spin summed ME
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @return ProductionMatrixElement containing results of
+ * helicity calculations
+ */
+ ProductionMatrixElement
+ ffb2rbfHeME(double & me2, bool first) const;
+
+ /**
+ * Compute the matrix element for \f$\Psi\Psi\to\Psi\Psi\f$
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @return ProductionMatrixElement containing results of
+ * helicity calculations
+ */
+ ProductionMatrixElement ff2rfHeME(double & me2, bool first) const;
+
+ /**
+ * Compute the matrix element for
+ * \f$\bar{\Psi}\bar{\Psi}\to\bar{\Psi}\bar{\Psi}\f$
+ * @param me2 colour averaged, spin summed ME
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @return ProductionMatrixElement containing results of
+ * helicity calculations
+ */
+ ProductionMatrixElement fbfb2rbfbHeME(double & me2, bool first) const;
+
+ /**
+ * Compute the matrix element for \f$\Psi\bar{\Psi}\to\lambda\lambda\f$
+ * @param me2 colour averaged, spin summed ME
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @return ProductionMatrixElement containing results of
+ * helicity calculations
+ */
+ ProductionMatrixElement
+ ffb2mfmfHeME(double & me2, bool first) const;
+ //@}
+
+ /**
+ * Construct the vertex information for the spin correlations
+ * @param sub Pointer to the relevent SubProcess
+ */
+ virtual void constructVertex(tSubProPtr sub);
+
+public:
+
+ /** @name Functions used by the persistent I/O system. */
+ //@{
+ /**
+ * Function used to write out object persistently.
+ * @param os the persistent output stream written to.
+ */
+ void persistentOutput(PersistentOStream & os) const;
+
+ /**
+ * Function used to read in object persistently.
+ * @param is the persistent input stream read from.
+ * @param version the version number of the object when written.
+ */
+ void persistentInput(PersistentIStream & is, int version);
+ //@}
+
+ /**
+ * The standard Init function used to initialize the interfaces.
+ * Called exactly once for each class by the class description system
+ * before the main function starts or
+ * when this class is dynamically loaded.
+ */
+ static void Init();
+
+protected:
+
+ /** @name Clone Methods. */
+ //@{
+ /**
+ * Make a simple clone of this object.
+ * @return a pointer to the new object.
+ */
+ 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.
+ */
+ MEff2rf & operator=(const MEff2rf &);
+
+private:
+
+ /**
+ * Store the vector of FFSVertex pairs
+ */
+ vector<pair<AbstractFFSVertexPtr, AbstractRFSVertexPtr> > scalar_;
+
+ /**
+ * Store the vector of FFVVertex pairs
+ */
+ vector<pair<AbstractFFVVertexPtr, AbstractRFVVertexPtr> > vector_;
+
+ /**
+ * Spinors
+ */
+ mutable std::array<SpinorVector,3> spin_;
+
+ /**
+ * Barred spinors
+ */
+ mutable std::array<SpinorBarVector,3> sbar_;
+
+ mutable RSSpinorVector rs_;
+ mutable RSSpinorBarVector rsbar_;
+};
+
+}
+
+#endif /* Herwig_MEff2rf_H */
diff --git a/MatrixElement/General/MEff2ss.cc b/MatrixElement/General/MEff2ss.cc
--- a/MatrixElement/General/MEff2ss.cc
+++ b/MatrixElement/General/MEff2ss.cc
@@ -1,318 +1,332 @@
// -*- C++ -*-
//
// MEff2ss.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEff2ss class.
//
#include "MEff2ss.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using ThePEG::Helicity::VectorWaveFunction;
using ThePEG::Helicity::TensorWaveFunction;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
void MEff2ss::doinit() {
GeneralHardME::doinit();
fermion_.resize(numberOfDiags());
+ RSfermion_.resize(numberOfDiags());
scalar_ .resize(numberOfDiags());
vector_ .resize(numberOfDiags());
tensor_ .resize(numberOfDiags());
+ fourPoint_.resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
PDT::Spin0 , PDT::Spin0 );
for(HPCount i = 0; i < numberOfDiags(); ++i) {
const HPDiagram & current = getProcessInfo()[i];
if(current.channelType == HPDiagram::tChannel) {
if(current.intermediate->iSpin() == PDT::Spin1Half)
fermion_[i] =
make_pair(dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.first),
dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.second));
+ else if(current.intermediate->iSpin() == PDT::Spin3Half)
+ RSfermion_[i] =
+ make_pair(dynamic_ptr_cast<AbstractRFSVertexPtr>(current.vertices.first),
+ dynamic_ptr_cast<AbstractRFSVertexPtr>(current.vertices.second));
else
throw InitException() << "MEFF2ss:doinit() - t-channel"
<< " intermediate must be a fermion "
<< Exception::runerror;
}
else if(current.channelType == HPDiagram::sChannel) {
if(current.intermediate->iSpin() == PDT::Spin0)
scalar_[i] =
make_pair(dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.first),
dynamic_ptr_cast<AbstractSSSVertexPtr>(current.vertices.second));
else if(current.intermediate->iSpin() == PDT::Spin1)
vector_[i] =
make_pair(dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.first),
dynamic_ptr_cast<AbstractVSSVertexPtr>(current.vertices.second));
else if(current.intermediate->iSpin() == PDT::Spin2)
tensor_[i] =
make_pair(dynamic_ptr_cast<AbstractFFTVertexPtr>(current.vertices.first),
dynamic_ptr_cast<AbstractSSTVertexPtr>(current.vertices.second));
else
throw InitException() << "MEFF2ss:doinit() - s-channel"
<< " intermediate must be a vector or tensor "
<< Exception::runerror;
}
+ else if(current.channelType == HPDiagram::fourPoint) {
+ fourPoint_[i] = dynamic_ptr_cast<AbstractFFSSVertexPtr>(current.vertices.first);
+ }
else
throw InitException() << "MEFF2ss:doinit() - Cannot find correct "
<< "channel from diagram. Vertex not cast! "
<< Exception::runerror;
}
}
double MEff2ss::me2() const {
// first setup wavefunctions for external particles
SpinorVector sp(2);
SpinorBarVector sbar(2);
for( unsigned int i = 0; i < 2; ++i ) {
sp[i] = SpinorWaveFunction (rescaledMomenta()[0],
mePartonData()[0], i, incoming);
sbar[i] = SpinorBarWaveFunction(rescaledMomenta()[1],
mePartonData()[1], i, incoming);
}
ScalarWaveFunction sca1(rescaledMomenta()[2],
mePartonData()[2], 1., outgoing);
ScalarWaveFunction sca2(rescaledMomenta()[3],
mePartonData()[3], 1., outgoing);
// calculate the ME
double full_me(0.);
ff2ssME(sp, sbar, sca1, sca2, full_me,true);
// debugging tests if needed
#ifndef NDEBUG
if( debugME() ) debug(full_me);
#endif
// return the answer
return full_me;
}
ProductionMatrixElement
MEff2ss::ff2ssME(const SpinorVector & sp, const SpinorBarVector & sbar,
const ScalarWaveFunction & sca1,
const ScalarWaveFunction & sca2,
double & me2, bool first) const {
// scale
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
// flow over the helicities and diagrams
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 2; ++if2) {
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr internal(current.intermediate);
- if(current.channelType == HPDiagram::tChannel &&
- internal->iSpin() == PDT::Spin1Half) {
+ if(current.channelType == HPDiagram::tChannel) {
if(internal->CC()) internal=internal->CC();
- unsigned int iopt = ( abs(sbar[if2].particle()->id()) == abs(internal->id()) ||
- abs(sp[if1] .particle()->id()) == abs(internal->id())) ? 5 : 3;
- SpinorBarWaveFunction interFB;
- if(current.ordered.second) {
- if(iopt==3) {
+ if(internal->iSpin() == PDT::Spin1Half) {
+ SpinorBarWaveFunction interFB;
+ if(current.ordered.second) {
interFB = fermion_[ix].second->
- evaluate(q2, iopt, internal, sbar[if2], sca2);
+ evaluate(q2, 3, internal, sbar[if2], sca2);
+ diag = fermion_[ix].first->evaluate(q2, sp[if1], interFB, sca1);
}
else {
interFB = fermion_[ix].second->
- evaluate(q2, iopt, internal, sbar[if2], sca2, 0.*GeV, 0.*GeV);
+ evaluate(q2, 3, internal, sbar[if2], sca1);
+ diag = fermion_[ix].first->evaluate(q2, sp[if1], interFB, sca2);
}
- diag = fermion_[ix].first->evaluate(q2, sp[if1], interFB, sca1);
}
- else {
- if(iopt==3) {
- interFB = fermion_[ix].second->
- evaluate(q2, iopt, internal, sbar[if2], sca1);
+ else if (internal->iSpin() == PDT::Spin3Half) {
+ RSSpinorBarWaveFunction interFB;
+ if(current.ordered.second) {
+ interFB = RSfermion_[ix].second->
+ evaluate(q2, 3, internal, sbar[if2], sca2);
+ diag = RSfermion_[ix].first->evaluate(q2, sp[if1], interFB, sca1);
}
- else {
- interFB = fermion_[ix].second->
- evaluate(q2, iopt, internal, sbar[if2], sca1, 0.*GeV, 0.*GeV);
+ else {
+ interFB = RSfermion_[ix].second->
+ evaluate(q2, 3, internal, sbar[if2], sca1);
+ diag = RSfermion_[ix].first->evaluate(q2, sp[if1], interFB, sca2);
}
- diag = fermion_[ix].first->evaluate(q2, sp[if1], interFB, sca2);
}
+ else
+ assert(false);
}
else if(current.channelType == HPDiagram::sChannel) {
if(internal->iSpin() == PDT::Spin0) {
ScalarWaveFunction interS = scalar_[ix].first->
evaluate(q2, 1, internal, sp[if1], sbar[if2]);
diag = scalar_[ix].second->evaluate(q2, interS, sca2, sca1);
}
else if(internal->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].first->
evaluate(q2, 1, internal, sp[if1], sbar[if2]);
diag = vector_[ix].second->evaluate(q2, interV, sca2, sca1);
}
else if(internal->iSpin() == PDT::Spin2) {
TensorWaveFunction interT = tensor_[ix].first->
evaluate(q2, 1, internal, sp[if1], sbar[if2]);
diag = tensor_[ix].second ->evaluate(q2, sca2, sca1, interT);
}
}
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = fourPoint_[ix]->evaluate(q2,sp[if1], sbar[if2],sca1,sca2);
+ }
// diagram
me[ix] += norm(diag);
diagramME()[ix](if1,if2,0,0) = diag;
// contributions to the different colour flows
for(unsigned int iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](if1,if2,0,0) = flows[iy];
// contribution to the squared matrix element
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii)
for(unsigned int ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEff2ss::persistentOutput(PersistentOStream & os) const {
- os << fermion_ << scalar_ << vector_ << tensor_;
+ os << fermion_ << scalar_ << vector_ << tensor_ << fourPoint_ << RSfermion_;
}
void MEff2ss::persistentInput(PersistentIStream & is, int) {
- is >> fermion_ >> scalar_ >> vector_ >> tensor_;
+ is >> fermion_ >> scalar_ >> vector_ >> tensor_ >> fourPoint_ >> RSfermion_;
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
PDT::Spin0 , PDT::Spin0 );
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEff2ss,GeneralHardME>
describeHerwigMEff2ss("Herwig::MEff2ss", "Herwig.so");
void MEff2ss::Init() {
static ClassDocumentation<MEff2ss> documentation
("MEff2ss implements the ME calculation of the fermion-antifermion "
"to scalar-scalar hard process.");
}
void MEff2ss::constructVertex(tSubProPtr sub) {
//get particles
ParticleVector ext = hardParticles(sub);
//First calculate wave functions with off-shell momenta
//to calculate correct spin information
SpinorVector sp;
SpinorBarVector sbar;
SpinorWaveFunction (sp , ext[0], incoming, false);
SpinorBarWaveFunction (sbar, ext[1], incoming, false);
ScalarWaveFunction sca1( ext[2], outgoing, true);
ScalarWaveFunction sca2( ext[3], outgoing, true);
// Need to use rescale momenta to calculate matrix element
setRescaledMomenta(ext);
// wave functions with rescaled momenta
SpinorWaveFunction spr(rescaledMomenta()[0],
ext[0]->dataPtr(), incoming);
SpinorBarWaveFunction sbr(rescaledMomenta()[1],
ext[1]->dataPtr(), incoming);
sca1 = ScalarWaveFunction(rescaledMomenta()[2],
ext[2]->dataPtr(), outgoing);
sca2 = ScalarWaveFunction(rescaledMomenta()[3],
ext[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
spr.reset(ihel);
sp[ihel] = spr;
sbr.reset(ihel);
sbar[ihel] = sbr;
}
double dummy(0.);
ProductionMatrixElement pme = ff2ssME(sp, sbar, sca1, sca2, dummy,false);
#ifndef NDEBUG
if( debugME() ) debug(dummy/36.);
#endif
createVertex(pme,ext);
}
void MEff2ss::debug(double me2) const {
if( !generator()->logfile().is_open() ) return;
long id1 = mePartonData()[0]->id();
long id2 = mePartonData()[1]->id();
long id3 = mePartonData()[2]->id();
long id4 = mePartonData()[3]->id();
if( (abs(id1) != 1 && abs(id1) != 2) || (abs(id2) != 1 && abs(id2) != 2) ||
( abs(id3) != 1000001 && abs(id3) != 1000002 &&
abs(id3) != 2000001 && abs(id3) != 2000002 ) ||
( abs(id4) != 1000001 && abs(id4) != 1000002 &&
abs(id4) != 2000001 && abs(id4) != 2000002 ) ) return;
tcSMPtr sm = generator()->standardModel();
double gs4 = sqr( 4.*Constants::pi*sm->alphaS(scale()) );
int Nc = sm->Nc();
double Cf = (sqr(Nc) - 1)/2./Nc;
Energy2 s(sHat());
Energy2 mgos = sqr( getParticleData(ParticleID::SUSY_g)->mass());
Energy2 m3s = sqr(mePartonData()[2]->mass());
Energy2 m4s = sqr(mePartonData()[3]->mass());
Energy4 spt2 = uHat()*tHat() - m3s*m4s;
Energy2 tgl(tHat() - mgos), ugl(uHat() - mgos);
unsigned int alpha = abs(id3)/1000000;
unsigned int beta = abs(id4)/1000000;
bool iflav = ( abs(id1) == abs(id2) );
unsigned int oflav = ( abs(id3) - abs(id1) ) % 10;
double analytic(0.);
if( alpha != beta ) {
if( ( id1 > 0 && id2 > 0) ||
( id1 < 0 && id2 < 0) ) {
analytic = spt2/sqr(tgl);
if( iflav ) analytic += spt2/sqr(ugl);
}
else {
analytic = s*mgos/sqr(tgl);
}
}
else {
if( oflav != 0 ) {
analytic = 2.*spt2/sqr(s);
}
else if( ( id1 > 0 && id2 > 0) ||
( id1 < 0 && id2 < 0) ) {
analytic = s*mgos/sqr(tgl);
if( iflav ) {
analytic += s*mgos/sqr(ugl) - 2.*s*mgos/Nc/tgl/ugl;
}
analytic /= ( iflav ? 2. : 1.);
}
else {
analytic = spt2/sqr(tgl);
if( iflav ) {
analytic += 2.*spt2/sqr(s) - 2.*spt2/Nc/s/tgl;
}
}
}
analytic *= gs4*Cf/2./Nc;
double diff = abs(analytic - me2);
if( diff > 1e-4 ) {
generator()->log()
<< mePartonData()[0]->PDGName() << ","
<< mePartonData()[1]->PDGName() << "->"
<< mePartonData()[2]->PDGName() << ","
<< mePartonData()[3]->PDGName() << " difference: "
<< setprecision(10) << diff << " ratio: " << analytic/me2
<< '\n';
}
}
diff --git a/MatrixElement/General/MEff2ss.h b/MatrixElement/General/MEff2ss.h
--- a/MatrixElement/General/MEff2ss.h
+++ b/MatrixElement/General/MEff2ss.h
@@ -1,195 +1,201 @@
// -*- C++ -*-
//
// MEff2ss.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_MEff2ss_H
#define HERWIG_MEff2ss_H
//
// This is the declaration of the MEff2ss class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractSSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractSSTVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFSSVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
using ThePEG::Helicity::SpinorWaveFunction;
using ThePEG::Helicity::SpinorBarWaveFunction;
using ThePEG::Helicity::ScalarWaveFunction;
/**
* The MEff2ss class is designed to implement the matrix element for a
* fermion-antifermion to scalar-scalar hard process. It inherits from
* GeneralHardME and implements the appropriate virtual functions for this
* specific spin combination.
*
- * @see \ref MEff2ssInterfaces "The interfaces"
- * defined for MEff2ss.
* @see GeneralHardME
*/
class MEff2ss: public GeneralHardME {
public:
/** Vector of SpinorWaveFunctions objects */
typedef vector<SpinorWaveFunction> SpinorVector;
/** Vector of SpinorBarWaveFunction objects. */
typedef vector<SpinorBarWaveFunction> SpinorBarVector;
public:
- /**
- * The default constructor.
- */
- MEff2ss() : fermion_(0), vector_(0), tensor_(0) {}
-
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
/**
* Construct the vertex information for the spin correlations
* @param sub Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr sub);
protected:
/**
* A debugging function to test the value of me2 against an
* analytic function.
* @param me2 The value of the \f$ |\bar{\mathcal{M}}|^2 \f$
*/
virtual void debug(double me2) 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 Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEff2ss & operator=(const MEff2ss &);
private:
/**
* Calculate the matrix element
* @param sp A vector of SpinorWaveFunction objects
* @param sbar A vector of SpinorBarWaveFunction objects
* @param sca1 A ScalarWaveFunction for an outgoing scalar
* @param sca2 A ScalarWaveFunction for the other outgoing scalar
* @param me2 The spin averaged matrix element
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
*/
ProductionMatrixElement ff2ssME(const SpinorVector & sp,
const SpinorBarVector & sbar,
const ScalarWaveFunction & sca1,
const ScalarWaveFunction & sca2,
double & me2, bool first) const;
private:
/**
* Storage for dynamically cast vertices for a diagram with intermediate
+ * vector
+ */
+ vector<pair<AbstractFFSVertexPtr, AbstractSSSVertexPtr> > scalar_;
+
+ /**
+ * Storage for dynamically cast vertices for a diagram with intermediate
* fermion
*/
vector<pair<AbstractFFSVertexPtr, AbstractFFSVertexPtr> > fermion_;
/**
* Storage for dynamically cast vertices for a diagram with intermediate
* vector
*/
- vector<pair<AbstractFFSVertexPtr, AbstractSSSVertexPtr> > scalar_;
+ vector<pair<AbstractFFVVertexPtr, AbstractVSSVertexPtr> > vector_;
/**
* Storage for dynamically cast vertices for a diagram with intermediate
- * vector
+ * fermion
*/
- vector<pair<AbstractFFVVertexPtr, AbstractVSSVertexPtr> > vector_;
+ vector<pair<AbstractRFSVertexPtr, AbstractRFSVertexPtr> > RSfermion_;
/**
* Storage for dynamically cast vertices for a diagram with intermediate
* tensor
*/
vector<pair<AbstractFFTVertexPtr, AbstractSSTVertexPtr> > tensor_;
+
+ /**
+ * Storage for dynamically cast 4 point vertices
+ */
+ vector<AbstractFFSSVertexPtr> fourPoint_;
};
}
#endif /* HERWIG_MEff2ss_H */
diff --git a/MatrixElement/General/MEff2sv.cc b/MatrixElement/General/MEff2sv.cc
deleted file mode 100644
--- a/MatrixElement/General/MEff2sv.cc
+++ /dev/null
@@ -1,223 +0,0 @@
-// -*- C++ -*-
-//
-// MEff2sv.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
-// Copyright (C) 2002-2017 The Herwig Collaboration
-//
-// Herwig is licenced under version 3 of the GPL, see COPYING for details.
-// Please respect the MCnet academic guidelines, see GUIDELINES for details.
-//
-//
-// This is the implementation of the non-inlined, non-templated member
-// functions of the MEff2sv class.
-//
-
-#include "MEff2sv.h"
-#include "ThePEG/Utilities/DescribeClass.h"
-#include "ThePEG/Interface/ClassDocumentation.h"
-#include "ThePEG/Persistency/PersistentOStream.h"
-#include "ThePEG/Persistency/PersistentIStream.h"
-
-using namespace Herwig;
-using ThePEG::Helicity::incoming;
-using ThePEG::Helicity::outgoing;
-
-void MEff2sv::doinit() {
- GeneralHardME::doinit();
- scalar_.resize(numberOfDiags());
- vector_.resize(numberOfDiags());
- fermion_.resize(numberOfDiags());
- initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
- PDT::Spin0,PDT::Spin1);
- for(HPCount i = 0; i < numberOfDiags(); ++i) {
- const HPDiagram & current = getProcessInfo()[i];
- if( current.channelType == HPDiagram::sChannel ) {
- if( current.intermediate->iSpin() == PDT::Spin0 )
- scalar_[i] =
- make_pair(dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.first),
- dynamic_ptr_cast<AbstractVSSVertexPtr>(current.vertices.second));
- else if( current.intermediate->iSpin() == PDT::Spin1 )
- vector_[i] =
- make_pair(dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.first),
- dynamic_ptr_cast<AbstractVVSVertexPtr>(current.vertices.second));
- }
- else if( current.channelType == HPDiagram::tChannel ) {
- if(current.intermediate->iSpin() == PDT::Spin1Half) {
- if( current.ordered.second )
- fermion_[i] =
- make_pair(dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.first),
- dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.second));
- else
- fermion_[i] =
- make_pair(dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.second),
- dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.first));
- }
- }
- }
-}
-
-void MEff2sv::persistentOutput(PersistentOStream & os) const {
- os << scalar_ << vector_ << fermion_;
-}
-
-void MEff2sv::persistentInput(PersistentIStream & is, int) {
- is >> scalar_ >> vector_ >> fermion_;
- initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
- PDT::Spin0,PDT::Spin1);
-}
-
-// The following static variable is needed for the type
-// description system in ThePEG.
-DescribeClass<MEff2sv,GeneralHardME>
-describeHerwigMEff2sv("Herwig::MEff2sv", "Herwig.so");
-
-void MEff2sv::Init() {
-
- static ClassDocumentation<MEff2sv> documentation
- ("MEff2sv implements the ME calculation of the fermion-antifermion "
- "to vector-scalar hard process.");
-
-}
-
-double MEff2sv::me2() const {
- //set up wavefunctions
- SpinorVector ina(2);
- SpinorBarVector inb(2);
- VBVector outa(3);
- ScalarWaveFunction sca(rescaledMomenta()[2], mePartonData()[2], Complex(1.),
- outgoing);
- for(unsigned int ih = 0; ih < 2; ++ih) {
- ina[ih] = SpinorWaveFunction(rescaledMomenta()[0], mePartonData()[0],
- ih, incoming);
- inb[ih] = SpinorBarWaveFunction(rescaledMomenta()[1], mePartonData()[1],
- ih, incoming);
- outa[2*ih] = VectorWaveFunction(rescaledMomenta()[3], mePartonData()[3],
- 2*ih, outgoing);
- }
- if( mePartonData()[2]->mass() > ZERO ) {
- outa[1] = VectorWaveFunction(rescaledMomenta()[3], mePartonData()[3],
- 1, outgoing);
- }
- double full_me(0.);
- ffb2svHeME(ina, inb, sca, outa, full_me,true);
- return full_me;
-}
-
-ProductionMatrixElement
-MEff2sv::ffb2svHeME(SpinorVector & sp, SpinorBarVector & spbar,
- ScalarWaveFunction & sca, VBVector & vec,
- double & me2, bool first) const {
- Energy2 m2(scale());
- bool mv = mePartonData()[2]->mass() == ZERO;
- // weights for the selection of the diagram
- vector<double> me(numberOfDiags(), 0.);
- // weights for the selection of the colour flow
- vector<double> flow(numberOfFlows(),0.);
- me2 = 0.;
- for(unsigned int ihel1 = 0; ihel1 < 2; ++ihel1) {
- for(unsigned int ihel2 = 0; ihel2 < 2; ++ihel2) {
- for(unsigned int ovhel = 0; ovhel < 3; ++ovhel) {
- if( mv && ovhel == 1 ) continue;
- vector<Complex> flows(numberOfFlows(),0.);
- for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
- Complex diag(0.);
- const HPDiagram & current = getProcessInfo()[ix];
- tcPDPtr offshell(current.intermediate);
- if( current.channelType == HPDiagram::sChannel ) {
- if( offshell->iSpin() == PDT::Spin0 ) {
- ScalarWaveFunction interS = scalar_[ix].first->
- evaluate(m2, 1, offshell, sp[ihel1], spbar[ihel2]);
- diag = scalar_[ix].second->evaluate(m2, vec[ovhel], sca, interS);
- }
- else if( offshell->iSpin() == PDT::Spin1 ) {
- VectorWaveFunction interV = vector_[ix].first->
- evaluate(m2, 1, offshell, sp[ihel1], spbar[ihel2]);
- diag = vector_[ix].second->evaluate(m2, vec[ovhel], interV, sca);
- }
- else diag = 0.0;
- }
- else if( current.channelType == HPDiagram::tChannel ) {
- if( offshell->iSpin() == PDT::Spin1Half ) {
- if( current.ordered.second ) {
- SpinorBarWaveFunction interFB = fermion_[ix].second->
- evaluate(m2, 3, offshell, spbar[ihel2], vec[ovhel]);
- diag = fermion_[ix].first->
- evaluate(m2, sp[ihel1], interFB, sca);
- }
- else {
- SpinorBarWaveFunction interFB = fermion_[ix].first->
- evaluate(m2, 3, offshell, spbar[ihel2], sca);
- diag = fermion_[ix].second->
- evaluate(m2, sp[ihel1], interFB, vec[ovhel]);
- }
- }
- }
- else diag = 0.;
- me[ix] += norm(diag);
- diagramME()[ix](ihel1, ihel2, 0, ovhel) = diag;
- //Compute flows
- for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
- assert(current.colourFlow[iy].first<flows.size());
- flows[current.colourFlow[iy].first] +=
- current.colourFlow[iy].second * diag;
- }
- }
- // MEs for the different colour flows
- for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
- flowME()[iy](ihel1, ihel2, 0, ovhel) = flows[iy];
- //Now add flows to me2 with appropriate colour factors
- for(size_t ii = 0; ii < numberOfFlows(); ++ii)
- for(size_t ij = 0; ij < numberOfFlows(); ++ij)
- me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
- // contribution to the colour flow
- for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
- flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
- }
- }
- }
- }
- // if not computing the cross section return the selected colour flow
- if(!first) return flowME()[colourFlow()];
- me2 = selectColourFlow(flow,me,me2);
- return flowME()[colourFlow()];
-}
-
-void MEff2sv::constructVertex(tSubProPtr sub) {
- // Hard proces external particles
- ParticleVector hdp = hardParticles(sub);
- SpinorVector sp;
- SpinorBarVector spbar;
- VBVector vec;
- bool mv(hdp[3]->dataPtr()->mass() == ZERO);
- SpinorWaveFunction (sp, hdp[0], incoming, false);
- SpinorBarWaveFunction (spbar, hdp[1], incoming, false);
- ScalarWaveFunction sca ( hdp[2], outgoing, true);
- VectorWaveFunction (vec, hdp[3], outgoing, true, mv);
- //Need to use rescale momenta to calculate matrix element
- setRescaledMomenta(hdp);
- // wavefunctions with rescaled momenta
- SpinorWaveFunction spr(rescaledMomenta()[0],
- hdp[0]->dataPtr(), incoming);
- SpinorBarWaveFunction sbr(rescaledMomenta()[1],
- hdp[1]->dataPtr(), incoming);
- sca = ScalarWaveFunction (rescaledMomenta()[2],
- hdp[2]->dataPtr(), outgoing);
- VectorWaveFunction vr(rescaledMomenta()[3],
- hdp[3]->dataPtr(), mv, outgoing);
- for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
- spr.reset(ihel);
- sp[ihel] = spr;
- sbr.reset(ihel);
- spbar[ihel] = sbr;
- vr.reset(2*ihel);
- vec[2*ihel] = vr;
- }
- if( !mv ) {
- vr.reset(1);
- vec[1] = vr;
- }
- double dummy(0.);
- ProductionMatrixElement prodme = ffb2svHeME(sp, spbar, sca, vec, dummy,false);
- createVertex(prodme,hdp);
-}
-
-
diff --git a/MatrixElement/General/MEff2sv.h b/MatrixElement/General/MEff2sv.h
deleted file mode 100644
--- a/MatrixElement/General/MEff2sv.h
+++ /dev/null
@@ -1,199 +0,0 @@
-// -*- C++ -*-
-//
-// MEff2sv.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_MEff2sv_H
-#define HERWIG_MEff2sv_H
-//
-// This is the declaration of the MEff2sv class.
-//
-
-#include "GeneralHardME.h"
-#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
-#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
-#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
-#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
-#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
-#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
-#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
-#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
-#include "Herwig/MatrixElement/ProductionMatrixElement.h"
-
-namespace Herwig {
-using namespace ThePEG;
-using Helicity::SpinorWaveFunction;
-using Helicity::SpinorBarWaveFunction;
-using Helicity::VectorWaveFunction;
-using Helicity::ScalarWaveFunction;
-
-/**
- * The MEff2sv class is designed to implement the matrix element for a
- * fermion-antifermion to vector-scalar hard process. It inherits from
- * GeneralHardME and implements the appropriate virtual functions for this
- * specific spin combination.
- *
- * @see \ref MEff2svInterfaces "The interfaces"
- * defined for MEff2sv.
- * @see GeneralHardME
- */
-class MEff2sv: public GeneralHardME {
-
-public:
-
- /** @name Typedefs */
- //@{
- /**
- * A vector of SpinorWaveFunctions
- */
- typedef vector<SpinorWaveFunction> SpinorVector;
-
- /**
- * A vector of SpinorWaveBarFunctions
- */
- typedef vector<SpinorBarWaveFunction> SpinorBarVector;
-
- /**
- * A vector of VectorWaveFunctions
- */
- typedef vector<VectorWaveFunction> VBVector;
- //@}
-
-public:
-
- /**
- * The default constructor.
- */
- MEff2sv() : scalar_(0), vector_(0), fermion_(0) {}
-
- /** @name Virtual functions required by the MEBase class. */
- //@{
- /**
- * The matrix element for the kinematical configuration
- * previously provided by the last call to setKinematics(), suitably
- * scaled by sHat() to give a dimension-less number.
- * @return the matrix element scaled with sHat() to give a
- * dimensionless number.
- */
- virtual double me2() const;
- //@}
-
- /**
- * Construct the vertex information for the spin correlations
- * @param sub Pointer to the relevent SubProcess
- */
- virtual void constructVertex(tSubProPtr sub);
-
-public:
-
- /** @name Functions used by the persistent I/O system. */
- //@{
- /**
- * Function used to write out object persistently.
- * @param os the persistent output stream written to.
- */
- void persistentOutput(PersistentOStream & os) const;
-
- /**
- * Function used to read in object persistently.
- * @param is the persistent input stream read from.
- * @param version the version number of the object when written.
- */
- void persistentInput(PersistentIStream & is, int version);
- //@}
-
- /**
- * The standard Init function used to initialize the interfaces.
- * Called exactly once for each class by the class description system
- * before the main function starts or
- * when this class is dynamically loaded.
- */
- static void Init();
-
-protected:
-
- /** @name Standard Interfaced functions. */
- //@{
- /**
- * Initialize this object after the setup phase before saving an
- * EventGenerator to disk.
- * @throws InitException if object could not be initialized properly.
- */
- virtual void doinit();
- //@}
-
-protected:
-
- /** @name Clone Methods. */
- //@{
- /**
- * Make a simple clone of this object.
- * @return a pointer to the new object.
- */
- virtual IBPtr clone() const {return new_ptr(*this);}
-
- /** Make a clone of this object, possibly modifying the cloned object
- * to make it sane.
- * @return a pointer to the new object.
- */
- virtual IBPtr fullclone() const {return new_ptr(*this);}
- //@}
-
-private:
-
- /**
- * The assignment operator is private and must never be called.
- * In fact, it should not even be implemented.
- */
- MEff2sv & operator=(const MEff2sv &);
-
-private:
-
- /** @name Functions to compute the ProductionMatrixElement. */
- //@{
- /**
- * Compute the matrix element for \f$\Psi\bar{\Psi}\to\Psi\bar{\Psi}\f$
- * @param sp Spinors for first incoming particle
- * @param spbar SpinorBar Wavefunctions for second incoming particle
- * @param vec VectorWaveFunctions for outgoing vector
- * @param sca Outgoing ScalarWaveFunction
- * @param me2 colour averaged, spin summed ME
- * @param first Whether or not first call to decide if colour decomposition etc
- * should be calculated
- * @return ProductionMatrixElement containing results of
- * helicity calculations
- */
- ProductionMatrixElement
- ffb2svHeME(SpinorVector & sp, SpinorBarVector & spbar,
- ScalarWaveFunction & sca, VBVector & vec,
- double & me2,bool first) const;
- //@}
-
-
-private:
-
- /**
- * Storage for dynamically cast vertices for a diagram with intermediate
- * scalar
- */
- vector<pair<AbstractFFSVertexPtr, AbstractVSSVertexPtr> > scalar_;
-
- /**
- * Storage for dynamically cast vertices for a diagram with intermediate
- * vector
- */
- vector<pair<AbstractFFVVertexPtr, AbstractVVSVertexPtr> > vector_;
-
- /**
- * Storage for dynamically cast vertices for a diagram with intermediate
- * fermion
- */
- vector<pair<AbstractFFSVertexPtr, AbstractFFVVertexPtr> > fermion_;
-};
-
-}
-
-#endif /* HERWIG_MEff2sv_H */
diff --git a/MatrixElement/General/MEff2tv.cc b/MatrixElement/General/MEff2ts.cc
copy from MatrixElement/General/MEff2tv.cc
copy to MatrixElement/General/MEff2ts.cc
--- a/MatrixElement/General/MEff2tv.cc
+++ b/MatrixElement/General/MEff2ts.cc
@@ -1,337 +1,223 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
-// functions of the MEff2tv class.
+// functions of the MEff2ts class.
//
-#include "MEff2tv.h"
+#include "MEff2ts.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
-IBPtr MEff2tv::clone() const {
+IBPtr MEff2ts::clone() const {
return new_ptr(*this);
}
-IBPtr MEff2tv::fullclone() const {
+IBPtr MEff2ts::fullclone() const {
return new_ptr(*this);
}
-void MEff2tv::persistentOutput(PersistentOStream & os) const {
- os << fermion_ << vector_ << fourPoint_;
+void MEff2ts::persistentOutput(PersistentOStream & os) const {
+ os << fermion_ << scalar_ << fourPoint_;
}
-void MEff2tv::persistentInput(PersistentIStream & is, int) {
- is >> fermion_ >> vector_ >> fourPoint_;
+void MEff2ts::persistentInput(PersistentIStream & is, int) {
+ is >> fermion_ >> scalar_ >> fourPoint_;
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
- PDT::Spin2 , PDT::Spin1);
+ PDT::Spin2 , PDT::Spin0);
}
// The following static variable is needed for the type
// description system in ThePEG.
-DescribeClass<MEff2tv,GeneralHardME>
-describeHerwigMEff2tv("Herwig::MEff2tv", "Herwig.so");
+DescribeClass<MEff2ts,GeneralHardME>
+describeHerwigMEff2ts("Herwig::MEff2ts", "Herwig.so");
-void MEff2tv::Init() {
+void MEff2ts::Init() {
- static ClassDocumentation<MEff2tv> documentation
- ("The MEff2tv class implements the general matrix element for "
- "fermion-antifermion -> tensor vector");
+ static ClassDocumentation<MEff2ts> documentation
+ ("The MEff2ts class implements the general matrix element for "
+ "fermion-antifermion -> tensor scalar");
}
-double MEff2tv::me2() const {
+double MEff2ts::me2() const {
// first setup wavefunctions for external particles
SpinorVector sp(2);
SpinorBarVector sbar(2);
- VBVector vec(3);
+ ScalarWaveFunction sca(rescaledMomenta()[3], mePartonData()[3],outgoing);
TBVector ten(5);
bool tMass = meMomenta()[2].mass()!=ZERO;
- bool vMass = meMomenta()[3].mass()!=ZERO;
for( unsigned int i = 0; i < 5; ++i ) {
if(i<2) {
sp[i] = SpinorWaveFunction (rescaledMomenta()[0],
mePartonData()[0], i, incoming);
sbar[i] = SpinorBarWaveFunction(rescaledMomenta()[1],
mePartonData()[1], i, incoming);
}
if( tMass || i==0 || i==4) {
ten[i] = TensorWaveFunction(rescaledMomenta()[2], mePartonData()[2],i ,
outgoing);
}
- if(i<3 && (i!=1||vMass) ) {
- vec[i] = VectorWaveFunction(rescaledMomenta()[3], mePartonData()[3],i ,
- outgoing);
- }
}
// calculate the ME
double full_me(0.);
- ffb2tvHeME(sp, sbar, ten, vec, full_me,true);
- // debugging tests if needed
-#ifndef NDEBUG
- if( debugME() ) debug(full_me);
-#endif
+ ffb2tsHeME(sp, sbar, ten, sca, full_me,true);
// return the answer
return full_me;
}
-void MEff2tv::doinit() {
+void MEff2ts::doinit() {
GeneralHardME::doinit();
fermion_ .resize(numberOfDiags());
- vector_ .resize(numberOfDiags());
+ scalar_ .resize(numberOfDiags());
fourPoint_ .resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
- PDT::Spin2 , PDT::Spin1);
+ PDT::Spin2 , PDT::Spin0);
for(HPCount i = 0; i < numberOfDiags(); ++i) {
const HPDiagram & current = getProcessInfo()[i];
if(current.channelType == HPDiagram::tChannel) {
if(current.intermediate->iSpin() != PDT::Spin1Half)
- throw InitException() << "MEff2tv:doinit() - Cannot find correct "
+ throw InitException() << "MEff2ts:doinit() - Cannot find correct "
<< "t-channel from diagram. Vertex not cast! "
<< Exception::runerror;
if( current.ordered.second )
fermion_[i] =
make_pair(dynamic_ptr_cast<AbstractFFTVertexPtr>(current.vertices.first),
- dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.second));
+ dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.second));
else
fermion_[i] =
make_pair(dynamic_ptr_cast<AbstractFFTVertexPtr>(current.vertices.second),
- dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.first));
+ dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.first));
}
else if(current.channelType == HPDiagram::sChannel) {
- if(current.intermediate->iSpin() != PDT::Spin1)
- throw InitException() << "MEff2tv:doinit() - Cannot find correct "
+ if(current.intermediate->iSpin() != PDT::Spin0)
+ throw InitException() << "MEff2ts:doinit() - Cannot find correct "
<< "s-channel from diagram. Vertex not cast! "
<< Exception::runerror;
- vector_[i] =
- make_pair(dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.first),
- dynamic_ptr_cast<AbstractVVTVertexPtr>(current.vertices.second));
+ scalar_[i] =
+ make_pair(dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.first),
+ dynamic_ptr_cast<AbstractSSTVertexPtr>(current.vertices.second));
}
else if(current.channelType == HPDiagram::fourPoint) {
fourPoint_[i] =
- dynamic_ptr_cast<AbstractFFVTVertexPtr>(current.vertices.first);
+ dynamic_ptr_cast<AbstractFFSTVertexPtr>(current.vertices.first);
}
}
}
-ProductionMatrixElement MEff2tv::
-ffb2tvHeME(SpinorVector & sp, SpinorBarVector & sb,
- TBVector & ten, VBVector & vec,
+ProductionMatrixElement MEff2ts::
+ffb2tsHeME(SpinorVector & sp, SpinorBarVector & sb,
+ TBVector & ten, ScalarWaveFunction & sca,
double & me2,bool first) const {
// scale
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
bool tMass = meMomenta()[2].mass() != ZERO;
- bool vMass = meMomenta()[3].mass() != ZERO;
// flow over the helicities and diagrams
for(unsigned int if1 = 0; if1 < 2; ++if1) {
for(unsigned int if2 = 0; if2 < 2; ++if2) {
for(unsigned int it=0; it<5; ++it) {
if( (it>0&&it<4) && !tMass ) continue;
- for(unsigned int iv=0; iv<3;++iv) {
- if(iv==1&&!vMass) continue;
- vector<Complex> flows(numberOfFlows(),0.);
- for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
- Complex diag(0.);
- const HPDiagram & current = getProcessInfo()[ix];
- tcPDPtr internal(current.intermediate);
- if(current.channelType == HPDiagram::tChannel) {
- if(current.ordered.second) {
- if(internal->CC()) internal = internal->CC();
- SpinorBarWaveFunction interFB = fermion_[ix].second->
- evaluate(q2,5,internal,sb[if2],vec[iv]);
- diag = fermion_[ix].first->
- evaluate(q2,sp[if1],interFB,ten[it]);
- }
- else {
- SpinorWaveFunction interF = fermion_[ix].second->
- evaluate(q2,5,internal,sp[if1],vec[iv]);
- diag = fermion_[ix].first->
- evaluate(q2,interF,sb[if2],ten[it]);
- }
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr internal(current.intermediate);
+ if(current.channelType == HPDiagram::tChannel) {
+ if(current.ordered.second) {
+ if(internal->CC()) internal = internal->CC();
+ SpinorBarWaveFunction interFB = fermion_[ix].second->
+ evaluate(q2,5,internal,sb[if2],sca);
+ diag = fermion_[ix].first->
+ evaluate(q2,sp[if1],interFB,ten[it]);
}
- else if(current.channelType == HPDiagram::sChannel) {
- VectorWaveFunction interV = vector_[ix].first->
- evaluate(q2, 1, internal, sp[if1], sb[if2],vec[iv].mass());
- diag = vector_[ix].second->evaluate(q2, interV, vec[iv],ten[it],
- vec[iv].mass());
- }
- else if(current.channelType == HPDiagram::fourPoint) {
- diag = fourPoint_[ix]->
- evaluate(q2,sp[if1],sb[if2],vec[iv],ten[it]);
- }
- // diagram
- me[ix] += norm(diag);
- diagramME()[ix](if1,if2,it,iv) = diag;
- // contributions to the different colour flows
- for(unsigned int iy = 0; iy < current.colourFlow.size(); ++iy) {
- assert(current.colourFlow[iy].first<flows.size());
- flows[current.colourFlow[iy].first] +=
- current.colourFlow[iy].second * diag;
+ else {
+ SpinorWaveFunction interF = fermion_[ix].second->
+ evaluate(q2,5,internal,sp[if1],sca);
+ diag = fermion_[ix].first->
+ evaluate(q2,interF,sb[if2],ten[it]);
}
}
- // MEs for the different colour flows
- for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
- flowME()[iy](if1,if2,it,iv) = flows[iy];
- // contribution to the squared matrix element
- for(unsigned int ii = 0; ii < numberOfFlows(); ++ii)
- for(unsigned int ij = 0; ij < numberOfFlows(); ++ij)
- me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
- // contribution to the colour flow
- for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
- flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ else if(current.channelType == HPDiagram::sChannel) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 1, internal, sp[if1], sb[if2],sca.mass());
+ diag = scalar_[ix].second->evaluate(q2, interS, sca,ten[it]);
}
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = fourPoint_[ix]->
+ evaluate(q2,sp[if1],sb[if2],sca,ten[it]);
+ }
+ // diagram
+ me[ix] += norm(diag);
+ diagramME()[ix](if1,if2,it,0) = diag;
+ // contributions to the different colour flows
+ for(unsigned int iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](if1,if2,it,0) = flows[iy];
+ // contribution to the squared matrix element
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii)
+ for(unsigned int ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
-void MEff2tv::debug(double me2) const {
- if( !generator()->logfile().is_open() ) return;
- long id1 = mePartonData()[0]->id();
- long id2 = mePartonData()[1]->id();
- long id4 = mePartonData()[3]->id();
- if(id1==-id2&&id1<=5&&id4==ParticleID::g) {
- unsigned int iloc(0);
- for(;iloc<vector_.size();++iloc)
- if(vector_[iloc].first) break;
- double gs = abs(vector_[iloc].first->norm());
- InvEnergy kappa = abs(vector_[iloc].second->norm())*UnitRemoval::InvE;
- Energy2 mg2 = sqr(meMomenta()[2].mass());
- double anal = sqr(gs)*sqr(kappa)/36.*(4.*uHat()*tHat()+sHat()*mg2)*
- (sqr(tHat()-mg2)+sqr(uHat()-mg2))/sHat()/tHat()/uHat();
- double diff = abs((anal - me2)/(anal+me2));
- if( diff > 1e-4 ) {
- generator()->log()
- << mePartonData()[0]->PDGName() << ","
- << mePartonData()[1]->PDGName() << "->"
- << mePartonData()[2]->PDGName() << ","
- << mePartonData()[3]->PDGName() << " difference: "
- << setprecision(10) << diff << " ratio: " << anal/me2
- << '\n';
- }
- }
- else if(id1==-id2&&id1==ParticleID::eminus&&id4==ParticleID::gamma) {
- unsigned int iloc(0);
- for(;iloc<vector_.size();++iloc)
- if(vector_[iloc].first) break;
- double gs = abs(vector_[iloc].first->norm());
- InvEnergy kappa = abs(vector_[iloc].second->norm())*UnitRemoval::InvE;
- Energy2 mg2 = sqr(meMomenta()[2].mass());
- double anal = sqr(gs)*sqr(kappa)/16./tHat()/uHat()/sHat()*
- (4.*uHat()*tHat()+mg2*sHat())*(sqr(uHat()-mg2)+sqr(tHat()-mg2));
- double diff = abs((anal - me2)/(anal+me2));
- if( diff > 1e-4 ) {
- generator()->log()
- << mePartonData()[0]->PDGName() << ","
- << mePartonData()[1]->PDGName() << "->"
- << mePartonData()[2]->PDGName() << ","
- << mePartonData()[3]->PDGName() << " difference: "
- << setprecision(10) << diff << " ratio: " << anal/me2
- << '\n';
- }
- }
- else if(id1==-id2&&id1==ParticleID::eminus&&id4==ParticleID::Z0) {
- unsigned int iloc(0);
- for(;iloc<vector_.size();++iloc)
- if(vector_[iloc].first) break;
- double gs = abs(vector_[iloc].first->norm());
- InvEnergy kappa = abs(vector_[iloc].second->norm())*UnitRemoval::InvE;
- Energy2 mg2 = sqr(meMomenta()[2].mass());
- Energy2 mz2 = sqr(meMomenta()[3].mass());
- double sw2 = SM().sin2ThetaW();
- double anal = sqr(gs)*sqr(kappa)/48./16./sw2/(1.-sw2)*
- 2.*(1.-4.*sw2+8.*sqr(sw2))/sqr(tHat())/sqr(uHat())/sqr(sHat()-mz2)*
- (8.*pow<3,1>(mz2)*uHat()*tHat()*(3.*mg2*(mg2-uHat()-tHat())+4.*uHat()*tHat())
- +2.*sqr(mz2)*uHat()*tHat()*(27.*pow<3,1>(mg2)-42.*sqr(mg2)*(uHat()+tHat())
- +15.*mg2*(sqr(uHat())+sqr(tHat()))
- +80.*mg2*uHat()*tHat()
- -28.*(sqr(uHat())*tHat()+uHat()*sqr(tHat())))
- +mz2*(3.*pow<4,1>(mg2)*(-sqr(uHat())-sqr(tHat())+12.*uHat()*tHat())
- +6.*pow<3,1>(mg2)*(pow<3,1>(uHat())
- -12.*(sqr(uHat())*tHat()+uHat()*sqr(tHat()))
- +pow<3,1>(tHat()))
- +3.*sqr(mg2)*(-pow<4,1>(uHat())+14.*pow<3,1>(uHat())*tHat()
- +62.*sqr(uHat()*tHat())+14.*uHat()*pow<3,1>(tHat())
- -pow<4,1>(tHat()))
- +6.*mg2*(-pow<4,1>(uHat())*tHat()
- -23.*(pow<3,1>(uHat())*sqr(tHat())+pow<3,1>(tHat())*sqr(uHat()))
- -uHat()*pow<4,1>(tHat()))
- +36.*(pow<4,1>(uHat())*sqr(tHat())+pow<4,1>(tHat())*sqr(uHat()))
- +52.*pow<3,1>(tHat()*uHat()))
- +3.*tHat()*uHat()*(-mg2+uHat()+tHat())*
- (-sqr(mg2)+mg2*(uHat()+tHat())-4.*uHat()*tHat())*
- (2.*sqr(mg2)-2.*mg2*(uHat()+tHat())+sqr(uHat())+sqr(tHat())));
- double diff = abs((anal - me2)/(anal+me2));
- if( diff > 1e-4 ) {
- generator()->log()
- << mePartonData()[0]->PDGName() << ","
- << mePartonData()[1]->PDGName() << "->"
- << mePartonData()[2]->PDGName() << ","
- << mePartonData()[3]->PDGName() << " difference: "
- << setprecision(10) << diff
- << " anal : " << anal
- << " code : " << me2
- << " ratio: " << anal/me2
- << '\n';
- }
- }
-}
-
-void MEff2tv::constructVertex(tSubProPtr sub) {
+void MEff2ts::constructVertex(tSubProPtr sub) {
ParticleVector ext = hardParticles(sub);
vector<SpinorWaveFunction> sp;
SpinorWaveFunction(sp, ext[0], incoming, false);
vector<SpinorBarWaveFunction> sbar;
SpinorBarWaveFunction(sbar, ext[1], incoming, false);
- vector<VectorWaveFunction> v2;
vector<TensorWaveFunction> t1;
bool mc = !(ext[2]->momentum().mass() > ZERO);
- bool md = !(ext[3]->data() .mass() > ZERO);
TensorWaveFunction(t1, ext[2], outgoing, true, mc);
- VectorWaveFunction(v2, ext[3], outgoing, true, md);
+ ScalarWaveFunction sca(ext[3], outgoing, true);
// Need to use rescale momenta to calculate matrix element
setRescaledMomenta(ext);
SpinorWaveFunction spr (rescaledMomenta()[0],
ext[0]->dataPtr(), incoming);
SpinorBarWaveFunction sbr(rescaledMomenta()[1],
ext[1]->dataPtr(), incoming);
TensorWaveFunction tr1 (rescaledMomenta()[2],
ext[2]->dataPtr(), outgoing);
- VectorWaveFunction vr2 (rescaledMomenta()[3],
- ext[3]->dataPtr(), outgoing);
+ sca = ScalarWaveFunction(rescaledMomenta()[3],
+ ext[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
spr.reset(ihel);
sp[ihel] = spr;
sbr.reset(ihel);
sbar[ihel] = sbr;
tr1.reset(4*ihel);
t1[4*ihel] = tr1;
- vr2.reset(2*ihel);
- v2[2*ihel] = vr2;
}
if( !mc ) {
for(unsigned int ihel=1;ihel<4;++ihel) {
tr1.reset(ihel);
t1[ihel] = tr1;
}
}
- if( !md ) {
- vr2.reset(1);
- v2[1] = vr2;
- }
double dummy(0.);
- ProductionMatrixElement pme = ffb2tvHeME(sp, sbar, t1, v2,dummy,false);
+ ProductionMatrixElement pme = ffb2tsHeME(sp, sbar, t1, sca,dummy,false);
createVertex(pme,ext);
}
diff --git a/MatrixElement/General/MEff2ts.h b/MatrixElement/General/MEff2ts.h
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEff2ts.h
@@ -0,0 +1,180 @@
+// -*- C++ -*-
+#ifndef HERWIG_MEff2ts_H
+#define HERWIG_MEff2ts_H
+//
+// This is the declaration of the MEff2ts class.
+//
+
+#include "GeneralHardME.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractSSTVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFSTVertex.h"
+
+namespace Herwig {
+
+using namespace ThePEG;
+using Helicity::SpinorWaveFunction;
+using Helicity::SpinorBarWaveFunction;
+using Helicity::ScalarWaveFunction;
+using Helicity::TensorWaveFunction;
+
+/**
+ * The MEff2ts class implements the general matrix element for fermion fermion -> tensor scalar
+ *
+ */
+class MEff2ts: public GeneralHardME {
+
+public:
+
+ /** @name Typedefs */
+ //@{
+ /**
+ * A vector of SpinorWaveFunctions
+ */
+ typedef vector<SpinorWaveFunction> SpinorVector;
+
+ /**
+ * A vector of SpinorWaveBarFunctions
+ */
+ typedef vector<SpinorBarWaveFunction> SpinorBarVector;
+
+ /**
+ * A vector of VectorWaveFunctions
+ */
+ typedef vector<TensorWaveFunction> TBVector;
+ //@}
+
+public:
+
+ /**
+ * The default constructor.
+ */
+ MEff2ts() : fermion_(0), scalar_(0), fourPoint_(0) {}
+
+ /**
+ * The matrix element for the kinematical configuration
+ * previously provided by the last call to setKinematics(), suitably
+ * scaled by sHat() to give a dimension-less number.
+ * @return the matrix element scaled with sHat() to give a
+ * dimensionless number.
+ */
+ virtual double me2() const;
+
+ /**
+ * Construct the vertex information for the spin correlations
+ * @param sub Pointer to the relevent SubProcess
+ */
+ virtual void constructVertex(tSubProPtr sub);
+
+public:
+
+ /** @name Functions used by the persistent I/O system. */
+ //@{
+ /**
+ * Function used to write out object persistently.
+ * @param os the persistent output stream written to.
+ */
+ void persistentOutput(PersistentOStream & os) const;
+
+ /**
+ * Function used to read in object persistently.
+ * @param is the persistent input stream read from.
+ * @param version the version number of the object when written.
+ */
+ void persistentInput(PersistentIStream & is, int version);
+ //@}
+
+ /**
+ * The standard Init function used to initialize the interfaces.
+ * Called exactly once for each class by the class description system
+ * before the main function starts or
+ * when this class is dynamically loaded.
+ */
+ static void Init();
+
+protected:
+
+ /** @name Clone Methods. */
+ //@{
+ /**
+ * Make a simple clone of this object.
+ * @return a pointer to the new object.
+ */
+ 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.
+ */
+ void doinit();
+ //@}
+
+private:
+
+ /**
+ * The assignment operator is private and must never be called.
+ * In fact, it should not even be implemented.
+ */
+ MEff2ts & operator=(const MEff2ts &);
+
+private:
+
+ /** @name Functions to compute the ProductionMatrixElement. */
+ //@{
+ /**
+ * Compute the matrix element for \f$\Psi\bar{\Psi}\to\Psi\bar{\Psi}\f$
+ * @param sp Spinors for first incoming particle
+ * @param spbar SpinorBar Wavefunctions for second incoming particle
+ * @param sca ScalarWaveFunction for outgoing scalar
+ * @param ten Outgoing TensorWaveFunction
+ * @param me2 colour averaged, spin summed ME
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @return ProductionMatrixElement containing results of
+ * helicity calculations
+ */
+ ProductionMatrixElement
+ ffb2tsHeME(SpinorVector & sp, SpinorBarVector & spbar,
+ TBVector & ten, ScalarWaveFunction & sca,
+ double & me2,bool first) const;
+ //@}
+
+private:
+
+ /**
+ * Store a pair of FFTVertex and FFVVertex pointers
+ */
+ vector<pair<AbstractFFTVertexPtr, AbstractFFSVertexPtr> > fermion_;
+
+ /**
+ * Store a pair of FFTVertex and VVTVertex pointers
+ */
+ vector<pair<AbstractFFSVertexPtr, AbstractSSTVertexPtr> > scalar_;
+
+ /**
+ * The four point vertex
+ */
+ vector<AbstractFFSTVertexPtr> fourPoint_;
+
+};
+
+}
+
+#endif /* HERWIG_MEff2ts_H */
diff --git a/MatrixElement/General/MEff2tv.h b/MatrixElement/General/MEff2tv.h
--- a/MatrixElement/General/MEff2tv.h
+++ b/MatrixElement/General/MEff2tv.h
@@ -1,194 +1,193 @@
// -*- C++ -*-
#ifndef HERWIG_MEff2tv_H
#define HERWIG_MEff2tv_H
//
// This is the declaration of the MEff2tv class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVTVertex.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::SpinorWaveFunction;
using Helicity::SpinorBarWaveFunction;
using Helicity::VectorWaveFunction;
using Helicity::TensorWaveFunction;
/**
- * Here is the documentation of the MEff2tv class.
+ * The documentation of the MEff2tv class implements the general matrix element for
+ * vector vectro to tensor vector
*
- * @see \ref MEff2tvInterfaces "The interfaces"
- * defined for MEff2tv.
*/
class MEff2tv: public GeneralHardME {
public:
/** @name Typedefs */
//@{
/**
* A vector of SpinorWaveFunctions
*/
typedef vector<SpinorWaveFunction> SpinorVector;
/**
* A vector of SpinorWaveBarFunctions
*/
typedef vector<SpinorBarWaveFunction> SpinorBarVector;
/**
* A vector of VectorWaveFunctions
*/
typedef vector<VectorWaveFunction> VBVector;
/**
* A vector of VectorWaveFunctions
*/
typedef vector<TensorWaveFunction> TBVector;
//@}
public:
/**
* The default constructor.
*/
MEff2tv() : fermion_(0), vector_(0), fourPoint_(0) {}
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
/**
* Construct the vertex information for the spin correlations
* @param sub Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr sub);
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
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.
*/
void doinit();
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEff2tv & operator=(const MEff2tv &);
private:
/** @name Functions to compute the ProductionMatrixElement. */
//@{
/**
* Compute the matrix element for \f$\Psi\bar{\Psi}\to\Psi\bar{\Psi}\f$
* @param sp Spinors for first incoming particle
* @param spbar SpinorBar Wavefunctions for second incoming particle
* @param vec VectorWaveFunctions for outgoing vector
* @param ten Outgoing TensorWaveFunction
* @param me2 colour averaged, spin summed ME
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @return ProductionMatrixElement containing results of
* helicity calculations
*/
ProductionMatrixElement
ffb2tvHeME(SpinorVector & sp, SpinorBarVector & spbar,
TBVector & ten, VBVector & vec,
double & me2,bool first) const;
//@}
/**
* A debugging function to test the value of me2 against an
* analytic function.
* @param me2 The value of the \f$ |\bar{\mathcal{M}}|^2 \f$
*/
virtual void debug(double me2) const;
private:
/**
* Store a pair of FFTVertex and FFVVertex pointers
*/
vector<pair<AbstractFFTVertexPtr, AbstractFFVVertexPtr> > fermion_;
/**
* Store a pair of FFTVertex and VVTVertex pointers
*/
vector<pair<AbstractFFVVertexPtr, AbstractVVTVertexPtr> > vector_;
/**
* The four point vertex
*/
vector<AbstractFFVTVertexPtr> fourPoint_;
};
}
#endif /* HERWIG_MEff2tv_H */
diff --git a/MatrixElement/General/MEff2vs.cc b/MatrixElement/General/MEff2vs.cc
--- a/MatrixElement/General/MEff2vs.cc
+++ b/MatrixElement/General/MEff2vs.cc
@@ -1,222 +1,231 @@
// -*- C++ -*-
//
// MEff2vs.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEff2vs class.
//
#include "MEff2vs.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
void MEff2vs::doinit() {
GeneralHardME::doinit();
scalar_.resize(numberOfDiags());
vector_.resize(numberOfDiags());
fermion_.resize(numberOfDiags());
+ four_.resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
PDT::Spin1,PDT::Spin0);
for(HPCount i = 0; i < numberOfDiags(); ++i) {
const HPDiagram & current = getProcessInfo()[i];
if( current.channelType == HPDiagram::sChannel ) {
if( current.intermediate->iSpin() == PDT::Spin0 )
scalar_[i] =
make_pair(dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.first),
dynamic_ptr_cast<AbstractVSSVertexPtr>(current.vertices.second));
else if( current.intermediate->iSpin() == PDT::Spin1 )
vector_[i] =
make_pair(dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.first),
dynamic_ptr_cast<AbstractVVSVertexPtr>(current.vertices.second));
}
else if( current.channelType == HPDiagram::tChannel ) {
if(current.intermediate->iSpin() == PDT::Spin1Half) {
if( current.ordered.second )
fermion_[i] =
make_pair(dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.first),
dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.second));
else
fermion_[i] =
make_pair(dynamic_ptr_cast<AbstractFFVVertexPtr>(current.vertices.second),
dynamic_ptr_cast<AbstractFFSVertexPtr>(current.vertices.first));
}
}
+ else if( current.channelType == HPDiagram::fourPoint) {
+ four_[i] = dynamic_ptr_cast<AbstractFFVSVertexPtr>(current.vertices.first);
+ }
}
}
void MEff2vs::persistentOutput(PersistentOStream & os) const {
- os << scalar_ << vector_ << fermion_;
+ os << scalar_ << vector_ << fermion_ << four_;
}
void MEff2vs::persistentInput(PersistentIStream & is, int) {
- is >> scalar_ >> vector_ >> fermion_;
+ is >> scalar_ >> vector_ >> fermion_ >> four_;
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1Half,
PDT::Spin1,PDT::Spin0);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEff2vs,GeneralHardME>
describeHerwigMEff2vs("Herwig::MEff2vs", "Herwig.so");
void MEff2vs::Init() {
static ClassDocumentation<MEff2vs> documentation
("MEff2vs implements the ME calculation of the fermion-antifermion "
"to vector-scalar hard process.");
}
double MEff2vs::me2() const {
//set up wavefunctions
SpinorVector ina(2);
SpinorBarVector inb(2);
VBVector outa(3);
+
ScalarWaveFunction sca(rescaledMomenta()[3], mePartonData()[3], Complex(1.),
outgoing);
for(unsigned int ih = 0; ih < 2; ++ih) {
ina[ih] = SpinorWaveFunction(rescaledMomenta()[0], mePartonData()[0],
ih, incoming);
inb[ih] = SpinorBarWaveFunction(rescaledMomenta()[1], mePartonData()[1],
ih, incoming);
outa[2*ih] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2],
2*ih, outgoing);
}
if( mePartonData()[2]->mass() > ZERO ) {
outa[1] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2],
1, outgoing);
}
double full_me(0.);
ffb2vsHeME(ina, inb, outa, sca, full_me,true);
return full_me;
}
ProductionMatrixElement
MEff2vs::ffb2vsHeME(SpinorVector & sp, SpinorBarVector & spbar,
VBVector & vec, ScalarWaveFunction & sca,
double & me2, bool first) const {
Energy2 m2(scale());
bool mv = mePartonData()[2]->mass() == ZERO;
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
me2 = 0.;
for(unsigned int ihel1 = 0; ihel1 < 2; ++ihel1) {
for(unsigned int ihel2 = 0; ihel2 < 2; ++ihel2) {
for(unsigned int ovhel = 0; ovhel < 3; ++ovhel) {
if( mv && ovhel == 1 ) continue;
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell(current.intermediate);
if( current.channelType == HPDiagram::sChannel ) {
if( offshell->iSpin() == PDT::Spin0 ) {
ScalarWaveFunction interS = scalar_[ix].first->
evaluate(m2, 1, offshell, sp[ihel1], spbar[ihel2]);
- diag = scalar_[ix].second->evaluate(m2, vec[ovhel], sca, interS);
+ diag = scalar_[ix].second->evaluate(m2, vec[ovhel], sca, interS);
}
else if( offshell->iSpin() == PDT::Spin1 ) {
VectorWaveFunction interV = vector_[ix].first->
evaluate(m2, 1, offshell, sp[ihel1], spbar[ihel2]);
diag = vector_[ix].second->evaluate(m2, vec[ovhel], interV, sca);
}
else diag = 0.0;
}
else if( current.channelType == HPDiagram::tChannel ) {
if( offshell->iSpin() == PDT::Spin1Half ) {
if( current.ordered.second ) {
if(offshell->CC()) offshell = offshell->CC();
SpinorBarWaveFunction interFB = fermion_[ix].second->
evaluate(m2, 3, offshell, spbar[ihel2], sca);
diag = fermion_[ix].first->
evaluate(m2, sp[ihel1], interFB, vec[ovhel]);
}
else {
if(offshell->CC()) offshell = offshell->CC();
SpinorBarWaveFunction interFB = fermion_[ix].first->
evaluate(m2, 3, offshell, spbar[ihel2], vec[ovhel]);
diag = fermion_[ix].second->
evaluate(m2, sp[ihel1], interFB, sca);
}
}
}
- else diag = 0.0;
+ else if( current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]->evaluate(m2,sp[ihel1], spbar[ihel2], vec[ovhel], sca);
+ }
+ else
+ assert(false);
me[ix] += norm(diag);
diagramME()[ix](ihel1, ihel2, ovhel, 0) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](ihel1, ihel2, ovhel, 0) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEff2vs::constructVertex(tSubProPtr sub) {
// Hard proces external particles
ParticleVector hdp = hardParticles(sub);
// wavefunctions with real momenta
SpinorVector sp;
SpinorBarVector spbar;
VBVector vec;
bool mv(hdp[2]->dataPtr()->mass() == ZERO);
SpinorWaveFunction (sp, hdp[0], incoming, false);
SpinorBarWaveFunction (spbar, hdp[1], incoming, false);
VectorWaveFunction (vec, hdp[2], outgoing, true, mv);
ScalarWaveFunction sca( hdp[3], outgoing, true);
//Need to use rescale momenta to calculate matrix element
setRescaledMomenta(hdp);
// wavefunctions with rescaled momenta
SpinorWaveFunction spr( rescaledMomenta()[0], hdp[0]->dataPtr(), incoming);
SpinorBarWaveFunction sbr(rescaledMomenta()[1], hdp[1]->dataPtr(), incoming);
VectorWaveFunction vr( rescaledMomenta()[2], hdp[2]->dataPtr(), outgoing);
sca = ScalarWaveFunction( rescaledMomenta()[3], hdp[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
spr.reset(ihel);
sp[ihel] = spr;
sbr.reset(ihel);
spbar[ihel] = sbr;
vr.reset(2*ihel);
vec[2*ihel] = vr;
}
if( !mv ) {
vr.reset(1);
vec[1] = vr;
}
double dummy(0.);
ProductionMatrixElement prodme = ffb2vsHeME(sp, spbar, vec, sca, dummy,false);
createVertex(prodme,hdp);
}
diff --git a/MatrixElement/General/MEff2vs.h b/MatrixElement/General/MEff2vs.h
--- a/MatrixElement/General/MEff2vs.h
+++ b/MatrixElement/General/MEff2vs.h
@@ -1,199 +1,205 @@
// -*- C++ -*-
//
// MEff2vs.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_MEff2vs_H
#define HERWIG_MEff2vs_H
//
// This is the declaration of the MEff2vs class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFVSVertex.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::SpinorWaveFunction;
using Helicity::SpinorBarWaveFunction;
using Helicity::VectorWaveFunction;
using Helicity::ScalarWaveFunction;
/**
* The MEff2vs class is designed to implement the matrix element for a
* fermion-antifermion to vector-scalar hard process. It inherits from
* GeneralHardME and implements the appropriate virtual functions for this
* specific spin combination.
*
* @see \ref MEff2vsInterfaces "The interfaces"
* defined for MEff2vs.
* @see GeneralHardME
*/
class MEff2vs: public GeneralHardME {
public:
/** @name Typedefs */
//@{
/**
* A vector of SpinorWaveFunctions
*/
typedef vector<SpinorWaveFunction> SpinorVector;
/**
* A vector of SpinorWaveBarFunctions
*/
typedef vector<SpinorBarWaveFunction> SpinorBarVector;
/**
* A vector of VectorWaveFunctions
*/
typedef vector<VectorWaveFunction> VBVector;
//@}
public:
/**
* The default constructor.
*/
MEff2vs() : scalar_(0), vector_(0), fermion_(0) {}
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
/**
* Construct the vertex information for the spin correlations
* @param sub Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr sub);
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEff2vs & operator=(const MEff2vs &);
private:
/** @name Functions to compute the ProductionMatrixElement. */
//@{
/**
* Compute the matrix element for \f$\Psi\bar{\Psi}\to\Psi\bar{\Psi}\f$
* @param sp Spinors for first incoming particle
* @param spbar SpinorBar Wavefunctions for second incoming particle
* @param vec VectorWaveFunctions for outgoing vector
* @param sca Outgoing ScalarWaveFunction
* @param me2 colour averaged, spin summed ME
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @return ProductionMatrixElement containing results of
* helicity calculations
*/
ProductionMatrixElement
ffb2vsHeME(SpinorVector & sp, SpinorBarVector & spbar,
VBVector & vec, ScalarWaveFunction & sca,
double & me2,bool first) const;
//@}
private:
/**
* Storage for dynamically cast vertices for a diagram with intermediate
* scalar
*/
vector<pair<AbstractFFSVertexPtr, AbstractVSSVertexPtr> > scalar_;
/**
* Storage for dynamically cast vertices for a diagram with intermediate
* vector
*/
vector<pair<AbstractFFVVertexPtr, AbstractVVSVertexPtr> > vector_;
/**
* Storage for dynamically cast vertices for a diagram with intermediate
* fermion
*/
vector<pair<AbstractFFVVertexPtr, AbstractFFSVertexPtr> > fermion_;
+
+ /**
+ * Four point vertices
+ */
+ vector<AbstractFFVSVertexPtr> four_;
};
}
#endif /* HERWIG_MEff2vs_H */
diff --git a/MatrixElement/General/MEfv2fs.cc b/MatrixElement/General/MEfv2fs.cc
--- a/MatrixElement/General/MEfv2fs.cc
+++ b/MatrixElement/General/MEfv2fs.cc
@@ -1,363 +1,451 @@
// -*- C++ -*-
//
// MEfv2fs.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEfv2fs class.
//
#include "MEfv2fs.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
void MEfv2fs::doinit() {
GeneralHardME::doinit();
scalar_.resize(numberOfDiags());
fermion_.resize(numberOfDiags());
+ vector_.resize(numberOfDiags());
+ four_.resize(numberOfDiags());
+ RSfermion_.resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1,
PDT::Spin1Half, PDT::Spin0);
for(size_t ix = 0; ix < numberOfDiags(); ++ix) {
HPDiagram curr = getProcessInfo()[ix];
if(curr.channelType == HPDiagram::tChannel) {
AbstractFFSVertexPtr ffs =
dynamic_ptr_cast<AbstractFFSVertexPtr>(curr.vertices.first);
if( curr.intermediate->iSpin() == PDT::Spin0 ) {
AbstractVSSVertexPtr vss =
dynamic_ptr_cast<AbstractVSSVertexPtr>(curr.vertices.second);
scalar_[ix] = make_pair(ffs, vss);
}
- else {
+ else if ( curr.intermediate->iSpin() == PDT::Spin1Half ) {
AbstractFFVVertexPtr ffv =
dynamic_ptr_cast<AbstractFFVVertexPtr>(curr.vertices.second);
fermion_[ix] = make_pair(ffs, ffv);
}
+ else if ( curr.intermediate->iSpin() == PDT::Spin1 ) {
+ AbstractFFVVertexPtr ffv =
+ dynamic_ptr_cast<AbstractFFVVertexPtr>(curr.vertices.first);
+ AbstractVVSVertexPtr vvs =
+ dynamic_ptr_cast<AbstractVVSVertexPtr>(curr.vertices.second);
+ vector_[ix] = make_pair(ffv, vvs);
+ }
+ else if ( curr.intermediate->iSpin() == PDT::Spin3Half ) {
+ AbstractRFSVertexPtr rfs =
+ dynamic_ptr_cast<AbstractRFSVertexPtr>(curr.vertices.first);
+ AbstractRFVVertexPtr rfv =
+ dynamic_ptr_cast<AbstractRFVVertexPtr>(curr.vertices.second);
+ RSfermion_[ix] = make_pair(rfs, rfv);
+ }
+ else
+ assert(false);
}
- else {
- AbstractFFVVertexPtr ffv =
- dynamic_ptr_cast<AbstractFFVVertexPtr>(curr.vertices.first);
- AbstractFFSVertexPtr ffs =
- dynamic_ptr_cast<AbstractFFSVertexPtr>(curr.vertices.second);
- fermion_[ix] = make_pair(ffs, ffv);
+ else if(curr.channelType == HPDiagram::sChannel) {
+ if(curr.intermediate->iSpin() == PDT::Spin1Half ) {
+ AbstractFFVVertexPtr ffv =
+ dynamic_ptr_cast<AbstractFFVVertexPtr>(curr.vertices.first);
+ AbstractFFSVertexPtr ffs =
+ dynamic_ptr_cast<AbstractFFSVertexPtr>(curr.vertices.second);
+ fermion_[ix] = make_pair(ffs, ffv);
+ }
+ else {
+ AbstractRFVVertexPtr rfv =
+ dynamic_ptr_cast<AbstractRFVVertexPtr>(curr.vertices.first);
+ AbstractRFSVertexPtr rfs =
+ dynamic_ptr_cast<AbstractRFSVertexPtr>(curr.vertices.second);
+ RSfermion_[ix] = make_pair(rfs, rfv);
+ }
}
+ else if(curr.channelType == HPDiagram::fourPoint) {
+ four_[ix] = dynamic_ptr_cast<AbstractFFVSVertexPtr>(curr.vertices.first);
+ }
+ else
+ assert(false);
}
}
double MEfv2fs::me2() const {
//massless vector
VecWFVector vecIn(2);
ScalarWaveFunction scaOut(rescaledMomenta()[3], mePartonData()[3],
Complex(1.,0.), outgoing);
double fullme(0.);
if( mePartonData()[0]->id() > 0 ) {
SpinorVector spIn(2);
SpinorBarVector spbOut(2);
for(size_t ih = 0; ih < 2; ++ih) {
spIn[ih] = SpinorWaveFunction(rescaledMomenta()[0], mePartonData()[0], ih,
incoming);
spbOut[ih] = SpinorBarWaveFunction(rescaledMomenta()[2], mePartonData()[2], ih,
outgoing);
vecIn[ih] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*ih,
incoming);
}
fv2fbsHeME(spIn, vecIn, spbOut, scaOut, fullme,true);
}
else {
SpinorBarVector spbIn(2);
SpinorVector spOut(2);
for(size_t ih = 0; ih < 2; ++ih) {
spbIn[ih] = SpinorBarWaveFunction(rescaledMomenta()[0], mePartonData()[0], ih,
incoming);
spOut[ih] = SpinorWaveFunction(rescaledMomenta()[2], mePartonData()[2], ih,
outgoing);
vecIn[ih] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*ih,
incoming);
}
fbv2fsHeME(spbIn, vecIn, spOut, scaOut, fullme,true);
}
#ifndef NDEBUG
if( debugME() ) debug(fullme);
#endif
return fullme;
}
ProductionMatrixElement
MEfv2fs::fv2fbsHeME(const SpinorVector & spIn, const VecWFVector & vecIn,
const SpinorBarVector & spbOut,
const ScalarWaveFunction & scaOut,
double & me2, bool first) const {
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
me2 = 0.;
for(unsigned int ihel1 = 0; ihel1 < 2; ++ihel1) {
for(unsigned int ihel2 = 0; ihel2 < 2; ++ihel2) {
for(unsigned int ohel1 = 0; ohel1 < 2; ++ohel1) {
vector<Complex> flows(numberOfFlows(),0.);
for(size_t ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if( current.channelType == HPDiagram::tChannel ) {
if( offshell->iSpin() == PDT::Spin0 ) {
ScalarWaveFunction interS = scalar_[ix].first->
evaluate(q2, 3, offshell, spIn[ihel1], spbOut[ohel1]);
diag = scalar_[ix].second->
evaluate(q2, vecIn[ihel2], scaOut, interS);
}
else if( offshell->iSpin() == PDT::Spin1Half ) {
if(offshell->CC()) offshell = offshell->CC();
SpinorBarWaveFunction interFB = fermion_[ix].second->
evaluate(q2, 3, offshell,spbOut[ohel1],vecIn[ihel2]);
diag = fermion_[ix].first->
evaluate(q2, spIn[ihel1], interFB, scaOut);
}
- else diag = 0.0;
+ else if( offshell->iSpin() == PDT::Spin1 ) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2,3,offshell,spIn[ihel1],spbOut[ohel1]);
+ diag = vector_[ix].second->
+ evaluate(q2, vecIn[ihel2], interV, scaOut);
+ }
+ else if( offshell->iSpin() == PDT::Spin3Half ) {
+ if(offshell->CC()) offshell = offshell->CC();
+ RSSpinorBarWaveFunction interFB = RSfermion_[ix].second->
+ evaluate(q2, 3, offshell,spbOut[ohel1],vecIn[ihel2]);
+ diag = RSfermion_[ix].first->
+ evaluate(q2, spIn[ihel1], interFB, scaOut);
+ }
}
else if( current.channelType == HPDiagram::sChannel ) {
- // check if take intermediate massless
- unsigned int propOpt =
- abs(offshell->id()) != abs(spIn[ihel1].particle()->id()) ? 1 : 5;
- SpinorWaveFunction interF = fermion_[ix].second->
- evaluate(q2, propOpt, offshell, spIn[ihel1], vecIn[ihel2]);
- diag = fermion_[ix].first->
- evaluate(q2, interF, spbOut[ohel1], scaOut);
+ if( offshell->iSpin() == PDT::Spin1Half ) {
+ // check if take intermediate massless
+ unsigned int propOpt =
+ abs(offshell->id()) != abs(spIn[ihel1].particle()->id()) ? 1 : 5;
+ SpinorWaveFunction interF = fermion_[ix].second->
+ evaluate(q2, propOpt, offshell, spIn[ihel1], vecIn[ihel2]);
+ diag = fermion_[ix].first->
+ evaluate(q2, interF, spbOut[ohel1], scaOut);
+ }
+ else if( offshell->iSpin() == PDT::Spin3Half ) {
+ RSSpinorWaveFunction interF = RSfermion_[ix].second->
+ evaluate(q2, 1, offshell, spIn[ihel1], vecIn[ihel2]);
+ diag = RSfermion_[ix].first->
+ evaluate(q2, interF, spbOut[ohel1], scaOut);
+ }
+ else
+ assert(false);
}
- else diag = 0.0;
+ else if( current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]-> evaluate(q2, spIn[ihel1], spbOut[ohel1],
+ vecIn[ihel2], scaOut);
+ }
+ else
+ assert(false);
me[ix] += norm(diag);
diagramME()[ix](ihel1, 2*ihel2, ohel1, 0) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](ihel1, 2*ihel2, ohel1, 0) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
ProductionMatrixElement
MEfv2fs::fbv2fsHeME(const SpinorBarVector & spbIn, const VecWFVector & vecIn,
const SpinorVector & spOut,
const ScalarWaveFunction & scaOut,
double & me2, bool first) const {
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
me2 = 0.;
for(unsigned int ihel1 = 0; ihel1 < 2; ++ihel1) {
for(unsigned int ihel2 = 0; ihel2 < 2; ++ihel2) {
for(unsigned int ohel1 = 0; ohel1 < 2; ++ohel1) {
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if( current.channelType == HPDiagram::tChannel ) {
if( offshell->iSpin() == PDT::Spin0 ) {
ScalarWaveFunction interS = scalar_[ix].first->
evaluate(q2, 3, offshell, spOut[ohel1], spbIn[ihel1]);
diag = scalar_[ix].second->
evaluate(q2, vecIn[ihel2], interS, scaOut);
}
else if( offshell->iSpin() == PDT::Spin1Half ) {
SpinorBarWaveFunction interFB = fermion_[ix].first->
evaluate(q2, 3, offshell, spbIn[ihel1], scaOut);
diag = fermion_[ix].second->
evaluate(q2, spOut[ohel1], interFB, vecIn[ihel2]);
}
- else diag = 0.0;
+ else if( offshell->iSpin() == PDT::Spin1 ) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2,3,offshell, spOut[ohel1], spbIn[ihel1]);
+ diag = vector_[ix].second->
+ evaluate(q2, vecIn[ihel2], interV, scaOut);
+ }
+ else if( offshell->iSpin() == PDT::Spin3Half ) {
+ RSSpinorBarWaveFunction interFB = RSfermion_[ix].first->
+ evaluate(q2, 3, offshell, spbIn[ihel1], scaOut);
+ diag = RSfermion_[ix].second->
+ evaluate(q2, spOut[ohel1], interFB, vecIn[ihel2]);
+ }
+ else
+ assert(false);
}
else if( current.channelType == HPDiagram::sChannel ) {
- // check if take intermediate massless
- unsigned int propOpt =
- abs(offshell->id()) != abs(spbIn[ihel1].particle()->id()) ? 1 : 5;
- SpinorBarWaveFunction interFB = fermion_[ix].second->
- evaluate(q2, propOpt, offshell, spbIn[ihel1], vecIn[ihel2]);
- diag = fermion_[ix].first->
- evaluate(q2, spOut[ohel1], interFB, scaOut);
+ if( offshell->iSpin() == PDT::Spin1Half ) {
+ // check if take intermediate massless
+ unsigned int propOpt =
+ abs(offshell->id()) != abs(spbIn[ihel1].particle()->id()) ? 1 : 5;
+ SpinorBarWaveFunction interFB = fermion_[ix].second->
+ evaluate(q2, propOpt, offshell, spbIn[ihel1], vecIn[ihel2]);
+ diag = fermion_[ix].first->
+ evaluate(q2, spOut[ohel1], interFB, scaOut);
+ }
+ else if( offshell->iSpin() == PDT::Spin3Half ) {
+ RSSpinorBarWaveFunction interFB = RSfermion_[ix].second->
+ evaluate(q2, 1, offshell, spbIn[ihel1], vecIn[ihel2]);
+ diag = RSfermion_[ix].first->
+ evaluate(q2, spOut[ohel1], interFB, scaOut);
+ }
+ else
+ assert(false);
}
- else diag = 0.0;
+ else if( current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]-> evaluate(q2, spOut[ohel1], spbIn[ihel1],
+ vecIn[ihel2], scaOut);
+ }
+ else
+ assert(false);
me[ix] += norm(diag);
diagramME()[ix](ihel1, 2*ihel2, ohel1, 0) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](ihel1, 2*ihel2, ohel1, 0) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEfv2fs::persistentOutput(PersistentOStream & os) const {
- os << scalar_ << fermion_;
+ os << scalar_ << fermion_ << vector_ << four_ << RSfermion_;
}
void MEfv2fs::persistentInput(PersistentIStream & is, int) {
- is >> scalar_ >> fermion_;
+ is >> scalar_ >> fermion_ >> vector_ >> four_ >> RSfermion_;
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1,
PDT::Spin1Half, PDT::Spin0);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEfv2fs,GeneralHardME>
describeHerwigMEfv2fs("Herwig::MEfv2fs", "Herwig.so");
void MEfv2fs::Init() {
static ClassDocumentation<MEfv2fs> documentation
("This class implements the matrix element for a fermion-vector to "
"a fermioin-scalar.");
}
void MEfv2fs::constructVertex(tSubProPtr subp) {
ParticleVector external = hardParticles(subp);
//calculate production ME
VecWFVector vecIn;
VectorWaveFunction(vecIn, external[1], incoming, false, true);
ScalarWaveFunction scaOut(external[3], outgoing, true);
//Need to use rescale momenta to calculate matrix element
setRescaledMomenta(external);
double dummy(0.);
if( external[0]->id() > 0 ) {
SpinorVector spIn;
SpinorBarVector spbOut;
SpinorWaveFunction (spIn, external[0], incoming, false);
SpinorBarWaveFunction(spbOut, external[2], outgoing, true);
SpinorWaveFunction spr (rescaledMomenta()[0],
external[0]->dataPtr(), incoming);
VectorWaveFunction vr (rescaledMomenta()[1],
external[1]->dataPtr(), incoming);
SpinorBarWaveFunction sbr (rescaledMomenta()[2],
external[2]->dataPtr(), outgoing);
scaOut = ScalarWaveFunction(rescaledMomenta()[3],
external[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
spr.reset(ihel);
spIn[ihel] = spr;
vr.reset(2*ihel);
vecIn[ihel] = vr;
sbr.reset(ihel);
spbOut[ihel] = sbr;
}
ProductionMatrixElement prodME = fv2fbsHeME(spIn, vecIn, spbOut,
scaOut, dummy,false);
createVertex(prodME,external);
}
else {
SpinorBarVector spbIn;
SpinorVector spOut;
SpinorBarWaveFunction(spbIn, external[0], incoming, false);
SpinorWaveFunction (spOut, external[2], outgoing, true);
SpinorBarWaveFunction sbr (rescaledMomenta()[0],
external[0]->dataPtr(), incoming);
VectorWaveFunction vr (rescaledMomenta()[1],
external[1]->dataPtr(), incoming);
SpinorWaveFunction spr (rescaledMomenta()[2],
external[2]->dataPtr(), outgoing);
scaOut = ScalarWaveFunction(rescaledMomenta()[3],
external[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
sbr.reset(ihel);
spbIn[ihel] = sbr;
vr.reset(2*ihel);
vecIn[ihel] = vr;
spr.reset(ihel);
spOut[ihel] = spr;
}
ProductionMatrixElement prodME = fbv2fsHeME(spbIn, vecIn, spOut,
scaOut, dummy,false);
createVertex(prodME,external);
}
#ifndef NDEBUG
if( debugME() ) debug(dummy/96.);
#endif
}
void MEfv2fs::debug(double me2) const {
if( !generator()->logfile().is_open() ) return;
long id1 = abs(mePartonData()[0]->id());
long id4 = abs(mePartonData()[3]->id());
if( (id1 != 1 && id1 != 2) || mePartonData()[1]->id() != 21 ||
mePartonData()[2]->id() != 1000021 ||
(id4 != 1000001 && id4 != 1000002 && id4 != 2000001 &&
id4 != 2000002) ) return;
tcSMPtr sm = generator()->standardModel();
double gs4 = sqr( 4.*Constants::pi*sm->alphaS(scale()) );
int Nc = sm->Nc();
Energy2 m3s = sqr(mePartonData()[2]->mass());
Energy2 m4s = sqr(mePartonData()[3]->mass());
//formula has vf->fs so swap t and u
Energy2 s(sHat()), t3(uHat() - m3s), u4(tHat() - m4s);
double analytic = -gs4*( u4 + 2.*(m4s - m3s)*(1. + m3s/t3 + m4s/u4) )*
( sqr(u4) + sqr(s) - sqr(t3)/sqr(Nc) )/s/t3/u4/4.;
double diff = abs( analytic - me2);
if( diff > 1e-4 ) {
generator()->log()
<< mePartonData()[0]->PDGName() << ","
<< mePartonData()[1]->PDGName() << "->"
<< mePartonData()[2]->PDGName() << ","
<< mePartonData()[3]->PDGName() << " difference: "
<< setprecision(10) << diff << " ratio: " << analytic/me2 << '\n';
}
}
diff --git a/MatrixElement/General/MEfv2fs.h b/MatrixElement/General/MEfv2fs.h
--- a/MatrixElement/General/MEfv2fs.h
+++ b/MatrixElement/General/MEfv2fs.h
@@ -1,205 +1,214 @@
// -*- C++ -*-
//
// MEfv2fs.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_MEfv2fs_H
#define HERWIG_MEfv2fs_H
//
// This is the declaration of the MEfv2fs class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFVSVertex.h"
namespace Herwig {
using namespace ThePEG;
using ThePEG::Helicity::SpinorWaveFunction;
using ThePEG::Helicity::SpinorBarWaveFunction;
using ThePEG::Helicity::VectorWaveFunction;
using ThePEG::Helicity::ScalarWaveFunction;
/**
* This class is designed to implement the matrix element for
* fermion-vector to fermion scalar. It inherits from GeneralHardME
* and implements the required virtual functions.
*
- * @see @see \ref MEfv2fsInterfaces "The Interfaces"
- * defined for MEfv2fs.
* @see GeneralHardME
*/
class MEfv2fs: public GeneralHardME {
/** Vector of SpinorWaveFunctions. */
typedef vector<SpinorWaveFunction> SpinorVector;
/** Vector of SpinorBarWaveFunctions. */
typedef vector<SpinorBarWaveFunction> SpinorBarVector;
/** Vector of VectorWaveFunctions. */
typedef vector<VectorWaveFunction> VecWFVector;
public:
- /**
- * The default constructor.
- */
- MEfv2fs() : scalar_(0), fermion_(0) {}
-
-public:
-
/** @name Virtual functions required by the GeneralHardME class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
/**
* Construct the vertex information for the spin correlations
* @param subp Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr subp);
private:
/** @name Functions to calculate production matrix elements and me2. */
//@{
/**
* Calculate me2 and the production matrix element for the normal mode.
* @param spIn Vector of SpinorWaveFunction for the incoming fermion
* @param vecIn Vector of VectorWaveFunction for incoming boson
* @param spbOut Vector of SpinorBarWaveFunction for outgoing fermion
* @param scaOut ScalarWaveFunction for outgoing scalar.
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @param full_me The value of me2 calculation
*/
ProductionMatrixElement fv2fbsHeME(const SpinorVector & spIn,
const VecWFVector & vecIn,
const SpinorBarVector & spbOut,
const ScalarWaveFunction & scaOut,
double & full_me, bool first) const;
/**
* Calculate me2 and the production matrix element for the cc mode.
* @param spbIn Vector of SpinorBarWaveFunction for the incoming fermion
* @param vecIn Vector of VectorWaveFunction for incoming boson
* @param spOut Vector of SpinorWaveFunction for outgoing fermion
* @param scaOut ScalarWaveFunction for outgoing scalar.
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @param full_me The value of me2 calculation
*/
ProductionMatrixElement fbv2fsHeME(const SpinorBarVector & spbIn,
const VecWFVector & vecIn,
const SpinorVector & spOut,
const ScalarWaveFunction & scaOut,
double & full_me, bool first) const;
//@}
protected:
/**
* A debugging function to test the value of me2 against an
* analytic function.
* @param me2 The value of the \f$ |\bar{\mathcal{M}}|^2 \f$
*/
virtual void debug(double me2) 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 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.
*/
void doinit();
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEfv2fs & operator=(const MEfv2fs &);
private:
/**
* Store a pair of FFSVertex and VSSVertex pointers
*/
vector<pair<AbstractFFSVertexPtr, AbstractVSSVertexPtr> > scalar_;
/**
* Store a pair of FFSVertex and FFVVertex pointers
*/
vector<pair<AbstractFFSVertexPtr, AbstractFFVVertexPtr> > fermion_;
-
+
+ /**
+ * Store a pair of VVSVertex and FFVVertex pointers
+ */
+ vector<pair<AbstractFFVVertexPtr,AbstractVVSVertexPtr> > vector_;
+
+ /**
+ * Store a pair of FFSVertex and FFVVertex pointers
+ */
+ vector<pair<AbstractRFSVertexPtr, AbstractRFVVertexPtr> > RSfermion_;
+
+ /**
+ * Store any 4-point vertices
+ */
+ vector<AbstractFFVSVertexPtr> four_;
};
}
#endif /* HERWIG_MEfv2fs_H */
diff --git a/MatrixElement/General/MEfv2rs.cc b/MatrixElement/General/MEfv2rs.cc
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEfv2rs.cc
@@ -0,0 +1,382 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the MEfv2rs class.
+//
+
+#include "MEfv2rs.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Utilities/DescribeClass.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+
+using namespace Herwig;
+
+double MEfv2rs::me2() const {
+ //massless vector
+ VecWFVector vecIn(2);
+ ScalarWaveFunction scaOut(rescaledMomenta()[3], mePartonData()[3],
+ Complex(1.,0.), outgoing);
+ double fullme(0.);
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ if( mePartonData()[0]->id() > 0 ) {
+ SpinorVector spIn(2);
+ RSSpinorBarVector spbOut(4);
+ for(size_t ih = 0; ih < 2; ++ih) {
+ spIn[ih] = SpinorWaveFunction(rescaledMomenta()[0], mePartonData()[0], ih,
+ incoming);
+ vecIn[ih] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*ih,
+ incoming);
+ }
+ for(size_t ih = 0; ih < 4; ++ih) {
+ if(massless && (ih==1 || ih==2)) continue;
+ spbOut[ih] = RSSpinorBarWaveFunction(rescaledMomenta()[2], mePartonData()[2], ih,
+ outgoing);
+ }
+ fv2rbsHeME(spIn, vecIn, spbOut, scaOut, fullme,true);
+ }
+ else {
+ SpinorBarVector spbIn(2);
+ RSSpinorVector spOut(4);
+ for(size_t ih = 0; ih < 2; ++ih) {
+ spbIn[ih] = SpinorBarWaveFunction(rescaledMomenta()[0], mePartonData()[0], ih,
+ incoming);
+ vecIn[ih] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*ih,
+ incoming);
+ }
+ for(size_t ih = 0; ih < 4; ++ih) {
+ if(massless && (ih==1 || ih==2)) continue;
+ spOut[ih] = RSSpinorWaveFunction(rescaledMomenta()[2], mePartonData()[2], ih,
+ outgoing);
+ }
+ fbv2rsHeME(spbIn, vecIn, spOut, scaOut, fullme,true);
+ }
+
+ return fullme;
+}
+
+IBPtr MEfv2rs::clone() const {
+ return new_ptr(*this);
+}
+
+IBPtr MEfv2rs::fullclone() const {
+ return new_ptr(*this);
+}
+
+void MEfv2rs::doinit() {
+ GeneralHardME::doinit();
+ scalar_.resize(numberOfDiags());
+ fermion1_.resize(numberOfDiags());
+ fermion2_.resize(numberOfDiags());
+ vector_.resize(numberOfDiags());
+ four_.resize(numberOfDiags());
+ initializeMatrixElements(PDT::Spin1Half, PDT::Spin1,
+ PDT::Spin3Half, PDT::Spin0);
+ for(size_t ix = 0; ix < numberOfDiags(); ++ix) {
+ HPDiagram curr = getProcessInfo()[ix];
+ if(curr.channelType == HPDiagram::tChannel) {
+ if( curr.intermediate->iSpin() == PDT::Spin0 ) {
+ AbstractRFSVertexPtr rfs =
+ dynamic_ptr_cast<AbstractRFSVertexPtr>(curr.vertices.first);
+ AbstractVSSVertexPtr vss =
+ dynamic_ptr_cast<AbstractVSSVertexPtr>(curr.vertices.second);
+ scalar_[ix] = make_pair(rfs, vss);
+ }
+ else if ( curr.intermediate->iSpin() == PDT::Spin1Half ) {
+ AbstractFFSVertexPtr ffs =
+ dynamic_ptr_cast<AbstractFFSVertexPtr>(curr.vertices.first);
+ AbstractRFVVertexPtr rfv =
+ dynamic_ptr_cast<AbstractRFVVertexPtr>(curr.vertices.second);
+ fermion2_[ix] = make_pair(ffs, rfv);
+ }
+ else if ( curr.intermediate->iSpin() == PDT::Spin1 ) {
+ AbstractRFVVertexPtr rfv =
+ dynamic_ptr_cast<AbstractRFVVertexPtr>(curr.vertices.first);
+ AbstractVVSVertexPtr vvs =
+ dynamic_ptr_cast<AbstractVVSVertexPtr>(curr.vertices.second);
+ vector_[ix] = make_pair(rfv, vvs);
+ }
+ else
+ assert(false);
+ }
+ else if (curr.channelType == HPDiagram::sChannel) {
+ assert(curr.intermediate->iSpin() == PDT::Spin1Half );
+ AbstractFFVVertexPtr ffv =
+ dynamic_ptr_cast<AbstractFFVVertexPtr>(curr.vertices.first);
+ AbstractRFSVertexPtr rfs =
+ dynamic_ptr_cast<AbstractRFSVertexPtr>(curr.vertices.second);
+ fermion1_[ix] = make_pair(ffv,rfs);
+ }
+ else if (curr.channelType == HPDiagram::fourPoint) {
+ four_[ix] = dynamic_ptr_cast<AbstractRFVSVertexPtr>(curr.vertices.first);
+ }
+ else
+ assert(false);
+ }
+}
+
+void MEfv2rs::persistentOutput(PersistentOStream & os) const {
+ os << scalar_ << fermion1_ << fermion2_ << vector_ << four_;
+}
+
+void MEfv2rs::persistentInput(PersistentIStream & is, int) {
+ is >> scalar_ >> fermion1_ >> fermion2_ >> vector_ >> four_;
+ initializeMatrixElements(PDT::Spin1Half, PDT::Spin1,
+ PDT::Spin3Half, PDT::Spin0);
+}
+
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEfv2rs,GeneralHardME>
+describeHerwigMEfv2rs("Herwig::MEfv2rs", "Herwig.so");
+
+void MEfv2rs::Init() {
+
+ static ClassDocumentation<MEfv2rs> documentation
+ ("The MEfv2rs class implements the general matrix element for "
+ "fermion-vector to RS fermion scalar");
+
+}
+
+ProductionMatrixElement
+MEfv2rs::fv2rbsHeME(const SpinorVector & spIn, const VecWFVector & vecIn,
+ const RSSpinorBarVector & spbOut,
+ const ScalarWaveFunction & scaOut,
+ double & me2, bool first) const {
+ const Energy2 q2(scale());
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ me2 = 0.;
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ for(unsigned int ihel1 = 0; ihel1 < 2; ++ihel1) {
+ for(unsigned int ihel2 = 0; ihel2 < 2; ++ihel2) {
+ for(unsigned int ohel1 = 0; ohel1 < 4; ++ohel1) {
+ if(massless && (ohel1==1 || ohel1==2)) continue;
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(size_t ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if( current.channelType == HPDiagram::tChannel ) {
+ if( offshell->iSpin() == PDT::Spin0 ) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 3, offshell, spIn[ihel1], spbOut[ohel1]);
+ diag = scalar_[ix].second->
+ evaluate(q2, vecIn[ihel2], scaOut, interS);
+ }
+ else if( offshell->iSpin() == PDT::Spin1Half ) {
+ if(offshell->CC()) offshell = offshell->CC();
+ SpinorBarWaveFunction interFB = fermion2_[ix].second->
+ evaluate(q2, 3, offshell,spbOut[ohel1],vecIn[ihel2]);
+ diag = fermion2_[ix].first->
+ evaluate(q2, spIn[ihel1], interFB, scaOut);
+ }
+ else {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2,3,offshell,spIn[ihel1],spbOut[ohel1]);
+ diag = vector_[ix].second->
+ evaluate(q2, vecIn[ihel2], interV, scaOut);
+ }
+ }
+ else if( current.channelType == HPDiagram::sChannel ) {
+ // check if take intermediate massless
+ unsigned int propOpt =
+ abs(offshell->id()) != abs(spIn[ihel1].particle()->id()) ? 1 : 5;
+ SpinorWaveFunction interF = fermion1_[ix].first->
+ evaluate(q2, propOpt, offshell, spIn[ihel1], vecIn[ihel2]);
+ diag = fermion1_[ix].second->
+ evaluate(q2, interF, spbOut[ohel1], scaOut);
+ }
+ else if( current.channelType == HPDiagram::fourPoint ) {
+ diag = four_[ix]->
+ evaluate(q2, spIn[ihel1], spbOut[ohel1], vecIn[ihel2], scaOut);
+ }
+ else
+ assert(false);
+ me[ix] += norm(diag);
+ diagramME()[ix](ihel1, 2*ihel2, ohel1, 0) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](ihel1, 2*ihel2, ohel1, 0) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii)
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+ProductionMatrixElement
+MEfv2rs::fbv2rsHeME(const SpinorBarVector & spbIn, const VecWFVector & vecIn,
+ const RSSpinorVector & spOut,
+ const ScalarWaveFunction & scaOut,
+ double & me2, bool first) const {
+ const Energy2 q2(scale());
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ me2 = 0.;
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ for(unsigned int ihel1 = 0; ihel1 < 2; ++ihel1) {
+ for(unsigned int ihel2 = 0; ihel2 < 2; ++ihel2) {
+ for(unsigned int ohel1 = 0; ohel1 < 4; ++ohel1) {
+ if(massless && (ohel1==1 || ohel1==2)) continue;
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if( current.channelType == HPDiagram::tChannel ) {
+ if( offshell->iSpin() == PDT::Spin0 ) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 3, offshell, spOut[ohel1], spbIn[ihel1]);
+ diag = scalar_[ix].second->
+ evaluate(q2, vecIn[ihel2], interS, scaOut);
+ }
+ else if( offshell->iSpin() == PDT::Spin1Half ) {
+ SpinorBarWaveFunction interFB = fermion2_[ix].first->
+ evaluate(q2, 3, offshell, spbIn[ihel1], scaOut);
+ diag = fermion2_[ix].second->
+ evaluate(q2, spOut[ohel1], interFB, vecIn[ihel2]);
+ }
+ else if( offshell->iSpin() == PDT::Spin1 ) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2,3,offshell, spOut[ohel1], spbIn[ihel1]);
+ diag = vector_[ix].second->
+ evaluate(q2, vecIn[ihel2], interV, scaOut);
+ }
+ else
+ assert(false);
+ }
+ else if( current.channelType == HPDiagram::sChannel ) {
+ // check if take intermediate massless
+ unsigned int propOpt =
+ abs(offshell->id()) != abs(spbIn[ihel1].particle()->id()) ? 1 : 5;
+ SpinorBarWaveFunction interFB = fermion1_[ix].first->
+ evaluate(q2, propOpt, offshell, spbIn[ihel1], vecIn[ihel2]);
+ diag = fermion1_[ix].second->
+ evaluate(q2, spOut[ohel1], interFB, scaOut);
+ }
+ else if( current.channelType == HPDiagram::fourPoint ) {
+ diag = four_[ix]-> evaluate(q2, spOut[ohel1], spbIn[ihel1],
+ vecIn[ihel2], scaOut);
+ }
+ else
+ assert(false);
+ me[ix] += norm(diag);
+ diagramME()[ix](ihel1, 2*ihel2, ohel1, 0) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](ihel1, 2*ihel2, ohel1, 0) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii)
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+void MEfv2rs::constructVertex(tSubProPtr subp) {
+ ParticleVector external = hardParticles(subp);
+ //calculate production ME
+ VecWFVector vecIn;
+ VectorWaveFunction(vecIn, external[1], incoming, false, true);
+ ScalarWaveFunction scaOut(external[3], outgoing, true);
+ //Need to use rescale momenta to calculate matrix element
+ setRescaledMomenta(external);
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ double dummy(0.);
+ if( external[0]->id() > 0 ) {
+ SpinorVector spIn;
+ RSSpinorBarVector spbOut;
+ SpinorWaveFunction (spIn, external[0], incoming, false);
+ RSSpinorBarWaveFunction(spbOut, external[2], outgoing, true);
+
+ SpinorWaveFunction spr (rescaledMomenta()[0],
+ external[0]->dataPtr(), incoming);
+ VectorWaveFunction vr (rescaledMomenta()[1],
+ external[1]->dataPtr(), incoming);
+ RSSpinorBarWaveFunction sbr (rescaledMomenta()[2],
+ external[2]->dataPtr(), outgoing);
+ scaOut = ScalarWaveFunction(rescaledMomenta()[3],
+ external[3]->dataPtr(), outgoing);
+
+ for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
+ spr.reset(ihel);
+ spIn[ihel] = spr;
+ vr.reset(2*ihel);
+ vecIn[ihel] = vr;
+ }
+ for( unsigned int ihel = 0; ihel < 4; ++ihel ) {
+ if(massless && (ihel==1 || ihel==2)) continue;
+ sbr.reset(ihel);
+ spbOut[ihel] = sbr;
+ }
+ ProductionMatrixElement prodME = fv2rbsHeME(spIn, vecIn, spbOut,
+ scaOut, dummy,false);
+ createVertex(prodME,external);
+ }
+ else {
+ SpinorBarVector spbIn;
+ RSSpinorVector spOut;
+ SpinorBarWaveFunction(spbIn, external[0], incoming, false);
+ RSSpinorWaveFunction (spOut, external[2], outgoing, true);
+ SpinorBarWaveFunction sbr (rescaledMomenta()[0],
+ external[0]->dataPtr(), incoming);
+ VectorWaveFunction vr (rescaledMomenta()[1],
+ external[1]->dataPtr(), incoming);
+ RSSpinorWaveFunction spr (rescaledMomenta()[2],
+ external[2]->dataPtr(), outgoing);
+ scaOut = ScalarWaveFunction(rescaledMomenta()[3],
+ external[3]->dataPtr(), outgoing);
+ for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
+ sbr.reset(ihel);
+ spbIn[ihel] = sbr;
+ vr.reset(2*ihel);
+ vecIn[ihel] = vr;
+ }
+ for( unsigned int ihel = 0; ihel < 4; ++ihel ) {
+ if(massless && (ihel==1 || ihel==2)) continue;
+ spr.reset(ihel);
+ spOut[ihel] = spr;
+ }
+ ProductionMatrixElement prodME = fbv2rsHeME(spbIn, vecIn, spOut,
+ scaOut, dummy,false);
+ createVertex(prodME,external);
+ }
+}
diff --git a/MatrixElement/General/MEfv2rs.h b/MatrixElement/General/MEfv2rs.h
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEfv2rs.h
@@ -0,0 +1,204 @@
+// -*- C++ -*-
+#ifndef Herwig_MEfv2rs_H
+#define Herwig_MEfv2rs_H
+//
+// This is the declaration of the MEfv2rs class.
+//
+
+#include "GeneralHardME.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/RSSpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/RSSpinorBarWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
+#include "Herwig/MatrixElement/ProductionMatrixElement.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * This class is designed to implement the matrix element for
+ * fermion-vector to RS fermion scalar. It inherits from GeneralHardME
+ * and implements the required virtual functions.
+ *
+ * @see GeneralHardME
+ */
+class MEfv2rs: public GeneralHardME {
+
+ /** Vector of SpinorWaveFunctions. */
+ typedef vector<SpinorWaveFunction> SpinorVector;
+
+ /** Vector of SpinorBarWaveFunctions. */
+ typedef vector<SpinorBarWaveFunction> SpinorBarVector;
+
+ /** Vector of RSSpinorWaveFunctions. */
+ typedef vector<RSSpinorWaveFunction> RSSpinorVector;
+
+ /** Vector of RSSpinorBarWaveFunctions. */
+ typedef vector<RSSpinorBarWaveFunction> RSSpinorBarVector;
+
+ /** Vector of VectorWaveFunctions. */
+ typedef vector<VectorWaveFunction> VecWFVector;
+
+public:
+
+ /** @name Virtual functions required by the MEBase class. */
+ //@{
+ /**
+ * The matrix element for the kinematical configuration
+ * previously provided by the last call to setKinematics(), suitably
+ * scaled by sHat() to give a dimension-less number.
+ * @return the matrix element scaled with sHat() to give a
+ * dimensionless number.
+ */
+ virtual double me2() const;
+ //@}
+
+ /**
+ * Construct the vertex information for the spin correlations
+ * @param subp Pointer to the relevent SubProcess
+ */
+ virtual void constructVertex(tSubProPtr subp);
+
+private:
+
+ /** @name Functions to calculate production matrix elements and me2. */
+ //@{
+ /**
+ * Calculate me2 and the production matrix element for the normal mode.
+ * @param spIn Vector of SpinorWaveFunction for the incoming fermion
+ * @param vecIn Vector of VectorWaveFunction for incoming boson
+ * @param spbOut Vector of SpinorBarWaveFunction for outgoing fermion
+ * @param scaOut ScalarWaveFunction for outgoing scalar.
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @param full_me The value of me2 calculation
+ */
+ ProductionMatrixElement fv2rbsHeME(const SpinorVector & spIn,
+ const VecWFVector & vecIn,
+ const RSSpinorBarVector & spbOut,
+ const ScalarWaveFunction & scaOut,
+ double & full_me, bool first) const;
+
+ /**
+ * Calculate me2 and the production matrix element for the cc mode.
+ * @param spbIn Vector of SpinorBarWaveFunction for the incoming fermion
+ * @param vecIn Vector of VectorWaveFunction for incoming boson
+ * @param spOut Vector of SpinorWaveFunction for outgoing fermion
+ * @param scaOut ScalarWaveFunction for outgoing scalar.
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @param full_me The value of me2 calculation
+ */
+ ProductionMatrixElement fbv2rsHeME(const SpinorBarVector & spbIn,
+ const VecWFVector & vecIn,
+ const RSSpinorVector & spOut,
+ const ScalarWaveFunction & scaOut,
+ double & full_me, bool first) 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.
+ */
+ MEfv2rs & operator=(const MEfv2rs &);
+
+private:
+
+ /**
+ * Store a pair of FFSVertex and VSSVertex pointers
+ */
+ vector<pair<AbstractRFSVertexPtr, AbstractVSSVertexPtr> > scalar_;
+
+ /**
+ * Store a pair of FFSVertex and FFVVertex pointers
+ */
+ vector<pair<AbstractFFVVertexPtr, AbstractRFSVertexPtr> > fermion1_;
+
+ /**
+ * Store a pair of FFSVertex and FFVVertex pointers
+ */
+ vector<pair<AbstractFFSVertexPtr, AbstractRFVVertexPtr> > fermion2_;
+
+ /**
+ * Store a pair of VVSVertex and FFVVertex pointers
+ */
+ vector<pair<AbstractRFVVertexPtr,AbstractVVSVertexPtr> > vector_;
+
+ /**
+ * Store the 4-point vertices
+ */
+ vector<AbstractRFVSVertexPtr> four_;
+};
+
+}
+
+#endif /* Herwig_MEfv2rs_H */
diff --git a/MatrixElement/General/MEfv2rv.cc b/MatrixElement/General/MEfv2rv.cc
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEfv2rv.cc
@@ -0,0 +1,370 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the MEfv2rv class.
+//
+
+#include "MEfv2rv.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Utilities/DescribeClass.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+
+using namespace Herwig;
+using ThePEG::Helicity::incoming;
+using ThePEG::Helicity::outgoing;
+using ThePEG::Helicity::SpinorWaveFunction;
+using ThePEG::Helicity::SpinorBarWaveFunction;
+using ThePEG::Helicity::RSSpinorWaveFunction;
+using ThePEG::Helicity::RSSpinorBarWaveFunction;
+using ThePEG::Helicity::VectorWaveFunction;
+
+void MEfv2rv::doinit() {
+ GeneralHardME::doinit();
+ fermion_.resize(numberOfDiags());
+ vector_.resize(numberOfDiags());
+ four_ .resize(numberOfDiags());
+ initializeMatrixElements(PDT::Spin1Half, PDT::Spin1,
+ PDT::Spin3Half, PDT::Spin1);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ HPDiagram diagram = getProcessInfo()[ix];
+ PDT::Spin offspin = diagram.intermediate->iSpin();
+ if ( diagram.channelType == HPDiagram::fourPoint) {
+ four_[ix] = dynamic_ptr_cast<AbstractRFVVVertexPtr>(diagram.vertices.first);
+ }
+ else if(diagram.channelType == HPDiagram::sChannel ||
+ ( diagram.channelType == HPDiagram::tChannel
+ && offspin == PDT::Spin1Half)) {
+ AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
+ (diagram.vertices.first);
+ AbstractRFVVertexPtr vert2 = dynamic_ptr_cast<AbstractRFVVertexPtr>
+ (diagram.vertices.second);
+ fermion_[ix] = make_pair(vert1, vert2);
+ }
+ else {
+ if(offspin == PDT::Spin1) {
+ AbstractRFVVertexPtr vert1 = dynamic_ptr_cast<AbstractRFVVertexPtr>
+ (diagram.vertices.first);
+ AbstractVVVVertexPtr vert2 = dynamic_ptr_cast<AbstractVVVVertexPtr>
+ (diagram.vertices.second);
+ vector_[ix] = make_pair(vert1, vert2);
+ }
+ }
+ }
+}
+
+double MEfv2rv::me2() const {
+ double fullme(0.);
+ //wavefunctions for the vectors
+ VBVector vecIn(2), vecOut(3);
+ bool mc = !(mePartonData()[3]->mass() > ZERO);
+ bool massless = mePartonData()[2]->mass()!=ZERO;
+ for(unsigned int i = 0; i < 2; ++i) {
+ vecIn[i] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*i,
+ incoming);
+ vecOut[2*i] = VectorWaveFunction(rescaledMomenta()[3], mePartonData()[3], 2*i,
+ outgoing);
+ }
+ if( !mc )
+ vecOut[1] = VectorWaveFunction(rescaledMomenta()[3], mePartonData()[3], 1,
+ outgoing);
+ // spinor wavefunctions and me call
+ if(mePartonData()[0]->id() > 0) {
+ SpinorVector sp(2);
+ RSSpinorBarVector spb(4);
+ for(unsigned int i = 0; i < 2; ++i) {
+ sp[i] = SpinorWaveFunction(rescaledMomenta()[0], mePartonData()[0], i,
+ incoming);
+ }
+ for(unsigned int i = 0; i < 4; ++i) {
+ if(massless && (i==1 || i==2)) continue;
+ spb[i] = RSSpinorBarWaveFunction(rescaledMomenta()[2], mePartonData()[2], i,
+ outgoing);
+ }
+ fv2rvHeME(sp, vecIn, spb, vecOut, mc, fullme,true);
+ }
+ else {
+ RSSpinorVector sp(4);
+ SpinorBarVector spb(2);
+ for(unsigned int i = 0; i < 2; ++i) {
+ spb[i] = SpinorBarWaveFunction(rescaledMomenta()[0], mePartonData()[0], i,
+ incoming);
+ }
+ for(unsigned int i = 0; i < 4; ++i) {
+ if(massless && (i==1 || i==2)) continue;
+ sp[i] = RSSpinorWaveFunction(rescaledMomenta()[2], mePartonData()[2], i,
+ outgoing);
+ }
+ fbv2rbvHeME(spb, vecIn, sp, vecOut, mc, fullme,true);
+ }
+ return fullme;
+}
+
+IBPtr MEfv2rv::clone() const {
+ return new_ptr(*this);
+}
+
+IBPtr MEfv2rv::fullclone() const {
+ return new_ptr(*this);
+}
+
+void MEfv2rv::persistentOutput(PersistentOStream & os) const {
+ os << fermion_ << vector_ << four_;
+}
+
+void MEfv2rv::persistentInput(PersistentIStream & is, int) {
+ is >> fermion_ >> vector_ >> four_;
+ initializeMatrixElements(PDT::Spin1Half, PDT::Spin1,
+ PDT::Spin3Half, PDT::Spin1);
+}
+
+
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEfv2rv,GeneralHardME>
+ describeHerwigMEfv2rv("Herwig::MEfv2rv", "Herwig.so");
+
+void MEfv2rv::Init() {
+
+ static ClassDocumentation<MEfv2rv> documentation
+ ("The MEfv2rv class implements the general matrix element for fv -> rv");
+
+}
+
+ProductionMatrixElement
+MEfv2rv::fv2rvHeME(const SpinorVector & spIn, const VBVector & vecIn,
+ const RSSpinorBarVector & spbOut,
+ const VBVector & vecOut, bool mc,
+ double & me2, bool first) const {
+ const Energy2 q2(scale());
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ bool massless = mePartonData()[2]->mass()!=ZERO;
+ me2 = 0.;
+ //loop over helicities
+ for(unsigned int ifh = 0; ifh < 2; ++ifh) {
+ for(unsigned int ivh = 0; ivh < 2; ++ivh) {
+ for(unsigned int ofh = 0; ofh < 4; ++ofh) {
+ if(massless && (ofh==1 || ofh==2)) continue;
+ for(unsigned int ovh = 0; ovh < 3; ++ovh) {
+ if(mc && ovh == 1) ++ovh;
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if(current.channelType == HPDiagram::tChannel) {
+ //t-chan spin-1/2
+ if(offshell->iSpin() == PDT::Spin1Half) {
+ if(offshell->CC()) offshell = offshell->CC();
+ unsigned int iopt = abs(offshell->id())==abs(spIn[ifh].particle()->id()) ? 5 : 3;
+ SpinorBarWaveFunction interFB = fermion_[ix].second->
+ evaluate(q2, iopt, offshell, spbOut[ofh], vecIn[ivh]);
+ diag = fermion_[ix].first->
+ evaluate(q2, spIn[ifh], interFB, vecOut[ovh]);
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ VectorWaveFunction interV = vector_[ix].second->
+ evaluate(q2, 3, offshell, vecIn[ivh], vecOut[ovh]);
+ diag = vector_[ix].first->
+ evaluate(q2, spIn[ifh], spbOut[ofh], interV);
+ }
+ else
+ assert(false);
+ }
+ else if(current.channelType == HPDiagram::sChannel) {
+ if(offshell->CC()) offshell = offshell->CC();
+ unsigned int iopt = abs(offshell->id())==abs(spIn[ifh].particle()->id()) ? 5 : 1;
+ SpinorBarWaveFunction interFB = fermion_[ix].second->
+ evaluate(q2, iopt, offshell, spbOut[ofh], vecOut[ovh]);
+ diag = fermion_[ix].first->
+ evaluate(q2, spIn[ifh], interFB, vecIn[ivh]);
+ }
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]->evaluate(q2, spIn[ifh],spbOut[ofh],vecIn[ivh],vecOut[ovh]);
+ }
+ me[ix] += norm(diag);
+ diagramME()[ix](ifh, 2*ivh, ofh, ovh) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](ifh, 2*ivh, ovh, ofh) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii)
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+ProductionMatrixElement
+MEfv2rv::fbv2rbvHeME(const SpinorBarVector & spbIn, const VBVector & vecIn,
+ const RSSpinorVector & spOut,
+ const VBVector & vecOut, bool mc,
+ double & me2, bool first) const {
+ const Energy2 q2(scale());
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ bool massless = mePartonData()[2]->mass()!=ZERO;
+ me2 = 0.;
+ //loop over helicities
+ for(unsigned int ifh = 0; ifh < 2; ++ifh) {
+ for(unsigned int ivh = 0; ivh < 2; ++ivh) {
+ for(unsigned int ofh = 0; ofh < 4; ++ofh) {
+ if(massless && (ofh==1 || ofh==2)) continue;
+ for(unsigned int ovh = 0; ovh < 3; ++ovh) {
+ if(mc && ovh == 1) ++ovh;
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tcPDPtr offshell = current.intermediate;
+ if(current.channelType == HPDiagram::tChannel) {
+ if(offshell->iSpin() == PDT::Spin1Half) {
+ SpinorBarWaveFunction interFB = fermion_[ix].first->
+ evaluate(q2, 3, offshell, spbIn[ifh], vecOut[ovh]);
+ diag = fermion_[ix].second->
+ evaluate(q2, spOut[ofh], interFB, vecIn[ivh]);
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 3, offshell, spOut[ofh], spbIn[ifh]);
+ diag = vector_[ix].second->
+ evaluate(q2, vecIn[ivh], interV, vecOut[ovh]);
+ }
+ else
+ assert(false);
+ }
+ else if(current.channelType == HPDiagram::sChannel) {
+ if(offshell->iSpin() == PDT::Spin1Half) {
+ SpinorBarWaveFunction interFB = fermion_[ix].first->
+ evaluate(q2, 1, offshell, spbIn[ifh], vecIn[ivh]);
+ diag = fermion_[ix].second->
+ evaluate(q2, spOut[ofh], interFB, vecOut[ovh]);
+ }
+ else
+ assert(false);
+ }
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]->evaluate(q2, spOut[ofh], spbIn[ifh],vecOut[ovh],vecIn[ivh]);
+ }
+ me[ix] += norm(diag);
+ diagramME()[ix](ifh, ivh, ovh, ofh) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](ifh, ivh, ovh, ofh) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii)
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+void MEfv2rv::constructVertex(tSubProPtr sub) {
+ ParticleVector ext = hardParticles(sub);
+ VBVector v1, v3;
+ bool mc = !(ext[2]->data().mass() > ZERO);
+ bool md = !(ext[3]->data().mass() > ZERO);
+ VectorWaveFunction(v1, ext[1], incoming, false, true);
+ VectorWaveFunction(v3, ext[3], outgoing, true, md);
+ double dummy(0.);
+ // Need to use rescale momenta to calculate matrix element
+ setRescaledMomenta(ext);
+ // wavefunctions with rescaled momenta
+ // vector
+ VectorWaveFunction vir(rescaledMomenta()[1],
+ ext[1]->dataPtr(), incoming);
+ VectorWaveFunction vor(rescaledMomenta()[3],
+ ext[3]->dataPtr(), outgoing);
+ for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
+ vir.reset(2*ihel);
+ v1[ihel] = vir;
+ vor.reset(2*ihel);
+ v3[2*ihel] = vor;
+ }
+ if( !md ) {
+ vor.reset(1);
+ v3[1] = vor;
+ }
+ // matrix element and spinor wavefunctions
+ if( ext[0]->id() > 0 ) {
+ SpinorVector sp;
+ RSSpinorBarVector sbar;
+ SpinorWaveFunction (sp , ext[0], incoming, false);
+ RSSpinorBarWaveFunction(sbar, ext[2], outgoing, true);
+ SpinorWaveFunction spr (rescaledMomenta()[0],
+ ext[0]->dataPtr(), incoming);
+ RSSpinorBarWaveFunction sbr(rescaledMomenta()[2],
+ ext[2]->dataPtr(), outgoing);
+ for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
+ spr.reset(ihel);
+ sp[ihel] = spr;
+ }
+ for( unsigned int ihel = 0; ihel < 4; ++ihel ) {
+ if(mc &&(ihel==1 || ihel==2)) continue;
+ sbr.reset(ihel);
+ sbar[ihel] = sbr;
+ }
+ ProductionMatrixElement pme = fv2rvHeME(sp, v1, sbar, v3, md, dummy,false);
+ createVertex(pme,ext);
+ }
+ else {
+ RSSpinorVector sp;
+ SpinorBarVector sbar;
+ SpinorBarWaveFunction(sbar, ext[0], incoming, false);
+ RSSpinorWaveFunction(sp, ext[2], outgoing, true);
+ SpinorBarWaveFunction sbr(rescaledMomenta()[0],
+ ext[0]->dataPtr(), incoming);
+ RSSpinorWaveFunction spr (rescaledMomenta()[2],
+ ext[2]->dataPtr(), outgoing);
+ for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
+ sbr.reset(ihel);
+ sbar[ihel] = sbr;
+ }
+ for( unsigned int ihel = 0; ihel < 4; ++ihel ) {
+ if(mc &&(ihel==1 || ihel==2)) continue;
+ spr.reset(ihel);
+ sp[ihel] = spr;
+ }
+ ProductionMatrixElement pme = fbv2rbvHeME(sbar, v1, sp, v3, md, dummy,false);
+ createVertex(pme,ext);
+ }
+}
diff --git a/MatrixElement/General/MEfv2rv.h b/MatrixElement/General/MEfv2rv.h
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEfv2rv.h
@@ -0,0 +1,197 @@
+// -*- C++ -*-
+#ifndef Herwig_MEfv2rv_H
+#define Herwig_MEfv2rv_H
+//
+// This is the declaration of the MEfv2rv class.
+//
+
+#include "GeneralHardME.h"
+#include "Herwig/MatrixElement/ProductionMatrixElement.h"
+#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/RSSpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/RSSpinorBarWaveFunction.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVVVertex.h"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * This class implements the matrix element for a fermion and a vector
+ * boson to a vector boson and a RS fermion. It inherits from GeneralHardME
+ * and implements the appropriate virtual functions.
+ *
+ * @see GeneralHardME
+ *
+ */
+class MEfv2rv: public GeneralHardME {
+
+public:
+
+ /** A vector of SpinorWaveFunctions. */
+ typedef vector<Helicity::SpinorWaveFunction> SpinorVector;
+
+ /** A vector of SpinorBarWaveFunctions. */
+ typedef vector<Helicity::SpinorBarWaveFunction> SpinorBarVector;
+
+ /** A vector of SpinorWaveFunctions. */
+ typedef vector<Helicity::RSSpinorWaveFunction> RSSpinorVector;
+
+ /** A vector of SpinorBarWaveFunctions. */
+ typedef vector<Helicity::RSSpinorBarWaveFunction> RSSpinorBarVector;
+
+ /** A vector of VectorWaveFunctions. */
+ typedef vector<Helicity::VectorWaveFunction> VBVector;
+
+public:
+
+ /** @name Virtual functions required by the MEBase class. */
+ //@{
+ /**
+ * The matrix element for the kinematical configuration
+ * previously provided by the last call to setKinematics(), suitably
+ * scaled by sHat() to give a dimension-less number.
+ * @return the matrix element scaled with sHat() to give a
+ * dimensionless number.
+ */
+ virtual double me2() const;
+ //@}
+
+ /**
+ * Construct the vertex information for the spin correlations
+ * @param sub Pointer to the relevent SubProcess
+ */
+ virtual void constructVertex(tSubProPtr sub);
+
+private:
+
+ /** @name Functions to calculate the Helicity MatrixElement.*/
+ //@{
+ /**
+ * Calculate the matrix element for an incoming fermion
+ * @param spIn A vector of spinors for the incoming fermion
+ * @param vecIn A vector of VectorWaveFunctions for the incoming boson
+ * @param spbOut A vector of SpinorBarWaveFunctions for the outgoing fermion
+ * @param vecOut A vector of VectorWaveFunctions for the outgoing boson
+ * @param mc If the outgoing vector is massless or not
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @param mesq The matrix element squared
+ */
+ ProductionMatrixElement
+ fv2rvHeME(const SpinorVector & spIn, const VBVector & vecIn,
+ const RSSpinorBarVector & spbOut,
+ const VBVector & vecOut, bool mc,
+ double & mesq, bool first) const;
+
+ /**
+ * Calculate the matrix element for an incoming anti-fermion
+ * @param spbIn A vector of SpinorBarWaveFunctions for the incoming anti-fermion
+ * @param vecIn A vector of VectorWaveFunctions for the incoming boson
+ * @param spOut A vector of Spinors for the outgoing antifermion
+ * @param vecOut A vector of VectorWaveFunctions for the outgoing boson
+ * @param mc If the outgoing vector is massless or not
+ * @param first Whether or not first call to decide if colour decomposition etc
+ * should be calculated
+ * @param mesq The matrix element squared
+ */
+ ProductionMatrixElement
+ fbv2rbvHeME(const SpinorBarVector & spbIn, const VBVector & vecIn,
+ const RSSpinorVector & spOut,
+ const VBVector & vecOut, bool mc,
+ double & mesq, bool first) 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.
+ */
+ MEfv2rv & operator=(const MEfv2rv &);
+
+private:
+
+ /** @name Store dynamically casted vertices. */
+ //@{
+ /**
+ * A pair off FFVVertex pointers
+ */
+ vector<pair<AbstractFFVVertexPtr, AbstractRFVVertexPtr> > fermion_;
+
+ /**
+ * A pair of FFVVertex, VVVertex pointers
+ */
+ vector<pair<AbstractRFVVertexPtr, AbstractVVVVertexPtr> > vector_;
+
+ /**
+ * Four point vertices
+ */
+ vector<AbstractRFVVVertexPtr> four_;
+ //@}
+
+};
+
+}
+
+#endif /* Herwig_MEfv2rv_H */
diff --git a/MatrixElement/General/MEfv2vf.cc b/MatrixElement/General/MEfv2vf.cc
--- a/MatrixElement/General/MEfv2vf.cc
+++ b/MatrixElement/General/MEfv2vf.cc
@@ -1,379 +1,389 @@
// -*- C++ -*-
//
// MEfv2vf.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEfv2vf class.
//
#include "MEfv2vf.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
using ThePEG::Helicity::SpinorWaveFunction;
using ThePEG::Helicity::SpinorBarWaveFunction;
using ThePEG::Helicity::VectorWaveFunction;
void MEfv2vf::doinit() {
GeneralHardME::doinit();
fermion_.resize(numberOfDiags());
vector_.resize(numberOfDiags());
+ four_ .resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1,
PDT::Spin1, PDT::Spin1Half);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
HPDiagram diagram = getProcessInfo()[ix];
PDT::Spin offspin = diagram.intermediate->iSpin();
- if(diagram.channelType == HPDiagram::sChannel ||
+ if ( diagram.channelType == HPDiagram::fourPoint) {
+ four_[ix] = dynamic_ptr_cast<AbstractFFVVVertexPtr>(diagram.vertices.first);
+ }
+ else if(diagram.channelType == HPDiagram::sChannel ||
( diagram.channelType == HPDiagram::tChannel
&& offspin == PDT::Spin1Half)) {
AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(diagram.vertices.first);
AbstractFFVVertexPtr vert2 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(diagram.vertices.second);
fermion_[ix] = make_pair(vert1, vert2);
}
else {
if(offspin == PDT::Spin1) {
AbstractFFVVertexPtr vert1 = dynamic_ptr_cast<AbstractFFVVertexPtr>
(diagram.vertices.first);
AbstractVVVVertexPtr vert2 = dynamic_ptr_cast<AbstractVVVVertexPtr>
(diagram.vertices.second);
vector_[ix] = make_pair(vert1, vert2);
}
}
}
}
double MEfv2vf::me2() const {
//wavefunctions
SpinorVector sp(2);
VBVector vecIn(2), vecOut(3);
SpinorBarVector spb(2);
double fullme(0.);
bool mc = !(mePartonData()[2]->mass() > ZERO);
if(mePartonData()[0]->id() > 0) {
for(unsigned int i = 0; i < 2; ++i) {
sp[i] = SpinorWaveFunction(rescaledMomenta()[0], mePartonData()[0], i,
incoming);
vecIn[i] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*i,
- incoming);
+ incoming);
vecOut[2*i] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2], 2*i,
- outgoing);
+ outgoing);
spb[i] = SpinorBarWaveFunction(rescaledMomenta()[3], mePartonData()[3], i,
outgoing);
}
if( !mc )
vecOut[1] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2], 1,
outgoing);
fv2vfHeME(sp, vecIn, vecOut, mc, spb, fullme,true);
}
else {
for(unsigned int i = 0; i < 2; ++i) {
spb[i] = SpinorBarWaveFunction(rescaledMomenta()[0], mePartonData()[0], i,
incoming);
vecIn[i] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*i,
incoming);
vecOut[2*i] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2], 2*i,
outgoing);
sp[i] = SpinorWaveFunction(rescaledMomenta()[3], mePartonData()[3], i,
outgoing);
}
if( !mc )
vecOut[1] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2], 1,
outgoing);
fbv2vfbHeME(spb, vecIn, vecOut, mc, sp, fullme,true);
}
#ifndef NDEBUG
if( debugME() ) debug(fullme);
#endif
return fullme;
}
ProductionMatrixElement
MEfv2vf::fv2vfHeME(const SpinorVector & spIn, const VBVector & vecIn,
const VBVector & vecOut, bool mc,
const SpinorBarVector & spbOut,
double & me2, bool first) const {
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
me2 = 0.;
//loop over helicities
for(unsigned int ifh = 0; ifh < 2; ++ifh) {
for(unsigned int ivh = 0; ivh < 2; ++ivh) {
for(unsigned int ovh = 0; ovh < 3; ++ovh) {
if(mc && ovh == 1) ++ovh;
for(unsigned int ofh = 0; ofh < 2; ++ofh) {
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if(current.channelType == HPDiagram::tChannel) {
//t-chan spin-1/2
if(offshell->iSpin() == PDT::Spin1Half) {
if(offshell->CC()) offshell = offshell->CC();
unsigned int iopt = abs(offshell->id())==abs(spIn[ifh].particle()->id()) ? 5 : 3;
SpinorBarWaveFunction interFB = fermion_[ix].second->
evaluate(q2, iopt, offshell, spbOut[ofh], vecIn[ivh]);
diag = fermion_[ix].first->
evaluate(q2, spIn[ifh], interFB, vecOut[ovh]);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].second->
evaluate(q2, 3, offshell, vecIn[ivh], vecOut[ovh]);
diag = vector_[ix].first->
evaluate(q2, spIn[ifh], spbOut[ofh], interV);
}
else
diag = 0.0;
}
else if(current.channelType == HPDiagram::sChannel) {
if(offshell->CC()) offshell = offshell->CC();
unsigned int iopt = abs(offshell->id())==abs(spIn[ifh].particle()->id()) ? 5 : 1;
SpinorBarWaveFunction interFB = fermion_[ix].second->
evaluate(q2, iopt, offshell, spbOut[ofh], vecOut[ovh]);
diag = fermion_[ix].first->
evaluate(q2, spIn[ifh], interFB, vecIn[ivh]);
}
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]->evaluate(q2, spIn[ifh],spbOut[ofh],vecIn[ivh],vecOut[ovh]);
+ }
me[ix] += norm(diag);
diagramME()[ix](ifh, 2*ivh, ovh, ofh) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](ifh, 2*ivh, ovh, ofh) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
ProductionMatrixElement
MEfv2vf::fbv2vfbHeME(const SpinorBarVector & spbIn, const VBVector & vecIn,
const VBVector & vecOut, bool mc,
const SpinorVector & spOut,
double & me2, bool first) const {
const Energy2 q2(scale());
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
me2 = 0.;
//loop over helicities
for(unsigned int ifh = 0; ifh < 2; ++ifh) {
for(unsigned int ivh = 0; ivh < 2; ++ivh) {
for(unsigned int ovh = 0; ovh < 3; ++ovh) {
if(mc && ovh == 1) ++ovh;
for(unsigned int ofh = 0; ofh < 2; ++ofh) {
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if(current.channelType == HPDiagram::tChannel) {
if(offshell->iSpin() == PDT::Spin1Half) {
SpinorBarWaveFunction interFB = fermion_[ix].first->
evaluate(q2, 3, offshell, spbIn[ifh], vecOut[ovh]);
diag = fermion_[ix].second->
evaluate(q2, spOut[ofh], interFB, vecIn[ivh]);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].first->
evaluate(q2, 3, offshell, spOut[ofh], spbIn[ifh]);
diag = vector_[ix].second->
evaluate(q2, vecIn[ivh], interV, vecOut[ovh]);
}
else diag = 0.0;
}
else if(current.channelType == HPDiagram::sChannel) {
if(offshell->iSpin() == PDT::Spin1Half) {
SpinorBarWaveFunction interFB = fermion_[ix].first->
evaluate(q2, 1, offshell, spbIn[ifh], vecIn[ivh]);
diag = fermion_[ix].second->
evaluate(q2, spOut[ofh], interFB, vecOut[ovh]);
}
}
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]->evaluate(q2, spOut[ofh], spbIn[ifh],vecOut[ovh],vecIn[ivh]);
+ }
me[ix] += norm(diag);
diagramME()[ix](ifh, ivh, ovh, ofh) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](ifh, ivh, ovh, ofh) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEfv2vf::persistentOutput(PersistentOStream & os) const {
- os << fermion_ << vector_;
+ os << fermion_ << vector_ << four_;
}
void MEfv2vf::persistentInput(PersistentIStream & is, int) {
- is >> fermion_ >> vector_;
+ is >> fermion_ >> vector_ >> four_;
initializeMatrixElements(PDT::Spin1Half, PDT::Spin1,
PDT::Spin1, PDT::Spin1Half);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEfv2vf,GeneralHardME>
describeHerwigMEfv2vf("Herwig::MEfv2vf", "Herwig.so");
void MEfv2vf::Init() {
static ClassDocumentation<MEfv2vf> documentation
("This is the implementation of the matrix element for a fermion-vector boson"
"to a vector-fermion.");
}
void MEfv2vf::constructVertex(tSubProPtr sub) {
ParticleVector ext = hardParticles(sub);
VBVector v1, v3;
bool mc = !(ext[2]->data().mass() > ZERO);
SpinorVector sp;
SpinorBarVector sbar;
VectorWaveFunction(v1, ext[1], incoming, false, true);
VectorWaveFunction(v3, ext[2], outgoing, true, mc);
double dummy(0.);
//Need to use rescale momenta to calculate matrix element
setRescaledMomenta(ext);
// wavefunctions with rescaled momenta
VectorWaveFunction vir(rescaledMomenta()[1],
ext[1]->dataPtr(), incoming);
VectorWaveFunction vor(rescaledMomenta()[2],
ext[2]->dataPtr(), outgoing);
if( ext[0]->id() > 0 ) {
SpinorWaveFunction (sp , ext[0], incoming, false);
SpinorBarWaveFunction(sbar, ext[3], outgoing, true);
SpinorWaveFunction spr (rescaledMomenta()[0],
ext[0]->dataPtr(), incoming);
SpinorBarWaveFunction sbr(rescaledMomenta()[3],
ext[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
spr.reset(ihel);
sp[ihel] = spr;
vir.reset(2*ihel);
v1[ihel] = vir;
vor.reset(2*ihel);
v3[2*ihel] = vor;
sbr.reset(ihel);
sbar[ihel] = sbr;
}
if( !mc ) {
vor.reset(1);
v3[1] = vor;
}
ProductionMatrixElement pme = fv2vfHeME(sp, v1, v3, mc, sbar, dummy,false);
createVertex(pme,ext);
}
else {
SpinorBarWaveFunction(sbar, ext[0], incoming, false);
SpinorWaveFunction(sp, ext[3], outgoing, true);
SpinorBarWaveFunction sbr(rescaledMomenta()[0],
ext[0]->dataPtr(), incoming);
SpinorWaveFunction spr (rescaledMomenta()[3],
ext[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
sbr.reset(ihel);
sbar[ihel] = sbr;
vir.reset(2*ihel);
v1[ihel] = vir;
vor.reset(2*ihel);
v3[2*ihel] = vor;
spr.reset(ihel);
sp[ihel] = spr;
}
if( !mc ) {
vor.reset(1);
v3[1] = vor;
}
ProductionMatrixElement pme = fbv2vfbHeME(sbar, v1, v3, mc, sp, dummy,false);
createVertex(pme,ext);
}
#ifndef NDEBUG
if( debugME() ) debug(dummy);
#endif
}
void MEfv2vf::debug(double me2) const {
if( !generator()->logfile().is_open() ) return;
long id1 = abs(mePartonData()[0]->id());
long id4 = abs(mePartonData()[3]->id());
if( (id1 != 1 && id1 != 2) || mePartonData()[1]->id() != 21 ||
mePartonData()[2]->id() != 5100021 ||
(id4 != 5100001 && id4 != 5100002 &&
id4 != 6100001 && id4 != 6100002) ) return;
tcSMPtr sm = generator()->standardModel();
double gs4 = sqr( 4.*Constants::pi*sm->alphaS(scale()) );
Energy2 s(sHat());
Energy2 mf2 = meMomenta()[2].m2();
// Energy4 spt2 = uHat()*tHat() - sqr(mf2);
//swap t and u as formula defines process vf->vf
Energy2 t3(uHat() - mf2), u4(tHat() - mf2);
Energy4 s2(sqr(s)), t3s(sqr(t3)), u4s(sqr(u4));
double analytic = -gs4*( 5.*s2/12./t3s + s2*s/t3s/u4 + 11.*s*u4/6./t3s
+ 5.*u4s/12./t3s + u4s*u4/s/t3s)/3.;
double diff = abs(analytic - me2);
if( diff > 1e-4 ) {
generator()->log()
<< mePartonData()[0]->PDGName() << ","
<< mePartonData()[1]->PDGName() << "->"
<< mePartonData()[2]->PDGName() << ","
<< mePartonData()[3]->PDGName() << " difference: "
<< setprecision(10) << diff << " ratio: " << analytic/me2 << '\n';
}
}
diff --git a/MatrixElement/General/MEfv2vf.h b/MatrixElement/General/MEfv2vf.h
--- a/MatrixElement/General/MEfv2vf.h
+++ b/MatrixElement/General/MEfv2vf.h
@@ -1,198 +1,204 @@
// -*- C++ -*-
//
// MEfv2vf.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_MEfv2vf_H
#define HERWIG_MEfv2vf_H
//
// This is the declaration of the MEfv2vf class.
//
#include "GeneralHardME.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFVVVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* This class implements the matrix element for a fermion and a vector
* boson to a fermion and a vector boson. It inherits from GeneralHardME
* and implements the appropriate virtual functions.
+ *
+ * @see GeneralHardME
*
- * @see \ref MEfv2vfInterfaces "The interfaces"
- * defined for MEfv2vf.
*/
class MEfv2vf: public GeneralHardME {
public:
/** A vector of SpinorWaveFunctions. */
typedef vector<Helicity::SpinorWaveFunction> SpinorVector;
/** A vector of SpinorBarWaveFunctions. */
typedef vector<Helicity::SpinorBarWaveFunction> SpinorBarVector;
/** A vector of VectorWaveFunctions. */
typedef vector<Helicity::VectorWaveFunction> VBVector;
public:
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
/**
* Construct the vertex information for the spin correlations
* @param sub Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr sub);
private:
/** @name Functions to calculate the Helicity MatrixElement.*/
//@{
/**
* Calculate the matrix element for an incoming fermion
* @param spIn A vector of spinors for the incoming fermion
* @param vecIn A vector of VectorWaveFunctions for the incoming boson
* @param spbOut A vector of SpinorBarWaveFunctions for the outgoing fermion
* @param vecOut A vector of VectorWaveFunctions for the outgoing boson
* @param mc If the outgoing vector is massless or not
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @param mesq The matrix element squared
*/
ProductionMatrixElement
fv2vfHeME(const SpinorVector & spIn, const VBVector & vecIn,
const VBVector & vecOut, bool mc,
const SpinorBarVector & spbOut,
double & mesq, bool first) const;
/**
* Calculate the matrix element for an incoming anti-fermion
* @param spbIn A vector of SpinorBarWaveFunctions for the incoming anti-fermion
* @param vecIn A vector of VectorWaveFunctions for the incoming boson
* @param spOut A vector of Spinors for the outgoing antifermion
* @param vecOut A vector of VectorWaveFunctions for the outgoing boson
* @param mc If the outgoing vector is massless or not
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @param mesq The matrix element squared
*/
ProductionMatrixElement
fbv2vfbHeME(const SpinorBarVector & spbIn, const VBVector & vecIn,
const VBVector & vecOut, bool mc,
const SpinorVector & spOut,
double & mesq, bool first) const;
//@}
protected:
/**
* A debugging function to test the value of me2 against an
* analytic function.
* @param me2 The value of the \f$ |\bar{\mathcal{M}}|^2 \f$
*/
virtual void debug(double me2) 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 Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEfv2vf & operator=(const MEfv2vf &);
private:
/** @name Store dynamically casted vertices. */
//@{
/**
* A pair off FFVVertex pointers
*/
vector<pair<AbstractFFVVertexPtr, AbstractFFVVertexPtr> > fermion_;
/**
* A pair of FFVVertex, VVVertex pointers
*/
vector<pair<AbstractFFVVertexPtr, AbstractVVVVertexPtr> > vector_;
- //@}
+
+ /**
+ * Four point vertices
+ */
+ vector<AbstractFFVVVertexPtr> four_;
+ //@}
};
}
#endif /* HERWIG_MEfv2vf_H */
diff --git a/MatrixElement/General/MEvv2ff.cc b/MatrixElement/General/MEvv2ff.cc
--- a/MatrixElement/General/MEvv2ff.cc
+++ b/MatrixElement/General/MEvv2ff.cc
@@ -1,280 +1,316 @@
// -*- C++ -*-
//
// MEvv2ff.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEvv2ff class.
//
#include "MEvv2ff.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using ThePEG::Helicity::TensorWaveFunction;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
void MEvv2ff::doinit() {
GeneralHardME::doinit();
scalar_ .resize(numberOfDiags());
fermion_.resize(numberOfDiags());
vector_ .resize(numberOfDiags());
+ RSfermion_.resize(numberOfDiags());
tensor_ .resize(numberOfDiags());
+ four_ .resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1 , PDT::Spin1,
PDT::Spin1Half, PDT::Spin1Half);
for( size_t i = 0; i < numberOfDiags(); ++i ) {
HPDiagram dg = getProcessInfo()[i];
if( dg.channelType == HPDiagram::tChannel ) {
- AbstractFFVVertexPtr ffv1 =
- dynamic_ptr_cast<AbstractFFVVertexPtr>(dg.vertices.first);
- AbstractFFVVertexPtr ffv2 =
- dynamic_ptr_cast<AbstractFFVVertexPtr>(dg.vertices.second);
- fermion_[i] = make_pair(ffv1, ffv2);
+ if( dg.intermediate->iSpin() == PDT::Spin1Half ) {
+ AbstractFFVVertexPtr ffv1 =
+ dynamic_ptr_cast<AbstractFFVVertexPtr>(dg.vertices.first);
+ AbstractFFVVertexPtr ffv2 =
+ dynamic_ptr_cast<AbstractFFVVertexPtr>(dg.vertices.second);
+ fermion_[i] = make_pair(ffv1, ffv2);
+ }
+ else if( dg.intermediate->iSpin() == PDT::Spin3Half ) {
+ AbstractRFVVertexPtr rfv1 =
+ dynamic_ptr_cast<AbstractRFVVertexPtr>(dg.vertices.first);
+ AbstractRFVVertexPtr rfv2 =
+ dynamic_ptr_cast<AbstractRFVVertexPtr>(dg.vertices.second);
+ RSfermion_[i] = make_pair(rfv1, rfv2);
+ }
+ else
+ assert(false);
}
else if( dg.channelType == HPDiagram::sChannel ) {
if( dg.intermediate->iSpin() == PDT::Spin0 ) {
AbstractVVSVertexPtr vvs =
dynamic_ptr_cast<AbstractVVSVertexPtr>(dg.vertices.first );
AbstractFFSVertexPtr ffs =
dynamic_ptr_cast<AbstractFFSVertexPtr>(dg.vertices.second);
scalar_[i] = make_pair(vvs,ffs);
}
else if( dg.intermediate->iSpin() == PDT::Spin1) {
AbstractVVVVertexPtr vvv =
dynamic_ptr_cast<AbstractVVVVertexPtr>(dg.vertices.first);
AbstractFFVVertexPtr ffv =
dynamic_ptr_cast<AbstractFFVVertexPtr>(dg.vertices.second);
vector_[i] = make_pair(vvv,ffv);
}
else if(dg.intermediate->iSpin() == PDT::Spin2) {
AbstractVVTVertexPtr vvt =
dynamic_ptr_cast<AbstractVVTVertexPtr>(dg.vertices.first);
AbstractFFTVertexPtr fft =
dynamic_ptr_cast<AbstractFFTVertexPtr>(dg.vertices.second);
tensor_[i] = make_pair(vvt,fft);
}
}
+ else if ( dg.channelType == HPDiagram::fourPoint) {
+ four_[i] = dynamic_ptr_cast<AbstractFFVVVertexPtr>(dg.vertices.first);
+ }
}
}
double MEvv2ff::me2() const {
// Set up wavefuctions
VBVector v1(2), v2(2);
SpinorVector sp(2); SpinorBarVector sbar(2);
for( size_t i = 0; i < 2; ++i ) {
v1[i] = VectorWaveFunction(rescaledMomenta()[0],mePartonData()[0], 2*i,
- incoming);
+ incoming);
v2[i] = VectorWaveFunction(rescaledMomenta()[1],mePartonData()[1], 2*i,
- incoming);
+ incoming);
sbar[i] = SpinorBarWaveFunction(rescaledMomenta()[2], mePartonData()[2], i,
outgoing);
sp[i] = SpinorWaveFunction(rescaledMomenta()[3], mePartonData()[3], i,
outgoing);
}
double full_me(0.);
vv2ffME(v1, v2, sbar, sp, full_me,true);
#ifndef NDEBUG
if( debugME() ) debug(full_me);
#endif
return full_me;
}
ProductionMatrixElement
MEvv2ff::vv2ffME(const VBVector & v1, const VBVector & v2,
const SpinorBarVector & sbar,const SpinorVector & sp,
double & me2, bool first) const {
- const Energy mass = sp[0].mass();
const Energy2 q2 = scale();
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
//sum over vector helicities
for(unsigned int iv1 = 0; iv1 < 2; ++iv1) {
for(unsigned int iv2 = 0; iv2 < 2; ++iv2) {
//sum over fermion helicities
for(unsigned int of1 = 0; of1 < 2; ++of1) {
for(unsigned int of2 = 0; of2 < 2; ++of2) {
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
PDPtr offshell = current.intermediate;
- if(current.channelType == HPDiagram::tChannel &&
- offshell->iSpin() == PDT::Spin1Half) {
- if(current.ordered.second) {
- SpinorBarWaveFunction interF = fermion_[ix].first->
- evaluate(q2, 3, offshell, sbar[of1], v1[iv1], mass);
- diag = fermion_[ix].second->
- evaluate(q2, sp[of2], interF, v2[iv2]);
+ if(current.channelType == HPDiagram::tChannel) {
+ if(offshell->iSpin() == PDT::Spin1Half) {
+ if(current.ordered.second) {
+ SpinorBarWaveFunction interF = fermion_[ix].first->
+ evaluate(q2, 3, offshell, sbar[of1], v1[iv1]);
+ diag = fermion_[ix].second->
+ evaluate(q2, sp[of2], interF, v2[iv2]);
+ }
+ else {
+ SpinorWaveFunction interF = fermion_[ix].first->
+ evaluate(q2, 3, offshell, sp[of2], v1[iv1]);
+ diag = fermion_[ix].second->
+ evaluate(q2, interF, sbar[of1], v2[iv2]);
+ }
}
- else {
- SpinorWaveFunction interF = fermion_[ix].second->
- evaluate(q2, 3, offshell, sp[of2], v1[iv1], mass);
- diag = fermion_[ix].first->
- evaluate(q2, interF, sbar[of1], v2[iv2]);
+ else if (offshell->iSpin() == PDT::Spin3Half) {
+ if(current.ordered.second) {
+ RSSpinorBarWaveFunction interF = RSfermion_[ix].first->
+ evaluate(q2, 3, offshell, sbar[of1], v1[iv1]);
+ diag = RSfermion_[ix].second->
+ evaluate(q2, sp[of2], interF, v2[iv2]);
+ }
+ else {
+ RSSpinorWaveFunction interF = RSfermion_[ix].first->
+ evaluate(q2, 3, offshell, sp[of2], v1[iv1]);
+ diag = RSfermion_[ix].second->
+ evaluate(q2, interF, sbar[of1], v2[iv2]);
+ }
}
+ else
+ assert(false);
}
else if(current.channelType == HPDiagram::sChannel) {
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction interS = scalar_[ix].first->
evaluate(q2, 1, offshell, v1[iv1], v2[iv2]);
diag = scalar_[ix].second->
evaluate(q2, sp[of2], sbar[of1], interS);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].first->
evaluate(q2, 1, offshell, v1[iv1], v2[iv2]);
diag = vector_[ix].second->
evaluate(q2, sp[of2], sbar[of1], interV);
}
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction interT = tensor_[ix].first->
evaluate(q2, 1, offshell, v1[iv1], v2[iv2]);
diag = tensor_[ix].second->
evaluate(q2, sp[of2], sbar[of1], interT);
}
}
- else diag = 0.;
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]->evaluate(q2, sp[of2], sbar[of1], v1[iv1], v2[iv2]);
+ }
+ else
+ assert(false);
me[ix] += norm(diag);
diagramME()[ix](2*iv1, 2*iv2, of1, of2) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](2*iv1, 2*iv2, of1, of2) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEvv2ff::persistentOutput(PersistentOStream & os) const {
- os << scalar_ << fermion_ << vector_ << tensor_;
+ os << scalar_ << fermion_ << vector_ << RSfermion_ << tensor_ << four_;
}
void MEvv2ff::persistentInput(PersistentIStream & is, int) {
- is >> scalar_ >> fermion_ >> vector_ >> tensor_;
+ is >> scalar_ >> fermion_ >> vector_ >> RSfermion_ >> tensor_ >> four_;
initializeMatrixElements(PDT::Spin1 , PDT::Spin1,
PDT::Spin1Half, PDT::Spin1Half);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEvv2ff,GeneralHardME>
describeHerwigMEvv2ff("Herwig::MEvv2ff", "Herwig.so");
void MEvv2ff::Init() {
static ClassDocumentation<MEvv2ff> documentation
("The MEvv2ff class handles the ME calculation for the general "
"spin configuration vector-vector to fermion-antifermion\n.");
}
void MEvv2ff::constructVertex(tSubProPtr sub) {
ParticleVector ext = hardParticles(sub);
// wavefunction with real momenta
VBVector v1, v2;
VectorWaveFunction(v1, ext[0], incoming, false, true);
VectorWaveFunction(v2, ext[1], incoming, false, true);
SpinorBarVector sbar;
SpinorBarWaveFunction(sbar, ext[2], outgoing, true);
SpinorVector sp;
SpinorWaveFunction(sp, ext[3], outgoing, true);
// rescale momenta
setRescaledMomenta(ext);
// wavefuncions with rescaled momenta
VectorWaveFunction v1r(rescaledMomenta()[0],
ext[0]->dataPtr(), incoming);
VectorWaveFunction v2r(rescaledMomenta()[1],
ext[1]->dataPtr(), incoming);
SpinorBarWaveFunction sbr(rescaledMomenta()[2],
ext[2]->dataPtr(), outgoing);
SpinorWaveFunction spr(rescaledMomenta()[3],
ext[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
v1r.reset(2*ihel);
v1[ihel] = v1r;
v2r.reset(2*ihel);
v2[ihel] = v2r;
sbr.reset(ihel);
sbar[ihel] = sbr;
spr.reset(ihel);
sp[ihel] = spr;
}
double dummy(0.);
ProductionMatrixElement pme = vv2ffME(v1, v2, sbar, sp, dummy,false);
#ifndef NDEBUG
if( debugME() ) debug(dummy);
#endif
createVertex(pme,ext);
}
void MEvv2ff::debug(double me2) const {
if( !generator()->logfile().is_open() ) return;
long id3(abs(mePartonData()[2]->id())), id4(abs(mePartonData()[3]->id()));
if( mePartonData()[0]->id() != 21 || mePartonData()[1]->id() != 21 ||
id3 != id4 || (id3 != 1000021 && id3 != 5100002 && id3 != 5100001 &&
id3 != 6100002 && id3 != 6100001) )
return;
tcSMPtr sm = generator()->standardModel();
double gs4 = sqr( 4.*Constants::pi*sm->alphaS(scale()) );
int Nc = sm->Nc();
Energy2 s(sHat());
Energy2 mf2 = meMomenta()[2].m2();
Energy4 spt2 = uHat()*tHat() - sqr(mf2);
Energy2 t3(tHat() - mf2), u4(uHat() - mf2);
double analytic(0.);
if( id3 == 1000021 ) {
analytic = gs4*sqr(Nc)*u4*t3*
( sqr(u4) + sqr(t3) + 4.*mf2*s*spt2/u4/t3 ) *
( 1./sqr(s*t3) + 1./sqr(s*u4) + 1./sqr(u4*t3) )/2./(Nc*Nc - 1.);
}
else {
double brac = sqr(s)/6./t3/u4 - 3./8.;
analytic = gs4*( -4.*sqr(mf2)*brac/t3/u4 + 4.*mf2*brac/s + brac
- 1./3. + 3.*t3*u4/4/s/s);
}
double diff = abs(analytic - me2);
if( diff > 1e-4 ) {
generator()->log()
<< mePartonData()[0]->PDGName() << ","
<< mePartonData()[1]->PDGName() << "->"
<< mePartonData()[2]->PDGName() << ","
<< mePartonData()[3]->PDGName() << " difference: "
<< setprecision(10) << diff << " ratio: " << analytic/me2 << '\n';
}
}
diff --git a/MatrixElement/General/MEvv2ff.h b/MatrixElement/General/MEvv2ff.h
--- a/MatrixElement/General/MEvv2ff.h
+++ b/MatrixElement/General/MEvv2ff.h
@@ -1,187 +1,198 @@
// -*- C++ -*-
//
// MEvv2ff.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_MEvv2ff_H
#define HERWIG_MEvv2ff_H
//
// This is the declaration of the MEvv2ff class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFVVVertex.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
using ThePEG::Helicity::SpinorWaveFunction;
using ThePEG::Helicity::SpinorBarWaveFunction;
using ThePEG::Helicity::VectorWaveFunction;
/**
* This class is designed to implement the matrix element for the
* \f$2 \rightarrow 2\f$ process vector-vector to fermion-antifermion pair. It
* inherits from GeneralHardME and implements the me2() virtual function.
*
- * @see \ref MEvv2ffInterfaces "The Interfaces"
- * defined for MEvv2ff.
* @see GeneralHardME
*
*/
class MEvv2ff: public GeneralHardME {
public:
/** A Vector of VectorWaveFunction objects. */
typedef vector<VectorWaveFunction> VBVector;
/** A vector of SpinorBarWaveFunction objects. */
typedef vector<SpinorWaveFunction> SpinorVector;
/** A vector of SpinorBarWaveFunction objects. */
typedef vector<SpinorBarWaveFunction> SpinorBarVector;
public:
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
/**
* Construct the vertex information for the spin correlations
* @param sub Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr sub);
private:
/**
* Calculate the value of the matrix element
*/
ProductionMatrixElement vv2ffME(const VBVector & v1, const VBVector & v2,
const SpinorBarVector & sbar,
const SpinorVector & sp,
double & me2, bool first) const;
protected:
/**
* A debugging function to test the value of me2 against an
* analytic function.
* @param me2 The value of the \f$ |\bar{\mathcal{M}}|^2 \f$
*/
virtual void debug(double me2) 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 Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEvv2ff & operator=(const MEvv2ff &);
private:
/** @name Dynamically casted vertices. */
//@{
/**
* Intermediate scalar
*/
vector<pair<AbstractVVSVertexPtr, AbstractFFSVertexPtr > > scalar_;
+
/**
* Intermediate fermion
*/
vector<pair<AbstractFFVVertexPtr, AbstractFFVVertexPtr> > fermion_;
/**
* Intermediate vector
*/
vector<pair<AbstractVVVVertexPtr, AbstractFFVVertexPtr> > vector_;
/**
+ * Intermediate RS fermion
+ */
+ vector<pair<AbstractRFVVertexPtr, AbstractRFVVertexPtr> > RSfermion_;
+
+ /**
* Intermediate tensor
*/
vector<pair<AbstractVVTVertexPtr, AbstractFFTVertexPtr> > tensor_;
+
+ /**
+ * Four point vertices
+ */
+ vector<AbstractFFVVVertexPtr> four_;
//@}
};
}
#endif /* HERWIG_MEvv2ff_H */
diff --git a/MatrixElement/General/MEvv2rf.cc b/MatrixElement/General/MEvv2rf.cc
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEvv2rf.cc
@@ -0,0 +1,377 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the MEvv2rf class.
+//
+
+#include "MEvv2rf.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/Utilities/DescribeClass.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+
+using namespace Herwig;
+using ThePEG::Helicity::incoming;
+using ThePEG::Helicity::outgoing;
+
+IBPtr MEvv2rf::clone() const {
+ return new_ptr(*this);
+}
+
+IBPtr MEvv2rf::fullclone() const {
+ return new_ptr(*this);
+}
+
+void MEvv2rf::doinit() {
+ GeneralHardME::doinit();
+ scalar_ .resize(numberOfDiags());
+ fermion_.resize(numberOfDiags());
+ vector_ .resize(numberOfDiags());
+ four_ .resize(numberOfDiags());
+ initializeMatrixElements(PDT::Spin1 , PDT::Spin1,
+ PDT::Spin3Half, PDT::Spin1Half);
+
+ for( size_t i = 0; i < numberOfDiags(); ++i ) {
+ HPDiagram dg = getProcessInfo()[i];
+ if( dg.channelType == HPDiagram::tChannel ) {
+ AbstractRFVVertexPtr rfv;
+ AbstractFFVVertexPtr ffv;
+ if(dg.ordered.second) {
+ rfv = dynamic_ptr_cast<AbstractRFVVertexPtr>(dg.vertices.first);
+ ffv = dynamic_ptr_cast<AbstractFFVVertexPtr>(dg.vertices.second);
+ }
+ else {
+ rfv = dynamic_ptr_cast<AbstractRFVVertexPtr>(dg.vertices.second);
+ ffv = dynamic_ptr_cast<AbstractFFVVertexPtr>(dg.vertices.first );
+ }
+ fermion_[i] = make_pair(rfv, ffv);
+ }
+ else if( dg.channelType == HPDiagram::sChannel ) {
+ if( dg.intermediate->iSpin() == PDT::Spin0 ) {
+ AbstractVVSVertexPtr vvs =
+ dynamic_ptr_cast<AbstractVVSVertexPtr>(dg.vertices.first );
+ AbstractRFSVertexPtr rfs =
+ dynamic_ptr_cast<AbstractRFSVertexPtr>(dg.vertices.second);
+ scalar_[i] = make_pair(vvs,rfs);
+ }
+ else if( dg.intermediate->iSpin() == PDT::Spin1) {
+ AbstractVVVVertexPtr vvv =
+ dynamic_ptr_cast<AbstractVVVVertexPtr>(dg.vertices.first);
+ AbstractRFVVertexPtr rfv =
+ dynamic_ptr_cast<AbstractRFVVertexPtr>(dg.vertices.second);
+ vector_[i] = make_pair(vvv,rfv);
+ }
+ }
+ else if ( dg.channelType == HPDiagram::fourPoint) {
+ four_[i] = dynamic_ptr_cast<AbstractRFVVVertexPtr>(dg.vertices.first);
+ }
+ }
+}
+
+void MEvv2rf::persistentOutput(PersistentOStream & os) const {
+ os << scalar_ << fermion_ << vector_ << four_;
+}
+
+void MEvv2rf::persistentInput(PersistentIStream & is, int) {
+ is >> scalar_ >> fermion_ >> vector_ >> four_;
+ initializeMatrixElements(PDT::Spin1 , PDT::Spin1,
+ PDT::Spin3Half, PDT::Spin1Half);
+}
+
+//The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<MEvv2rf,GeneralHardME>
+describeHerwigMEvv2rf("Herwig::MEvv2rf", "Herwig.so");
+
+void MEvv2rf::Init() {
+
+ static ClassDocumentation<MEvv2rf> documentation
+ ("The MEvv2rf class handes the ME calculation for vv -> rf");
+
+}
+
+double MEvv2rf::me2() const {
+ // set up the vector wavefunctions
+ VBVector v1(2), v2(2);
+ for( size_t i = 0; i < 2; ++i ) {
+ v1[i] = VectorWaveFunction(rescaledMomenta()[0],mePartonData()[0], 2*i,
+ incoming);
+ v2[i] = VectorWaveFunction(rescaledMomenta()[1],mePartonData()[1], 2*i,
+ incoming);
+ }
+ // setup spinor wavefunctions and decide which case to use
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ double full_me(0.);
+ if(mePartonData()[2]->id()<0) {
+ RSSpinorVector sp(4); SpinorBarVector sbar(2);
+ for( size_t i = 0; i < 4; ++i ) {
+ if(massless && (i==2||i==3)) continue;
+ sp[i] = RSSpinorWaveFunction(rescaledMomenta()[2], mePartonData()[2], i,
+ outgoing);
+ }
+ for( size_t i = 0; i < 2; ++i ) {
+ sbar[i] = SpinorBarWaveFunction(rescaledMomenta()[3], mePartonData()[3], i,
+ outgoing);
+ }
+ vv2frME(v1, v2, sbar, sp, full_me,true);
+ }
+ else {
+ SpinorVector sp(2); RSSpinorBarVector sbar(4);
+ for( size_t i = 0; i < 4; ++i ) {
+ if(massless && (i==2||i==3)) continue;
+ sbar[i] = RSSpinorBarWaveFunction(rescaledMomenta()[2], mePartonData()[2], i,
+ outgoing);
+ }
+ for( size_t i = 0; i < 2; ++i ) {
+ sp[i] = SpinorWaveFunction(rescaledMomenta()[3], mePartonData()[3], i,
+ outgoing);
+ }
+ vv2rfME(v1, v2, sbar, sp, full_me,true);
+ }
+ return full_me;
+}
+
+ProductionMatrixElement
+MEvv2rf::vv2rfME(const VBVector & v1, const VBVector & v2,
+ const RSSpinorBarVector & sbar,const SpinorVector & sp,
+ double & me2, bool first) const {
+ // scale
+ const Energy2 q2 = scale();
+ // whether or not rs fermion is massless
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ //sum over vector helicities
+ for(unsigned int iv1 = 0; iv1 < 2; ++iv1) {
+ for(unsigned int iv2 = 0; iv2 < 2; ++iv2) {
+ //sum over fermion helicities
+ for(unsigned int of1 = 0; of1 < 4; ++of1) {
+ if(massless && (of1==1 || of1==2) ) continue;
+ for(unsigned int of2 = 0; of2 < 2; ++of2) {
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tPDPtr offshell = current.intermediate;
+ if(current.channelType == HPDiagram::tChannel &&
+ offshell->iSpin() == PDT::Spin1Half) {
+ if(current.ordered.second) {
+ SpinorBarWaveFunction interF = fermion_[ix].first->
+ evaluate(q2, 3, offshell, sbar[of1], v1[iv1]);
+ diag = fermion_[ix].second->
+ evaluate(q2, sp[of2], interF, v2[iv2]);
+ }
+ else {
+ SpinorWaveFunction interF = fermion_[ix].second->
+ evaluate(q2, 3, offshell, sp[of2], v1[iv1]);
+ diag = fermion_[ix].first->
+ evaluate(q2, interF, sbar[of1], v2[iv2]);
+ }
+ }
+ else if(current.channelType == HPDiagram::sChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 1, offshell, v1[iv1], v2[iv2]);
+ diag = scalar_[ix].second->
+ evaluate(q2, sp[of2], sbar[of1], interS);
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 1, offshell, v1[iv1], v2[iv2]);
+ diag = vector_[ix].second->
+ evaluate(q2, sp[of2], sbar[of1], interV);
+ }
+ }
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]->evaluate(q2, sp[of2], sbar[of1], v1[iv1], v2[iv2]);
+ }
+ else
+ assert(false);
+ me[ix] += norm(diag);
+ diagramME()[ix](2*iv1, 2*iv2, of1, of2) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](2*iv1, 2*iv2, of1, of2) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii)
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+ProductionMatrixElement
+MEvv2rf::vv2frME(const VBVector & v1, const VBVector & v2,
+ const SpinorBarVector & sbar,const RSSpinorVector & sp,
+ double & me2, bool first) const {
+ // scale
+ const Energy2 q2 = scale();
+ // whether or not rs fermion is massless
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ // weights for the selection of the diagram
+ vector<double> me(numberOfDiags(), 0.);
+ // weights for the selection of the colour flow
+ vector<double> flow(numberOfFlows(),0.);
+ //sum over vector helicities
+ for(unsigned int iv1 = 0; iv1 < 2; ++iv1) {
+ for(unsigned int iv2 = 0; iv2 < 2; ++iv2) {
+ //sum over fermion helicities
+ for(unsigned int of1 = 0; of1 < 4; ++of1) {
+ for(unsigned int of2 = 0; of2 < 2; ++of2) {
+ if(massless && (of2==1 || of2==2) ) continue;
+ vector<Complex> flows(numberOfFlows(),0.);
+ for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
+ Complex diag(0.);
+ const HPDiagram & current = getProcessInfo()[ix];
+ tPDPtr offshell = current.intermediate;
+ if(current.channelType == HPDiagram::tChannel &&
+ offshell->iSpin() == PDT::Spin1Half) {
+ if(current.ordered.second) {
+ SpinorWaveFunction interF = fermion_[ix].first->
+ evaluate(q2, 3, offshell, sp[of2], v1[iv1]);
+ diag = fermion_[ix].second->
+ evaluate(q2, interF, sbar[of1],v2[iv2]);
+ }
+ else {
+ SpinorBarWaveFunction interF = fermion_[ix].second->
+ evaluate(q2, 3, offshell, sbar[of1], v1[iv1]);
+ diag = fermion_[ix].first->
+ evaluate(q2, sp[of2], interF, v2[iv2]);
+ }
+ }
+ else if(current.channelType == HPDiagram::sChannel) {
+ if(offshell->iSpin() == PDT::Spin0) {
+ ScalarWaveFunction interS = scalar_[ix].first->
+ evaluate(q2, 1, offshell, v1[iv1], v2[iv2]);
+ diag = scalar_[ix].second->
+ evaluate(q2, sp[of2], sbar[of1], interS);
+ }
+ else if(offshell->iSpin() == PDT::Spin1) {
+ VectorWaveFunction interV = vector_[ix].first->
+ evaluate(q2, 1, offshell, v1[iv1], v2[iv2]);
+ diag = vector_[ix].second->
+ evaluate(q2, sp[of2], sbar[of1], interV);
+ }
+ }
+ else if(current.channelType == HPDiagram::fourPoint) {
+ diag = four_[ix]->evaluate(q2, sp[of2], sbar[of1], v1[iv1], v2[iv2]);
+ }
+ else
+ assert(false);
+ me[ix] += norm(diag);
+ diagramME()[ix](2*iv1, 2*iv2, of2, of1) = diag;
+ //Compute flows
+ for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
+ assert(current.colourFlow[iy].first<flows.size());
+ flows[current.colourFlow[iy].first] +=
+ current.colourFlow[iy].second * diag;
+ }
+ }
+ // MEs for the different colour flows
+ for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
+ flowME()[iy](2*iv1, 2*iv2, of1, of2) = flows[iy];
+ //Now add flows to me2 with appropriate colour factors
+ for(size_t ii = 0; ii < numberOfFlows(); ++ii)
+ for(size_t ij = 0; ij < numberOfFlows(); ++ij)
+ me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
+ // contribution to the colour flow
+ for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
+ flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
+ }
+ }
+ }
+ }
+ }
+ // if not computing the cross section return the selected colour flow
+ if(!first) return flowME()[colourFlow()];
+ me2 = selectColourFlow(flow,me,me2);
+ return flowME()[colourFlow()];
+}
+
+void MEvv2rf::constructVertex(tSubProPtr sub) {
+ ParticleVector ext = hardParticles(sub);
+ // vector wavefunctions are common do them first
+ // wavefunction with real momenta
+ VBVector v1, v2;
+ VectorWaveFunction(v1, ext[0], incoming, false, true);
+ VectorWaveFunction(v2, ext[1], incoming, false, true);
+ // rescale momenta
+ setRescaledMomenta(ext);
+ // wavefunctions with rescaled momenta
+ VectorWaveFunction v1r(rescaledMomenta()[0],
+ ext[0]->dataPtr(), incoming);
+ VectorWaveFunction v2r(rescaledMomenta()[1],
+ ext[1]->dataPtr(), incoming);
+ ProductionMatrixElement pme;
+ for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
+ v1r.reset(2*ihel);
+ v1[ihel] = v1r;
+ v2r.reset(2*ihel);
+ v2[ihel] = v2r;
+ }
+ // setup spinor wavefunctions and decide which case to use
+ bool massless = mePartonData()[2]->mass()==ZERO;
+ double dummy(0.);
+ if(ext[2]->id()<0) {
+ RSSpinorVector sp;
+ RSSpinorWaveFunction(sp, ext[2], outgoing, true);
+ SpinorBarVector sbar;
+ SpinorBarWaveFunction(sbar, ext[3], outgoing, true);
+ // wavefuncions with rescaled momenta
+ SpinorBarWaveFunction sbr(rescaledMomenta()[3],
+ ext[3]->dataPtr(), outgoing);
+ RSSpinorWaveFunction spr(rescaledMomenta()[2],
+ ext[2]->dataPtr(), outgoing);
+ for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
+ sbr.reset(ihel);
+ sbar[ihel] = sbr;
+ }
+ for( unsigned int ihel = 0; ihel < 4; ++ihel ) {
+ if(massless && (ihel==1 || ihel==2)) continue;
+ spr.reset(ihel);
+ sp[ihel] = spr;
+ }
+ pme = vv2frME(v1, v2, sbar, sp, dummy,false);
+ }
+ else {
+ SpinorVector sp;
+ SpinorWaveFunction(sp, ext[3], outgoing, true);
+ RSSpinorBarVector sbar;
+ RSSpinorBarWaveFunction(sbar, ext[2], outgoing, true);
+ // wavefuncions with rescaled momenta
+ RSSpinorBarWaveFunction sbr(rescaledMomenta()[2],
+ ext[2]->dataPtr(), outgoing);
+ SpinorWaveFunction spr(rescaledMomenta()[3],
+ ext[3]->dataPtr(), outgoing);
+ for( unsigned int ihel = 0; ihel < 4; ++ihel ) {
+ if(massless && (ihel==1 || ihel==2)) continue;
+ sbr.reset(ihel);
+ sbar[ihel] = sbr;
+ }
+ for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
+ spr.reset(ihel);
+ sp[ihel] = spr;
+ }
+ pme = vv2rfME(v1, v2, sbar, sp, dummy,false);
+ }
+ createVertex(pme,ext);
+}
diff --git a/MatrixElement/General/MEvv2rf.h b/MatrixElement/General/MEvv2rf.h
new file mode 100644
--- /dev/null
+++ b/MatrixElement/General/MEvv2rf.h
@@ -0,0 +1,182 @@
+// -*- C++ -*-
+#ifndef Herwig_MEvv2rf_H
+#define Herwig_MEvv2rf_H
+//
+// This is the declaration of the MEvv2rf class.
+//
+
+#include "GeneralHardME.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
+#include "ThePEG/Helicity/Vertex/AbstractRFVVVertex.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/RSSpinorWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/RSSpinorBarWaveFunction.h"
+#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
+#include "Herwig/MatrixElement/ProductionMatrixElement.h"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * This class is designed to implement the matrix element for the
+ * \f$2 \rightarrow 2\f$ process vector-vector to fermion- RS fermion. It
+ * inherits from GeneralHardME and implements the me2() virtual function.
+ *
+ * @see GeneralHardME
+ *
+ */
+class MEvv2rf: public GeneralHardME {
+
+public:
+
+ /** A Vector of VectorWaveFunction objects. */
+ typedef vector<VectorWaveFunction> VBVector;
+
+ /** A vector of SpinorBarWaveFunction objects. */
+ typedef vector<SpinorWaveFunction> SpinorVector;
+
+ /** A vector of SpinorBarWaveFunction objects. */
+ typedef vector<SpinorBarWaveFunction> SpinorBarVector;
+
+ /** A vector of SpinorBarWaveFunction objects. */
+ typedef vector<RSSpinorWaveFunction> RSSpinorVector;
+
+ /** A vector of SpinorBarWaveFunction objects. */
+ typedef vector<RSSpinorBarWaveFunction> RSSpinorBarVector;
+
+public:
+
+ /** @name Virtual functions required by the MEBase class. */
+ //@{
+ /**
+ * The matrix element for the kinematical configuration
+ * previously provided by the last call to setKinematics(), suitably
+ * scaled by sHat() to give a dimension-less number.
+ * @return the matrix element scaled with sHat() to give a
+ * dimensionless number.
+ */
+ virtual double me2() const;
+ //@}
+
+ /**
+ * Construct the vertex information for the spin correlations
+ * @param sub Pointer to the relevent SubProcess
+ */
+ virtual void constructVertex(tSubProPtr sub);
+
+public:
+
+ /** @name Functions used by the persistent I/O system. */
+ //@{
+ /**
+ * Function used to write out object persistently.
+ * @param os the persistent output stream written to.
+ */
+ void persistentOutput(PersistentOStream & os) const;
+
+ /**
+ * Function used to read in object persistently.
+ * @param is the persistent input stream read from.
+ * @param version the version number of the object when written.
+ */
+ void persistentInput(PersistentIStream & is, int version);
+ //@}
+
+ /**
+ * The standard Init function used to initialize the interfaces.
+ * Called exactly once for each class by the class description system
+ * before the main function starts or
+ * when this class is dynamically loaded.
+ */
+ static void Init();
+
+protected:
+
+ /** @name Clone Methods. */
+ //@{
+ /**
+ * Make a simple clone of this object.
+ * @return a pointer to the new object.
+ */
+ 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:
+
+ /**
+ * Calculate the value of the matrix element
+ */
+ ProductionMatrixElement vv2rfME(const VBVector & v1, const VBVector & v2,
+ const RSSpinorBarVector & sbar,
+ const SpinorVector & sp,
+ double & me2, bool first) const;
+
+ /**
+ * Calculate the value of the matrix element
+ */
+ ProductionMatrixElement vv2frME(const VBVector & v1, const VBVector & v2,
+ const SpinorBarVector & sbar,
+ const RSSpinorVector & sp,
+ double & me2, bool first) const;
+
+private:
+
+ /**
+ * The assignment operator is private and must never be called.
+ * In fact, it should not even be implemented.
+ */
+ MEvv2rf & operator=(const MEvv2rf &);
+private:
+
+ /** @name Dynamically casted vertices. */
+ //@{
+ /**
+ * Intermediate scalar
+ */
+ vector<pair<AbstractVVSVertexPtr, AbstractRFSVertexPtr > > scalar_;
+
+ /**
+ * Intermediate fermion
+ */
+ vector<pair<AbstractRFVVertexPtr, AbstractFFVVertexPtr> > fermion_;
+
+ /**
+ * Intermediate vector
+ */
+ vector<pair<AbstractVVVVertexPtr, AbstractRFVVertexPtr> > vector_;
+
+ /**
+ * Four point vertices
+ */
+ vector<AbstractRFVVVertexPtr> four_;
+ //@}
+
+};
+
+}
+
+#endif /* Herwig_MEvv2rf_H */
diff --git a/MatrixElement/General/MEvv2ss.cc b/MatrixElement/General/MEvv2ss.cc
--- a/MatrixElement/General/MEvv2ss.cc
+++ b/MatrixElement/General/MEvv2ss.cc
@@ -1,312 +1,313 @@
// -*- C++ -*-
//
// MEvv2ss.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEvv2ss class.
//
#include "MEvv2ss.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using ThePEG::Helicity::TensorWaveFunction;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
void MEvv2ss::doinit() {
GeneralHardME::doinit();
scalar1_.resize(numberOfDiags());
scalar2_.resize(numberOfDiags());
scalar3_.resize(numberOfDiags());
vector_ .resize(numberOfDiags());
tensor_ .resize(numberOfDiags());
+ contact_.resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1, PDT::Spin1,
PDT::Spin0, PDT::Spin0);
for(size_t i = 0; i < numberOfDiags(); ++i ) {
HPDiagram dg = getProcessInfo()[i];
if( !dg.intermediate ) {
- contact_ = dynamic_ptr_cast<AbstractVVSSVertexPtr>(dg.vertices.first);
+ contact_[i] = dynamic_ptr_cast<AbstractVVSSVertexPtr>(dg.vertices.first);
}
else if(dg.channelType == HPDiagram::tChannel) {
if (dg.intermediate->iSpin() == PDT::Spin0 ) {
AbstractVSSVertexPtr vss1 =
dynamic_ptr_cast<AbstractVSSVertexPtr>(dg.vertices.first);
AbstractVSSVertexPtr vss2 =
dynamic_ptr_cast<AbstractVSSVertexPtr>(dg.vertices.second);
scalar2_[i] = make_pair(vss1, vss2);
}
else if( dg.intermediate->iSpin() == PDT::Spin1 ) {
AbstractVVSVertexPtr vvs1 =
dynamic_ptr_cast<AbstractVVSVertexPtr>(dg.vertices.first);
AbstractVVSVertexPtr vvs2 =
dynamic_ptr_cast<AbstractVVSVertexPtr>(dg.vertices.second);
scalar3_[i] = make_pair(vvs1, vvs2);
}
else
assert(false);
}
else {
if( dg.intermediate->iSpin() == PDT::Spin0 ) {
AbstractVVSVertexPtr vvs =
dynamic_ptr_cast<AbstractVVSVertexPtr>(dg.vertices.first);
AbstractSSSVertexPtr sss =
dynamic_ptr_cast<AbstractSSSVertexPtr>(dg.vertices.second);
scalar1_[i] = make_pair(vvs, sss);
}
else if( dg.intermediate->iSpin() == PDT::Spin1 ) {
AbstractVVVVertexPtr vvv =
dynamic_ptr_cast<AbstractVVVVertexPtr>(dg.vertices.first);
AbstractVSSVertexPtr vss =
dynamic_ptr_cast<AbstractVSSVertexPtr>(dg.vertices.second);
vector_[i] = make_pair(vvv, vss);
}
else if( dg.intermediate->iSpin() == PDT::Spin2 ) {
AbstractVVTVertexPtr vvt =
dynamic_ptr_cast<AbstractVVTVertexPtr>(dg.vertices.first);
AbstractSSTVertexPtr sst =
dynamic_ptr_cast<AbstractSSTVertexPtr>(dg.vertices.second);
tensor_[i] = make_pair(vvt, sst);
}
}
}
}
double MEvv2ss::me2() const {
VBVector v1(2), v2(2);
for( size_t i = 0; i < 2; ++i ) {
v1[i] = VectorWaveFunction(rescaledMomenta()[0],mePartonData()[0], 2*i,
incoming);
v2[i] = VectorWaveFunction(rescaledMomenta()[1],mePartonData()[1], 2*i,
incoming);
}
ScalarWaveFunction sca1(rescaledMomenta()[2],mePartonData()[2],
Complex(1.,0.),outgoing);
ScalarWaveFunction sca2(rescaledMomenta()[3],mePartonData()[3],
Complex(1.,0.),outgoing);
double full_me(0.);
vv2ssME(v1, v2, sca1, sca2, full_me , true);
#ifndef NDEBUG
if( debugME() ) debug(full_me);
#endif
return full_me;
}
ProductionMatrixElement
MEvv2ss::vv2ssME(const VBVector & v1, const VBVector & v2,
const ScalarWaveFunction & sca1,
const ScalarWaveFunction & sca2,
double & me2, bool first) const {
const Energy2 m2(scale());
const Energy masst = sca1.mass(), massu = sca2.mass();
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
//loop over vector helicities
for(unsigned int iv1 = 0; iv1 < 2; ++iv1) {
for(unsigned int iv2 = 0; iv2 < 2; ++iv2) {
vector<Complex> flows(numberOfFlows(),0.);
// loop over diagrams
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
// do four-point diag first
if(current.channelType == HPDiagram::fourPoint) {
- diag = contact_->evaluate(m2, v1[iv1], v2[iv2], sca1, sca2);
+ diag = contact_[ix]->evaluate(m2, v1[iv1], v2[iv2], sca1, sca2);
}
else {
tcPDPtr offshell = current.intermediate;
if(current.channelType == HPDiagram::tChannel) {
if(offshell->iSpin() == PDT::Spin0) {
if(current.ordered.second) {
ScalarWaveFunction interS = scalar2_[ix].first->
evaluate(m2, 3, offshell, v1[iv1], sca1, masst);
diag = scalar2_[ix].second->evaluate(m2, v2[iv2], interS, sca2);
}
else {
ScalarWaveFunction interS = scalar2_[ix].first->
evaluate(m2, 3, offshell, v1[iv1], sca2, massu);
diag = scalar2_[ix].second->evaluate(m2, v2[iv2], interS, sca1);
}
}
else {
if(current.ordered.second) {
VectorWaveFunction interV = scalar3_[ix].first->
evaluate(m2, 3, offshell, v1[iv1], sca1);
diag = scalar3_[ix].second->evaluate(m2, v2[iv2], interV, sca2);
}
else {
VectorWaveFunction interV = scalar3_[ix].first->
evaluate(m2, 3, offshell, v1[iv1], sca2);
diag = scalar3_[ix].second->evaluate(m2, v2[iv2], interV, sca1);
}
}
}
else if(current.channelType == HPDiagram::sChannel) {
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction interS = scalar1_[ix].first->
evaluate(m2, 1, offshell, v1[iv1], v2[iv2]);
diag = scalar1_[ix].second->evaluate(m2, interS, sca1, sca2);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].first->
evaluate(m2, 1, offshell, v1[iv1], v2[iv2]);
diag = vector_[ix].second->evaluate(m2, interV, sca1, sca2);
}
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction interT = tensor_[ix].first->
evaluate(m2, 1, offshell, v1[iv1], v2[iv2]);
diag = tensor_[ix].second->evaluate(m2, sca1, sca2, interT);
}
}
else
diag = 0.;
}
me[ix] += norm(diag);
diagramME()[ix](2*iv1, 2*iv2, 0, 0) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](2*iv1, 2*iv2, 0, 0) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEvv2ss::persistentOutput(PersistentOStream & os) const {
os << scalar1_ << scalar2_ << scalar3_ << vector_ << tensor_ << contact_;
}
void MEvv2ss::persistentInput(PersistentIStream & is, int) {
is >> scalar1_ >> scalar2_ >> scalar3_ >> vector_ >> tensor_ >> contact_;
initializeMatrixElements(PDT::Spin1, PDT::Spin1,
PDT::Spin0, PDT::Spin0);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEvv2ss,GeneralHardME>
describeHerwigMEvv2ss("Herwig::MEvv2ss", "Herwig.so");
void MEvv2ss::Init() {
static ClassDocumentation<MEvv2ss> documentation
("This class implements the ME for the vector-vector to scalar-scalar "
"hard-process");
}
void MEvv2ss::constructVertex(tSubProPtr sub) {
ParticleVector ext = hardParticles(sub);
VBVector v1, v2;
// set up the wavefunctions with real momenta
VectorWaveFunction(v1, ext[0], incoming, false, true);
VectorWaveFunction(v2, ext[1], incoming, false, true);
ScalarWaveFunction sca1(ext[2], outgoing, true);
ScalarWaveFunction sca2(ext[3], outgoing, true);
// calculate rescaled moment
setRescaledMomenta(ext);
// wavefunctions with rescaled momenta
VectorWaveFunction v1r (rescaledMomenta()[0],
ext[0]->dataPtr(), incoming);
VectorWaveFunction v2r (rescaledMomenta()[1],
ext[1]->dataPtr(), incoming);
sca1 = ScalarWaveFunction(rescaledMomenta()[2],
ext[2]->dataPtr(), outgoing);
sca2 = ScalarWaveFunction(rescaledMomenta()[3],
ext[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
v1r.reset(2*ihel);
v1[ihel] = v1r;
v2r.reset(2*ihel);
v2[ihel] = v2r;
}
double dummy(0.);
ProductionMatrixElement pme = vv2ssME(v1, v2, sca1, sca2, dummy , false);
#ifndef NDEBUG
if( debugME() ) debug(dummy);
#endif
createVertex(pme,ext);
}
void MEvv2ss::debug(double me2) const {
if( !generator()->logfile().is_open() ) return;
if( mePartonData()[0]->id() != 21 || mePartonData()[1]->id() != 21) return;
long id3 = abs(mePartonData()[2]->id());
long id4 = abs(mePartonData()[3]->id());
int type = -1;
//SUSY gg>~q~q
if( ((id3 >= 1000001 && id3 <= 1000006 ) && (id4 >= 1000001 && id4 <= 1000006 ) ) ||
((id3 >= 2000001 && id3 <= 2000006 ) && (id4 >= 2000001 && id4 <= 2000006 ) ) ) {
type = 0;
}
// Sextet production
else if(mePartonData()[2]->iColour() == PDT::Colour6 &&
mePartonData()[3]->iColour() == PDT::Colour6bar ) {
type = 1;
}
else {
return;
}
double gs4 = sqr( 4.*Constants::pi*SM().alphaS(scale()));
int Nc = SM().Nc();
Energy4 s2 = sqr(sHat());
Energy2 m3s = meMomenta()[2].m2();
Energy2 m4s = meMomenta()[3].m2();
Energy4 spt2 = uHat()*tHat() - m3s*m4s;
Energy2 t3 = tHat()-m3s, u4 = uHat()-m4s;
Energy4 t3s = sqr(t3) , u4s = sqr(u4);
Energy8 pre = gs4*(sqr(spt2) + s2*m3s*m4s);
// matrix element
double analytic(0.);
// triplet scalars
if(type==0) {
analytic = pre*Nc*
( u4s + t3s - s2/sqr(Nc) )/2./(sqr(Nc) - 1.)/s2/t3s/u4s;
}
// sextet scalars
else if(type==1) {
analytic = pre*(Nc+2.)/(sqr(Nc)-1.)/Nc*
((Nc+2.)*(Nc-1.)/t3s/u4s - sqr(Nc)/t3/u4/s2);
}
double diff = abs(analytic - me2)/(analytic+me2);
if( diff > 1e-10 ) {
generator()->log()
<< mePartonData()[0]->PDGName() << ","
<< mePartonData()[1]->PDGName() << "->"
<< mePartonData()[2]->PDGName() << ","
<< mePartonData()[3]->PDGName() << " difference: "
<< setprecision(10) << diff << " ratio: " << analytic/me2 << '\n';
}
}
diff --git a/MatrixElement/General/MEvv2ss.h b/MatrixElement/General/MEvv2ss.h
--- a/MatrixElement/General/MEvv2ss.h
+++ b/MatrixElement/General/MEvv2ss.h
@@ -1,199 +1,199 @@
// -*- C++ -*-
//
// MEvv2ss.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_MEvv2ss_H
#define HERWIG_MEvv2ss_H
//
// This is the declaration of the MEvv2ss class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractSSTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractSSSVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
using ThePEG::Helicity::VectorWaveFunction;
using ThePEG::Helicity::ScalarWaveFunction;
/**
* This is the implementation of the matrix element for the process
* vector-vector to scalar-scalar. It inherits from GeneralHardME and
* implements the required virtual functions.
*
* @see \ref MEff2ffInterfaces "The Interfaces"
* defined for MEff2ff.
* @see GeneralHardME
*/
class MEvv2ss: public GeneralHardME {
public:
/** A vector of VectorWaveFunction objects*/
typedef vector<VectorWaveFunction> VBVector;
public:
/** @name Virtual functions required by the MEBase class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
/**
* Set the Hardvertex for the spin correlations
* @param sub
*/
virtual void constructVertex(tSubProPtr sub);
private:
/**
* Calculate the matrix element.
* @param v1 A vector of VectorWaveFunction objects for the first boson
* @param v2 A vector of VectorWaveFunction objects for the second boson
* @param sca1 A ScalarWaveFunction for the first outgoing
* @param sca2 A ScalarWaveFunction for the second outgoing
* @param me2 The value of the spin-summed matrix element squared
* (to be calculated)
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
*/
ProductionMatrixElement vv2ssME(const VBVector & v1, const VBVector & v2,
const ScalarWaveFunction & sca1,
const ScalarWaveFunction & sca2,
double & me2, bool first) const;
protected:
/**
* A debugging function to test the value of me2 against an
* analytic function.
* @param me2 The value of the \f$ |\bar{\mathcal{M}}|^2 \f$
*/
virtual void debug(double me2) 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 Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEvv2ss & operator=(const MEvv2ss &);
private:
/** @name The dynamically casted vertices. */
//@{
/**
* Intermediate s-channel scalar
*/
vector<pair<AbstractVVSVertexPtr, AbstractSSSVertexPtr> > scalar1_;
/**
* Intermediate t-channel scalar
*/
vector<pair<AbstractVSSVertexPtr, AbstractVSSVertexPtr> > scalar2_;
/**
* Intermediate t-channel scalar
*/
vector<pair<AbstractVVSVertexPtr, AbstractVVSVertexPtr> > scalar3_;
/**
* Intermediate s-channel vector
*/
vector<pair<AbstractVVVVertexPtr, AbstractVSSVertexPtr> > vector_;
/**
* Intermediate s-channel tensor
*/
vector<pair<AbstractVVTVertexPtr, AbstractSSTVertexPtr> > tensor_;
/**
* The contact vertex
*/
- AbstractVVSSVertexPtr contact_;
+ vector<AbstractVVSSVertexPtr> contact_;
//@}
};
}
#endif /* HERWIG_MEvv2ss_H */
diff --git a/MatrixElement/General/MEvv2vs.cc b/MatrixElement/General/MEvv2vs.cc
--- a/MatrixElement/General/MEvv2vs.cc
+++ b/MatrixElement/General/MEvv2vs.cc
@@ -1,259 +1,260 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEvv2vs class.
//
#include "MEvv2vs.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using ThePEG::Helicity::ScalarWaveFunction;
using ThePEG::Helicity::VectorWaveFunction;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
IBPtr MEvv2vs::clone() const {
return new_ptr(*this);
}
IBPtr MEvv2vs::fullclone() const {
return new_ptr(*this);
}
void MEvv2vs::persistentOutput(PersistentOStream & os) const {
- os << scalar_ << vector_ << fourPointVertex_;
+ os << scalar_ << vector_ << four_;
}
void MEvv2vs::persistentInput(PersistentIStream & is, int) {
- is >> scalar_ >> vector_ >> fourPointVertex_;
+ is >> scalar_ >> vector_ >> four_;
initializeMatrixElements(PDT::Spin1, PDT::Spin1,
PDT::Spin1, PDT::Spin0);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEvv2vs,GeneralHardME>
describeHerwigMEvv2vs("Herwig::MEvv2vs", "Herwig.so");
void MEvv2vs::Init() {
static ClassDocumentation<MEvv2vs> documentation
("The MEvv2vs class implements the general matrix elements"
" for vector vector -> vector scalar");
}
void MEvv2vs::doinit() {
GeneralHardME::doinit();
scalar_.resize(numberOfDiags());
vector_.resize(numberOfDiags());
+ four_.resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1, PDT::Spin1,
PDT::Spin1, PDT::Spin0);
for(size_t i = 0; i < numberOfDiags(); ++i) {
HPDiagram diag = getProcessInfo()[i];
tcPDPtr offshell = diag.intermediate;
if(!offshell) {
- fourPointVertex_ =
+ four_[i] =
dynamic_ptr_cast<AbstractVVVSVertexPtr>(diag.vertices.first);
}
else if(offshell->iSpin() == PDT::Spin0) {
AbstractVVSVertexPtr vert1;
AbstractVSSVertexPtr vert2;
if(diag.channelType == HPDiagram::sChannel ||
(diag.channelType == HPDiagram::tChannel && diag.ordered.second)) {
vert1 = dynamic_ptr_cast<AbstractVVSVertexPtr>(diag.vertices.first );
vert2 = dynamic_ptr_cast<AbstractVSSVertexPtr>(diag.vertices.second);
}
else {
vert1 = dynamic_ptr_cast<AbstractVVSVertexPtr>(diag.vertices.second);
vert2 = dynamic_ptr_cast<AbstractVSSVertexPtr>(diag.vertices.first );
}
scalar_[i] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1) {
AbstractVVVVertexPtr vert1;
AbstractVVSVertexPtr vert2;
if(diag.channelType == HPDiagram::sChannel ||
(diag.channelType == HPDiagram::tChannel && diag.ordered.second)) {
vert1 = dynamic_ptr_cast<AbstractVVVVertexPtr>(diag.vertices.first );
vert2 = dynamic_ptr_cast<AbstractVVSVertexPtr>(diag.vertices.second);
}
else {
vert1 = dynamic_ptr_cast<AbstractVVVVertexPtr>(diag.vertices.second);
vert2 = dynamic_ptr_cast<AbstractVVSVertexPtr>(diag.vertices.first );
}
vector_[i] = make_pair(vert1, vert2);
}
}
}
double MEvv2vs::me2() const {
VBVector va(2), vb(2), vc(3);
for(unsigned int i = 0; i < 2; ++i) {
va[i] = VectorWaveFunction(rescaledMomenta()[0], mePartonData()[0], 2*i,
incoming);
vb[i] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*i,
incoming);
}
//always 0 and 2 polarisations
for(unsigned int i = 0; i < 2; ++i) {
vc[2*i] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2], 2*i,
outgoing);
}
bool mc = !(mePartonData()[2]->mass() > ZERO);
//massive vector, also 1
if( !mc )
vc[1] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2], 1,
outgoing);
ScalarWaveFunction sd(rescaledMomenta()[3], mePartonData()[3], outgoing);
double full_me(0.);
vv2vsHeME(va, vb, vc, mc, sd, full_me,true);
return full_me;
}
ProductionMatrixElement
MEvv2vs::vv2vsHeME(VBVector & vin1, VBVector & vin2,
VBVector & vout1, bool mc, ScalarWaveFunction & sd,
double & me2, bool first) const {
const Energy2 q2(scale());
const Energy mass = vout1[0].mass();
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
// flow over the helicities and diagrams
for(unsigned int ihel1 = 0; ihel1 < 2; ++ihel1) {
for(unsigned int ihel2 = 0; ihel2 < 2; ++ihel2) {
for(unsigned int ohel1 = 0; ohel1 < 3; ++ohel1) {
if(mc && ohel1 == 1) ++ohel1;
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if(!offshell) {
- diag = fourPointVertex_->evaluate(q2, vin1[ihel1], vin2[ihel2],
- vout1[ohel1], sd);
+ diag = four_[ix]->evaluate(q2, vin1[ihel1], vin2[ihel2],
+ vout1[ohel1], sd);
}
else if(current.channelType == HPDiagram::sChannel) {
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction interS = scalar_[ix].first->
evaluate(q2, 1, offshell,vin1[ihel1], vin2[ihel2]);
diag = scalar_[ix].second->
evaluate(q2, vout1[ohel1], sd, interS);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].first->
evaluate(q2, 1, offshell, vin1[ihel1], vin2[ihel2]);
diag = vector_[ix].second->
evaluate(q2, vout1[ohel1], interV, sd);
}
else
assert(false);
}
else if(current.channelType == HPDiagram::tChannel) {
if(offshell->iSpin() == PDT::Spin0) {
if(current.ordered.second) {
ScalarWaveFunction interS = scalar_[ix].
first->evaluate(q2, 3, offshell, vin1[ihel1],vout1[ohel1], mass);
diag = scalar_[ix].second->
evaluate(q2, vin2[ihel2], sd, interS);
}
else {
ScalarWaveFunction interS = scalar_[ix].first->
evaluate(q2, 3, offshell, vin2[ihel2],vout1[ohel1], mass);
diag = scalar_[ix].second->
evaluate(q2, vin1[ihel1], sd, interS);
}
}
else if(offshell->iSpin() == PDT::Spin1) {
if(current.ordered.second) {
VectorWaveFunction interV = vector_[ix].
first->evaluate(q2, 3, offshell, vin1[ihel1],vout1[ohel1], mass);
diag = vector_[ix].second->
evaluate(q2, vin2[ihel2], interV, sd);
}
else {
VectorWaveFunction interV = vector_[ix].first->
evaluate(q2, 3, offshell, vin2[ihel2],vout1[ohel1], mass);
diag = vector_[ix].second->
evaluate(q2, vin1[ihel1], interV, sd);
}
}
else
assert(false);
}
else
assert(false);
me[ix] += norm(diag);
diagramME()[ix](2*ihel1, 2*ihel2, ohel1,0) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](2*ihel1, 2*ihel2, ohel1, 0) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEvv2vs::constructVertex(tSubProPtr sub) {
ParticleVector ext = hardParticles(sub);
// set wave functions with real momenta
VBVector v1, v2, v3;
VectorWaveFunction(v1, ext[0], incoming, false, true);
VectorWaveFunction(v2, ext[1], incoming, false, true);
//function to calculate me2 expects massless incoming vectors
// and this constructor sets the '1' polarisation at element [2]
//in the vector
bool mc = !(ext[2]->data().mass() > ZERO);
VectorWaveFunction(v3, ext[2], outgoing, true, mc);
ScalarWaveFunction sd(ext[3], outgoing, true);
// Need to use rescale momenta to calculate matrix element
setRescaledMomenta(ext);
// wave functions with rescaled momenta
VectorWaveFunction vr1(rescaledMomenta()[0],
ext[0]->dataPtr(), incoming);
VectorWaveFunction vr2(rescaledMomenta()[1],
ext[1]->dataPtr(), incoming);
VectorWaveFunction vr3(rescaledMomenta()[2],
ext[2]->dataPtr(), outgoing);
ScalarWaveFunction sr4(rescaledMomenta()[3],
ext[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
vr1.reset(2*ihel);
v1[ihel] = vr1;
vr2.reset(2*ihel);
v2[ihel] = vr2;
vr3.reset(2*ihel);
v3[2*ihel] = vr3;
}
if( !mc ) {
vr3.reset(1);
v3[1] = vr3;
}
double dummy(0.);
ProductionMatrixElement pme = vv2vsHeME(v1, v2, v3, mc, sd, dummy,false);
createVertex(pme,ext);
}
diff --git a/MatrixElement/General/MEvv2vs.h b/MatrixElement/General/MEvv2vs.h
--- a/MatrixElement/General/MEvv2vs.h
+++ b/MatrixElement/General/MEvv2vs.h
@@ -1,163 +1,163 @@
// -*- C++ -*-
#ifndef HERWIG_MEvv2vs_H
#define HERWIG_MEvv2vs_H
//
// This is the declaration of the MEvv2vs class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVSVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VectorWaveFunction;
using Helicity::ScalarWaveFunction;
/**
* This is the implementation of the matrix element for
* \f$2\to 2\f$ massless vector-boson pair to a vector and scalar boson.
* It inherits from GeneralHardME and implements the appropriate virtual
* member functions.
*
* @see \ref MEvv2vsInterfaces "The interfaces"
* defined for MEvv2vs.
*/
class MEvv2vs: public GeneralHardME {
public:
/**
* Typedef for VectorWaveFunction
*/
typedef vector<VectorWaveFunction> VBVector;
public:
/** @name Virtual functions required by the GeneralHardME class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
/**
* Construct the vertex information for the spin correlations
* @param sub Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr sub);
private:
/**
* Compute the matrix element for \f$V\, V\to V\, V\f$
* @param vin1 VectorWaveFunctions for first incoming particle
* @param vin2 VectorWaveFunctions for second incoming particle
* @param vout1 VectorWaveFunctions for first outgoing particle
* @param mc Whether vout1 is massless or not
* @param sout2 ScalarWaveFunction for outgoing particle
* @param me2 colour averaged, spin summed ME
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @return ProductionMatrixElement containing results of
* helicity calculations
*/
ProductionMatrixElement
vv2vsHeME(VBVector & vin1, VBVector & vin2,
VBVector & vout1, bool mc, ScalarWaveFunction & sout2,
double & me2, bool first ) 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.
*/
MEvv2vs & operator=(const MEvv2vs &);
private:
/**
* Store the dynamically casted VVSVertex and VSSVertex pointers
*/
vector<pair<AbstractVVSVertexPtr, AbstractVSSVertexPtr> > scalar_;
/**
* Store the dynamically casted VVVVertex and VVSVertex pointers
*/
vector<pair<AbstractVVVVertexPtr, AbstractVVSVertexPtr> > vector_;
/**
* Store the dynamically casted VVVSVertex pointer
*/
- AbstractVVVSVertexPtr fourPointVertex_;
+ vector<AbstractVVVSVertexPtr> four_;
};
}
#endif /* HERWIG_MEvv2vs_H */
diff --git a/MatrixElement/General/MEvv2vv.cc b/MatrixElement/General/MEvv2vv.cc
--- a/MatrixElement/General/MEvv2vv.cc
+++ b/MatrixElement/General/MEvv2vv.cc
@@ -1,344 +1,407 @@
// -*- C++ -*-
//
// MEvv2vv.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEvv2vv class.
//
#include "MEvv2vv.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
+#include "Herwig/Models/StandardModel/StandardModel.h"
using namespace Herwig;
using ThePEG::Helicity::ScalarWaveFunction;
using ThePEG::Helicity::TensorWaveFunction;
using ThePEG::Helicity::incoming;
using ThePEG::Helicity::outgoing;
void MEvv2vv::doinit() {
GeneralHardME::doinit();
scalar_.resize(numberOfDiags());
vector_.resize(numberOfDiags());
tensor_.resize(numberOfDiags());
+ four_ .resize(numberOfDiags());
initializeMatrixElements(PDT::Spin1, PDT::Spin1,
PDT::Spin1, PDT::Spin1);
for(size_t i = 0; i < numberOfDiags(); ++i) {
HPDiagram diag = getProcessInfo()[i];
tcPDPtr offshell = diag.intermediate;
if(!offshell)
- fourPointVertex_ = dynamic_ptr_cast<AbstractVVVVVertexPtr>
+ four_[i] = dynamic_ptr_cast<AbstractVVVVVertexPtr>
(diag.vertices.first);
else if(offshell->iSpin() == PDT::Spin0) {
AbstractVVSVertexPtr vert1 = dynamic_ptr_cast<AbstractVVSVertexPtr>
(diag.vertices.first);
AbstractVVSVertexPtr vert2 = dynamic_ptr_cast<AbstractVVSVertexPtr>
(diag.vertices.second);
scalar_[i] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin1) {
AbstractVVVVertexPtr vert1 = dynamic_ptr_cast<AbstractVVVVertexPtr>
(diag.vertices.first);
AbstractVVVVertexPtr vert2 = dynamic_ptr_cast<AbstractVVVVertexPtr>
(diag.vertices.second);
vector_[i] = make_pair(vert1, vert2);
}
else if(offshell->iSpin() == PDT::Spin2) {
AbstractVVTVertexPtr vert1 = dynamic_ptr_cast<AbstractVVTVertexPtr>
(diag.vertices.first);
AbstractVVTVertexPtr vert2 = dynamic_ptr_cast<AbstractVVTVertexPtr>
(diag.vertices.second);
tensor_[i] = make_pair(vert1, vert2);
}
}
+ if(colour()==Colour88to88||colour()==Colour88to66bar) {
+ tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
+ for(size_t i = 0; i < numberOfDiags(); ++i) {
+ HPDiagram diag = getProcessInfo()[i];
+ if(diag.intermediate) continue;
+ vector<int> order;
+ for(map<string,pair<unsigned int,int> >::const_iterator it=hwsm->couplings().begin();
+ it!=hwsm->couplings().end();++it) {
+ order.push_back(0);
+ if(diag.vertices.first ) order.back() += diag.vertices.first ->orderInCoupling(it->second.first);
+ if(diag.vertices.second&&diag.vertices.first->getNpoint()==3)
+ order.back() += diag.vertices.second->orderInCoupling(it->second.first);
+ }
+ vector<unsigned int> matchdiags;
+ for(size_t j = 0; j < numberOfDiags(); ++j) {
+ HPDiagram diag2 = getProcessInfo()[j];
+ if(!diag2.intermediate ||
+ (diag2.intermediate->iColour()==PDT::Colour8 &&
+ diag2.intermediate->iColour()==PDT::Colour6 &&
+ diag2.intermediate->iColour()==PDT::Colour6bar)) continue;
+ unsigned int iloc(0);
+ bool match=true;
+ for(map<string,pair<unsigned int,int> >::const_iterator it=hwsm->couplings().begin();
+ it!=hwsm->couplings().end();++it) {
+ int otemp(0);
+ if(diag2.vertices.first ) otemp += diag2.vertices.first ->orderInCoupling(it->second.first);
+ if(diag2.vertices.second&&diag2.vertices.first->getNpoint()==3)
+ otemp += diag2.vertices.second->orderInCoupling(it->second.first);
+ if(otemp!=order[iloc]) {
+ match = false;
+ break;
+ }
+ iloc+=1;
+ }
+ if(!match) continue;
+ matchdiags.push_back(j);
+ }
+ double weight = 3./double(matchdiags.size());
+ for(unsigned int iy=0;iy<matchdiags.size();++iy)
+ if(fourFlow_.find(matchdiags[iy])!=fourFlow_.end())
+ fourFlow_[matchdiags[iy]].push_back(make_pair(i,weight));
+ else
+ fourFlow_[matchdiags[iy]] = vector<pair<unsigned int,double> >(1,make_pair(i,weight));
+ }
+ }
}
double MEvv2vv::me2() const {
VBVector va(2), vb(2), vc(3), vd(3);
for(unsigned int i = 0; i < 2; ++i) {
va[i] = VectorWaveFunction(rescaledMomenta()[0], mePartonData()[0], 2*i,
incoming);
vb[i] = VectorWaveFunction(rescaledMomenta()[1], mePartonData()[1], 2*i,
incoming);
}
//always 0 and 2 polarisations
for(unsigned int i = 0; i < 2; ++i) {
vc[2*i] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2], 2*i,
outgoing);
vd[2*i] = VectorWaveFunction(rescaledMomenta()[3], mePartonData()[3], 2*i,
outgoing);
}
bool mc = !(mePartonData()[2]->mass() > ZERO);
//massive vector, also 1
if( !mc )
vc[1] = VectorWaveFunction(rescaledMomenta()[2], mePartonData()[2], 1,
outgoing);
bool md = !(mePartonData()[3]->mass() > ZERO);
if( !md )
vd[1] = VectorWaveFunction(rescaledMomenta()[3], mePartonData()[3], 1,
outgoing);
double full_me(0.);
vv2vvHeME(va, vb, vc, mc, vd, md, full_me,true);
#ifndef NDEBUG
if( debugME() ) debug(full_me);
#endif
return full_me;
}
ProductionMatrixElement
MEvv2vv::vv2vvHeME(VBVector & vin1, VBVector & vin2,
VBVector & vout1, bool mc, VBVector & vout2, bool md,
double & me2, bool first) const {
const Energy2 q2(scale());
const Energy mass = vout1[0].mass();
// weights for the selection of the diagram
vector<double> me(numberOfDiags(), 0.);
// weights for the selection of the colour flow
vector<double> flow(numberOfFlows(),0.);
// flow over the helicities and diagrams
for(unsigned int ihel1 = 0; ihel1 < 2; ++ihel1) {
for(unsigned int ihel2 = 0; ihel2 < 2; ++ihel2) {
for(unsigned int ohel1 = 0; ohel1 < 3; ++ohel1) {
if(mc && ohel1 == 1) ++ohel1;
for(unsigned int ohel2 = 0; ohel2 < 3; ++ohel2) {
if(md && ohel2 == 1) ++ohel2;
vector<Complex> flows(numberOfFlows(),0.);
for(HPCount ix = 0; ix < numberOfDiags(); ++ix) {
Complex diag(0.);
const HPDiagram & current = getProcessInfo()[ix];
tcPDPtr offshell = current.intermediate;
if(current.channelType == HPDiagram::sChannel) {
if(offshell->iSpin() == PDT::Spin0) {
ScalarWaveFunction interS =
scalar_[ix].first->evaluate(q2, 1, offshell,
vin1[ihel1], vin2[ihel2]);
diag = scalar_[ix].second->
evaluate(q2, vout1[ohel1], vout2[ohel2], interS);
}
else if(offshell->iSpin() == PDT::Spin1) {
VectorWaveFunction interV = vector_[ix].first->
evaluate(q2, 1, offshell, vin1[ihel1], vin2[ihel2]);
diag = vector_[ix].second->
evaluate(q2, vout1[ohel1], vout2[ohel2], interV);
if(colour()==Colour88to88)
- diag += fourPointVertex_->evaluate(q2, 0, vout1[ohel1], vin2[ihel2],
- vout2[ohel2], vin1[ihel1]);
+ for(unsigned int iy=0;iy<fourFlow_.at(ix).size();++iy) {
+ unsigned int iloc=fourFlow_.at(ix)[iy].first;
+ double wgt = fourFlow_.at(ix)[iy].second;
+ diag += wgt*four_[iloc]->evaluate(q2, 0, vout1[ohel1], vin2[ihel2],
+ vout2[ohel2], vin1[ihel1]);
+ }
else if(colour()==Colour88to66bar)
- diag -= fourPointVertex_->evaluate(q2, 0, vout1[ohel1], vin2[ihel2],
- vout2[ohel2], vin1[ihel1]);
+ for(unsigned int iy=0;iy<fourFlow_.at(ix).size();++iy) {
+ unsigned int iloc=fourFlow_.at(ix)[iy].first;
+ double wgt = fourFlow_.at(ix)[iy].second;
+ diag -= wgt*four_[iloc]->evaluate(q2, 0, vout1[ohel1], vin2[ihel2],
+ vout2[ohel2], vin1[ihel1]);
+ }
}
else if(offshell->iSpin() == PDT::Spin2) {
TensorWaveFunction interT = tensor_[ix].first->
evaluate(q2, 1, offshell, vin1[ihel1], vin2[ihel2]);
diag = tensor_[ix].second->
evaluate(q2, vout1[ohel1], vout2[ohel2],interT);
}
else
assert(false);
}
else if(current.channelType == HPDiagram::tChannel) {
if(offshell->iSpin() == PDT::Spin0) {
if(current.ordered.second) {
ScalarWaveFunction interS = scalar_[ix].
first->evaluate(q2, 3, offshell, vin1[ihel1],vout1[ohel1]);
diag = scalar_[ix].second->
evaluate(q2, vin2[ihel2], vout2[ohel2], interS);
}
else {
ScalarWaveFunction interS = scalar_[ix].first->
evaluate(q2, 3, offshell, vin2[ihel2],vout1[ohel1]);
diag = scalar_[ix].second->
evaluate(q2, vin1[ihel1], vout2[ohel2], interS);
}
}
else if(offshell->iSpin() == PDT::Spin1) {
if(current.ordered.second) {
VectorWaveFunction interV = vector_[ix].
first->evaluate(q2, 3, offshell, vin1[ihel1],vout1[ohel1], mass);
diag = vector_[ix].second->
evaluate(q2, vin2[ihel2], interV, vout2[ohel2]);
if(colour()==Colour88to88 || colour()==Colour88to66bar)
- diag += fourPointVertex_->evaluate(q2, 0, vin1[ihel1], vin2[ihel2],
- vout1[ohel1], vout2[ohel2]);
+ for(unsigned int iy=0;iy<fourFlow_.at(ix).size();++iy) {
+ unsigned int iloc=fourFlow_.at(ix)[iy].first;
+ double wgt = fourFlow_.at(ix)[iy].second;
+ diag += wgt*four_[iloc]->evaluate(q2, 0, vin1[ihel1], vin2[ihel2],
+ vout1[ohel1], vout2[ohel2]);
+ }
}
else {
if(offshell->CC()) offshell = offshell->CC();
VectorWaveFunction interV = vector_[ix].first->
evaluate(q2, 3, offshell, vin2[ihel2],vout1[ohel1], mass);
diag = vector_[ix].second->
evaluate(q2, vin1[ihel1], interV, vout2[ohel2]);
if(colour()==Colour88to88 || colour()==Colour88to66bar)
- diag += fourPointVertex_->
- evaluate(q2, 0, vin2[ihel2], vin1[ihel1],
- vout1[ohel1], vout2[ohel2]);
+ for(unsigned int iy=0;iy<fourFlow_.at(ix).size();++iy) {
+ unsigned int iloc=fourFlow_.at(ix)[iy].first;
+ double wgt = fourFlow_.at(ix)[iy].second;
+ diag += wgt*four_[iloc]->
+ evaluate(q2, 0, vin2[ihel2], vin1[ihel1],
+ vout1[ohel1], vout2[ohel2]);
+ }
}
}
else if(offshell->iSpin() == PDT::Spin2) {
if(current.ordered.second) {
TensorWaveFunction interT = tensor_[ix].first->
evaluate(q2, 3, offshell, vin1[ihel1],vout1[ohel1]);
diag = tensor_[ix].second->
evaluate(q2, vin2[ihel2], vout2[ohel2], interT);
}
else {
TensorWaveFunction interT = tensor_[ix].first->
evaluate(q2, 3, offshell, vin2[ihel2],vout1[ohel1]);
diag = tensor_[ix].second->
evaluate(q2, vin1[ihel1], vout2[ohel2], interT);
}
}
else
assert(false);
}
else if(current.channelType == HPDiagram::fourPoint) {
if(colour()==Colour88to88||colour()==Colour88to66bar)
diag = 0.;
else
- diag = fourPointVertex_->evaluate(q2, 0, vin1[ihel1], vin2[ihel2],
- vout1[ohel1], vout2[ohel2]);
+ diag = four_[ix]->evaluate(q2, 0, vin1[ihel1], vin2[ihel2],
+ vout1[ohel1], vout2[ohel2]);
}
else
assert(false);
me[ix] += norm(diag);
diagramME()[ix](2*ihel1, 2*ihel2, ohel1, ohel2) = diag;
//Compute flows
for(size_t iy = 0; iy < current.colourFlow.size(); ++iy) {
assert(current.colourFlow[iy].first<flows.size());
flows[current.colourFlow[iy].first] +=
current.colourFlow[iy].second * diag;
}
}
// MEs for the different colour flows
for(unsigned int iy = 0; iy < numberOfFlows(); ++iy)
flowME()[iy](2*ihel1, 2*ihel2, ohel1, ohel2) = flows[iy];
//Now add flows to me2 with appropriate colour factors
for(size_t ii = 0; ii < numberOfFlows(); ++ii)
for(size_t ij = 0; ij < numberOfFlows(); ++ij)
me2 += getColourFactors()[ii][ij]*(flows[ii]*conj(flows[ij])).real();
// contribution to the colour flow
for(unsigned int ii = 0; ii < numberOfFlows(); ++ii) {
flow[ii] += getColourFactors()[ii][ii]*norm(flows[ii]);
}
}
}
}
}
// if not computing the cross section return the selected colour flow
if(!first) return flowME()[colourFlow()];
me2 = selectColourFlow(flow,me,me2);
return flowME()[colourFlow()];
}
void MEvv2vv::persistentOutput(PersistentOStream & os) const {
- os << scalar_ << vector_ << tensor_ << fourPointVertex_;
+ os << scalar_ << vector_ << tensor_ << four_ << fourFlow_;
}
void MEvv2vv::persistentInput(PersistentIStream & is, int) {
- is >> scalar_ >> vector_ >> tensor_ >> fourPointVertex_;
+ is >> scalar_ >> vector_ >> tensor_ >> four_ >> fourFlow_;
initializeMatrixElements(PDT::Spin1, PDT::Spin1,
PDT::Spin1, PDT::Spin1);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEvv2vv,GeneralHardME>
describeHerwigMEvv2vv("Herwig::MEvv2vv", "Herwig.so");
void MEvv2vv::Init() {
static ClassDocumentation<MEvv2vv> documentation
("This is the implementation of the 2 to 2 ME for a pair"
"of massless vector-bosons to a pair of vector bosons");
}
void MEvv2vv::constructVertex(tSubProPtr sub) {
ParticleVector ext = hardParticles(sub);
// set wave functions with real momenta
VBVector v1, v2, v3, v4;
VectorWaveFunction(v1, ext[0], incoming, false, true);
VectorWaveFunction(v2, ext[1], incoming, false, true);
//function to calculate me2 expects massless incoming vectors
// and this constructor sets the '1' polarisation at element [2]
//in the vector
bool mc = !(ext[2]->data().mass() > ZERO);
bool md = !(ext[3]->data().mass() > ZERO);
VectorWaveFunction(v3, ext[2], outgoing, true, mc);
VectorWaveFunction(v4, ext[3], outgoing, true, md);
// Need to use rescale momenta to calculate matrix element
setRescaledMomenta(ext);
// wave functions with rescaled momenta
VectorWaveFunction vr1(rescaledMomenta()[0],
ext[0]->dataPtr(), incoming);
VectorWaveFunction vr2(rescaledMomenta()[1],
ext[1]->dataPtr(), incoming);
VectorWaveFunction vr3(rescaledMomenta()[2],
ext[2]->dataPtr(), outgoing);
VectorWaveFunction vr4(rescaledMomenta()[3],
ext[3]->dataPtr(), outgoing);
for( unsigned int ihel = 0; ihel < 2; ++ihel ) {
vr1.reset(2*ihel);
v1[ihel] = vr1;
vr2.reset(2*ihel);
v2[ihel] = vr2;
vr3.reset(2*ihel);
v3[2*ihel] = vr3;
vr4.reset(2*ihel);
v4[2*ihel] = vr4;
}
if( !mc ) {
vr3.reset(1);
v3[1] = vr3;
}
if( !md ) {
vr4.reset(1);
v4[1] = vr4;
}
double dummy(0.);
ProductionMatrixElement pme = vv2vvHeME(v1, v2, v3, mc, v4, md, dummy,false);
#ifndef NDEBUG
if( debugME() ) debug(dummy);
#endif
createVertex(pme,ext);
}
void MEvv2vv::debug(double me2) const {
if( !generator()->logfile().is_open() ) return;
if( mePartonData()[0]->id() != 21 || mePartonData()[1]->id() != 21 ||
mePartonData()[2]->id() != 5100021 ||
mePartonData()[3]->id() != 5100021 ) return;
tcSMPtr sm = generator()->standardModel();
double gs4 = sqr( 4.*Constants::pi*sm->alphaS(scale()) );
Energy2 s(sHat());
Energy2 mf2 = meMomenta()[2].m2();
Energy2 t3(tHat() - mf2), u4(uHat() - mf2);
Energy4 s2(sqr(s)), t3s(sqr(t3)), u4s(sqr(u4));
Energy4 num = s2 + t3s + u4s;
double analytic = 3.*mf2*( mf2*num/t3s/u4s - num/s/t3/u4 ) + 1.
+ sqr(num)*num/4./s2/t3s/u4s - t3*u4/s2;
analytic *= 9.*gs4/8.;
double diff = abs( analytic - me2 );
if( diff > 1e-4 ) {
generator()->log()
<< mePartonData()[0]->PDGName() << ","
<< mePartonData()[1]->PDGName() << "->"
<< mePartonData()[2]->PDGName() << ","
<< mePartonData()[3]->PDGName() << " difference: "
<< setprecision(10) << diff << " ratio: " << analytic/me2 << '\n';
}
}
diff --git a/MatrixElement/General/MEvv2vv.h b/MatrixElement/General/MEvv2vv.h
--- a/MatrixElement/General/MEvv2vv.h
+++ b/MatrixElement/General/MEvv2vv.h
@@ -1,183 +1,188 @@
// -*- C++ -*-
//
// MEvv2vv.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_MEvv2vv_H
#define HERWIG_MEvv2vv_H
//
// This is the declaration of the MEvv2vv class.
//
#include "GeneralHardME.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVTVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVVertex.h"
#include "Herwig/MatrixElement/ProductionMatrixElement.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VectorWaveFunction;
/**
* This is the implementation of the matrix element for
* \f$2\to 2\f$ massless vector-boson pair to vector-boson pair. It inherits from
* GeneralHardME and implements the appropriate virtual member functions.
*
* @see \ref MEvv2vvInterfaces "The interfaces"
* defined for MEvv2vv.
*/
class MEvv2vv: public GeneralHardME {
public:
/**
* Typedef for VectorWaveFunction
*/
typedef vector<VectorWaveFunction> VBVector;
public:
/** @name Virtual functions required by the GeneralHardME class. */
//@{
/**
* The matrix element for the kinematical configuration
* previously provided by the last call to setKinematics(), suitably
* scaled by sHat() to give a dimension-less number.
* @return the matrix element scaled with sHat() to give a
* dimensionless number.
*/
virtual double me2() const;
//@}
/**
* Construct the vertex information for the spin correlations
* @param sub Pointer to the relevent SubProcess
*/
virtual void constructVertex(tSubProPtr sub);
private:
/**
* Compute the matrix element for \f$V\, V\to V\, V\f$
* @param vin1 VectorWaveFunctions for first incoming particle
* @param vin2 VectorWaveFunctions for second incoming particle
* @param vout1 VectorWaveFunctions for first outgoing particle
* @param mc Whether vout1 is massless or not
* @param vout2 VectorWaveFunctions for outgoing particle
* @param md Whether vout2 is massless or not
* @param me2 colour averaged, spin summed ME
* @param first Whether or not first call to decide if colour decomposition etc
* should be calculated
* @return ProductionMatrixElement containing results of
* helicity calculations
*/
ProductionMatrixElement
vv2vvHeME(VBVector & vin1, VBVector & vin2,
VBVector & vout1, bool mc, VBVector & vout2, bool md,
double & me2, bool first ) const;
protected:
/**
* A debugging function to test the value of me2 against an
* analytic function.
* @param me2 The value of the \f$ |\bar{\mathcal{M}}|^2 \f$
*/
virtual void debug(double me2) 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 {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MEvv2vv & operator=(const MEvv2vv &);
private:
/**
* Store the dynamically casted VVSVertex pointers
*/
vector<pair<AbstractVVSVertexPtr, AbstractVVSVertexPtr> > scalar_;
/**
* Store the dynamically casted VVVVertex pointers
*/
vector<pair<AbstractVVVVertexPtr, AbstractVVVVertexPtr> > vector_;
/**
* Store the dynamically casted VVTVertex pointers
*/
vector<pair<AbstractVVTVertexPtr, AbstractVVTVertexPtr> > tensor_;
/**
* Store the dynamically casted VVVVVertex pointer
*/
- AbstractVVVVVertexPtr fourPointVertex_;
+ vector<AbstractVVVVVertexPtr> four_;
+
+ /**
+ * Four points for colour flows
+ */
+ map<unsigned int,vector<pair<unsigned int,double> > > fourFlow_;
};
}
#endif /* HERWIG_MEvv2vv_H */
diff --git a/MatrixElement/General/Makefile.am b/MatrixElement/General/Makefile.am
--- a/MatrixElement/General/Makefile.am
+++ b/MatrixElement/General/Makefile.am
@@ -1,20 +1,24 @@
noinst_LTLIBRARIES = libHwGeneralME.la
libHwGeneralME_la_SOURCES = \
GeneralHardME.cc GeneralHardME.h GeneralHardME.fh \
MEvv2ff.cc MEvv2ff.h \
+MEvv2rf.cc MEvv2rf.h \
MEvv2ss.cc MEvv2ss.h \
MEfv2fs.cc MEfv2fs.h \
+MEfv2rs.cc MEfv2rs.h \
MEff2ss.cc MEff2ss.h \
MEff2ff.cc MEff2ff.h \
+MEff2rf.cc MEff2rf.h \
MEff2vv.cc MEff2vv.h \
MEfv2vf.cc MEfv2vf.h \
+MEfv2rv.cc MEfv2rv.h \
MEff2vs.cc MEff2vs.h \
-MEff2sv.cc MEff2sv.h \
MEvv2vv.cc MEvv2vv.h \
MEvv2vs.cc MEvv2vs.h \
MEff2tv.cc MEff2tv.h \
+MEff2ts.cc MEff2ts.h \
MEvv2tv.cc MEvv2tv.h \
MEfv2tf.cc MEfv2tf.h \
GeneralfftoVH.cc GeneralfftoVH.h GeneralfftoVH.fh\
GeneralfftoffH.cc GeneralfftoffH.h GeneralfftoffH.fh\
GeneralQQHiggs.cc GeneralQQHiggs.h GeneralQQHiggs.fh
diff --git a/MatrixElement/Hadron/MEPP2HiggsVBF.cc b/MatrixElement/Hadron/MEPP2HiggsVBF.cc
--- a/MatrixElement/Hadron/MEPP2HiggsVBF.cc
+++ b/MatrixElement/Hadron/MEPP2HiggsVBF.cc
@@ -1,1458 +1,1462 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2HiggsVBF class.
//
#include "MEPP2HiggsVBF.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/PDT/StandardMatchers.h"
#include <numeric>
#include "Herwig/Utilities/Maths.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "Herwig/Shower/RealEmissionProcess.h"
using namespace Herwig;
// namespace {
// using namespace Herwig;
// using namespace ThePEG;
// using namespace ThePEG::Helicity;
// void debuggingMatrixElement(bool BGF,
// tcPDPtr partons1, tcPDPtr partons2,
// tcPDPtr partons3, tcPDPtr partons4,
// const Lorentz5Momentum & psystem0,
// const Lorentz5Momentum & psystem1,
// const Lorentz5Momentum & pother0,
// const Lorentz5Momentum & pother1,
// const Lorentz5Momentum & p0,
// const Lorentz5Momentum & p1,
// const Lorentz5Momentum & p2,
// const Lorentz5Momentum & phiggs,
// Energy2 Q12, Energy2 scale,
// double old) {
// // get the vertex and the boson
// tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast<tcHwSMPtr>
// (CurrentGenerator::current().standardModel());
// assert(hwsm);
// tcPDPtr boson;
// AbstractFFVVertexPtr weakVertex;
// AbstractFFVVertexPtr strongVertex = hwsm->vertexFFG();
// AbstractVVSVertexPtr higgsVertex = hwsm->vertexWWH();
// if(partons1->id()==partons2->id()) {
// weakVertex = hwsm->vertexFFZ();
// boson = hwsm->getParticleData(ParticleID::Z0);
// }
// else {
// weakVertex = hwsm->vertexFFW();
// boson = hwsm->getParticleData(ParticleID::Wplus);
// }
// tcPDPtr hdata = hwsm->getParticleData(ParticleID::h0);
// tcPDPtr gluon = hwsm->getParticleData(ParticleID::g);
// SpinorWaveFunction q1,q2;
// SpinorBarWaveFunction qbar1,qbar2;
// if(partons1->id()>0) {
// q1 = SpinorWaveFunction (psystem0,partons1,incoming);
// qbar1 = SpinorBarWaveFunction(psystem1,partons2,outgoing);
// }
// else {
// q1 = SpinorWaveFunction (psystem1,partons2,outgoing);
// qbar1 = SpinorBarWaveFunction(psystem0,partons1,incoming);
// }
// if(partons3->id()>0) {
// q2 = SpinorWaveFunction (pother0,partons3,incoming);
// qbar2 = SpinorBarWaveFunction(pother1,partons4,outgoing);
// }
// else {
// q2 = SpinorWaveFunction (pother1,partons4,outgoing);
// qbar2 = SpinorBarWaveFunction(pother0,partons3,incoming);
// }
// ScalarWaveFunction higgs(phiggs,hdata,outgoing);
// if(!BGF) {
// SpinorWaveFunction q1p;
// SpinorBarWaveFunction qbar1p;
// if(partons1->id()>0) {
// q1p = SpinorWaveFunction (p0 ,partons1,incoming);
// qbar1p = SpinorBarWaveFunction(p1 ,partons2,outgoing);
// }
// else {
// q1p = SpinorWaveFunction (p1 ,partons2,outgoing);
// qbar1p = SpinorBarWaveFunction(p0 ,partons1,incoming);
// }
// VectorWaveFunction gl(p2,gluon,outgoing);
// double lome(0.),realme(0.);
// for(unsigned int lhel1=0;lhel1<2;++lhel1) {
// q2.reset(lhel1);
// for(unsigned int lhel2=0;lhel2<2;++lhel2) {
// qbar2.reset(lhel2);
// VectorWaveFunction off1
// = weakVertex->evaluate(scale,3,boson,q2,qbar2);
// VectorWaveFunction off2
// = higgsVertex->evaluate(scale,3,boson,off1,higgs);
// for(unsigned int qhel1=0;qhel1<2;++qhel1) {
// q1.reset(qhel1);
// q1p.reset(qhel1);
// for(unsigned int qhel2=0;qhel2<2;++qhel2) {
// qbar1.reset(qhel2);
// qbar1p.reset(qhel2);
// Complex diag = weakVertex->evaluate(scale,q1,qbar1,off2);
// lome += norm(diag);
// for(unsigned int ghel=0;ghel<2;++ghel) {
// gl.reset(2*ghel);
// SpinorWaveFunction inter1 =
// strongVertex->evaluate(Q12,5,q1p.particle(),q1p,gl);
// Complex diag1 = weakVertex->evaluate(scale,inter1,qbar1p,off2);
// SpinorBarWaveFunction inter2 =
// strongVertex->evaluate(Q12,5,qbar1p.particle(),qbar1p,gl);
// Complex diag2 = weakVertex->evaluate(scale,q1p,inter2,off2);
// realme += norm(diag1+diag2);
// }
// }
// }
// }
// }
// double test1 = realme/lome/hwsm->alphaS(Q12)*Q12*UnitRemoval::InvE2;
// cerr << "testing ratio A " << old/test1 << "\n";
// }
// else {
// SpinorWaveFunction q1p;
// SpinorBarWaveFunction qbar1p;
// if(partons1->id()>0) {
// q1p = SpinorWaveFunction (p2,partons1->CC(),outgoing);
// qbar1p = SpinorBarWaveFunction(p1,partons2 ,outgoing);
// }
// else {
// q1p = SpinorWaveFunction (p1,partons2 ,outgoing);
// qbar1p = SpinorBarWaveFunction(p2,partons1->CC(),outgoing);
// }
// VectorWaveFunction gl(p0,gluon,incoming);
// double lome(0.),realme(0.);
// for(unsigned int lhel1=0;lhel1<2;++lhel1) {
// q2.reset(lhel1);
// for(unsigned int lhel2=0;lhel2<2;++lhel2) {
// qbar2.reset(lhel2);
// VectorWaveFunction off1
// = weakVertex->evaluate(scale,3,boson,q2,qbar2);
// VectorWaveFunction off2
// = higgsVertex->evaluate(scale,3,boson,off1,higgs);
// for(unsigned int qhel1=0;qhel1<2;++qhel1) {
// q1.reset(qhel1);
// q1p.reset(qhel1);
// for(unsigned int qhel2=0;qhel2<2;++qhel2) {
// qbar1.reset(qhel2);
// qbar1p.reset(qhel2);
// Complex diag = weakVertex->evaluate(scale,q1,qbar1,off2);
// lome += norm(diag);
// for(unsigned int ghel=0;ghel<2;++ghel) {
// gl.reset(2*ghel);
// SpinorWaveFunction inter1 =
// strongVertex->evaluate(Q12,5,q1p.particle(),q1p,gl);
// Complex diag1 = weakVertex->evaluate(scale,inter1,qbar1p,off2);
// SpinorBarWaveFunction inter2 =
// strongVertex->evaluate(Q12,5,qbar1p.particle(),qbar1p,gl);
// Complex diag2 = weakVertex->evaluate(scale,q1p,inter2,off2);
// realme += norm(diag1+diag2);
// }
// }
// }
// }
// }
// double test1 = realme/lome/hwsm->alphaS(Q12)*Q12*UnitRemoval::InvE2;
// cerr << "testing ratio B " << old/test1 << "\n";
// }
// }
// }
MEPP2HiggsVBF::MEPP2HiggsVBF() : comptonWeight_(8.), BGFWeight_(30.),
pTmin_(1.*GeV),initial_(10.),final_(8.),
procProb_(0.5), comptonInt_(0.), bgfInt_(0.),
nover_(0),maxwgt_(make_pair(0.,0.))
{}
void MEPP2HiggsVBF::doinit() {
gluon_ = getParticleData(ParticleID::g);
// integrals of me over phase space
double r5=sqrt(5.),darg((r5-1.)/(r5+1.)),ath(0.5*log((1.+1./r5)/(1.-1./r5)));
comptonInt_ = 2.*(-21./20.-6./(5.*r5)*ath+sqr(Constants::pi)/3.
-2.*Math::ReLi2(1.-darg)-2.*Math::ReLi2(1.-1./darg));
bgfInt_ = 121./9.-56./r5*ath;
// get the vertex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm)
throw InitException() << "Wrong type of StandardModel object in "
<< "MEPP2HiggsVBF::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
// set the vertex
setWWHVertex(hwsm->vertexWWH());
higgs(getParticleData(ParticleID::h0));
MEfftoffH::doinit();
}
void MEPP2HiggsVBF::dofinish() {
MEfftoffH::dofinish();
if(nover_==0) return;
generator()->log() << "VBFMECorrection when applying the hard correction "
<< nover_ << " weights larger than one were generated of which"
<< " the largest was " << maxwgt_.first << " for the QCD compton"
<< " processes and " << maxwgt_.second << " for the BGF process\n";
}
void MEPP2HiggsVBF::getDiagrams() const {
// get the quark particle data objects as we'll be using them
tcPDPtr q[6],qbar[6];
for ( int ix=0; ix<5; ++ix ) {
q [ix] = getParticleData(ix+1);
qbar[ix] = q[ix]->CC();
}
// WW processes
if(process()==0||process()==1) {
std::vector<pair<tcPDPtr,tcPDPtr> > parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxFlavour()) {
case 5:
if (minFlavour()<=4)
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::c)));
if (minFlavour()<=2)
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::u)));
+ [[fallthrough]];
case 4:
if (minFlavour()<=3)
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::c)));
if (minFlavour()<=1)
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::c)));
+ [[fallthrough]];
case 3:
if (minFlavour()<=2)
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::u)));
+ [[fallthrough]];
case 2:
if (minFlavour()<=1)
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::u)));
+ [[fallthrough]];
default:
;
}
for(unsigned int ix=0;ix<parentpair.size();++ix) {
for(unsigned int iy=0;iy<parentpair.size();++iy) {
// q1 q2 -> q1' q2' h
if(parentpair[ix].first->id()<parentpair[iy].second->id()) {
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(),
parentpair[iy].second, 1, parentpair[ix].second, 3,
parentpair[iy].first, 2, higgs(),-1)));
}
else {
add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second, WPlus(), WMinus(),
parentpair[ix].first, 1, parentpair[iy].first, 3,
parentpair[ix].second, 2, higgs(),-1)));
}
// q1 qbar2 -> q1' qbar2' h
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first, WMinus(), WPlus(),
parentpair[iy].first->CC(), 1,
parentpair[ix].second, 3, parentpair[iy].second->CC(),
2, higgs(),-1)));
add(new_ptr((Tree2toNDiagram(4),parentpair[iy].second, WPlus(), WMinus(),
parentpair[ix].second->CC(), 1, parentpair[iy].first,
3, parentpair[ix].first->CC(),
2, higgs(),-1)));
// qbar1 qbar2 -> qbar1' qbar2' h
if(parentpair[ix].first->id()<parentpair[ix].second->id()) {
add(new_ptr((Tree2toNDiagram(4), parentpair[ix].first->CC(), WPlus(), WMinus(),
parentpair[iy].second->CC(), 1,
parentpair[ix].second->CC(), 3, parentpair[iy].first->CC(),
2, higgs(),-1)));
}
else {
add(new_ptr((Tree2toNDiagram(4), parentpair[iy].second->CC(), WMinus(), WPlus(),
parentpair[ix].first->CC(), 1,
parentpair[iy].first->CC(), 3, parentpair[ix].second->CC(),
2, higgs(),-1)));
}
}
}
}
// ZZ processes
if(process()==0||process()==2) {
for(unsigned int ix=minFlavour()-1;ix<maxFlavour();++ix) {
for(unsigned int iy=ix;iy<maxFlavour();++iy) {
// q q -> q q H
add(new_ptr((Tree2toNDiagram(4), q[ix], Z0(), Z0(), q[iy],
1, q[ix], 3, q[iy], 2, higgs(),-2)));
// qbar qbar -> qbar qbar H
add(new_ptr((Tree2toNDiagram(4), qbar[ix], Z0(), Z0(), qbar[iy],
1, qbar[ix], 3, qbar[iy], 2, higgs(),-2)));
}
// q qbar -> q qbar H
for(unsigned int iy=minFlavour()-1;iy<maxFlavour();++iy) {
add(new_ptr((Tree2toNDiagram(4), q[ix], Z0(), Z0(), qbar[iy],
1, q[ix], 3, qbar[iy], 2, higgs(),-2)));
}
}
}
}
void MEPP2HiggsVBF::persistentOutput(PersistentOStream & os) const {
os << initial_ << final_
<< alpha_ << ounit(pTmin_,GeV) << comptonWeight_ << BGFWeight_ << gluon_
<< comptonInt_ << bgfInt_ << procProb_;
}
void MEPP2HiggsVBF::persistentInput(PersistentIStream & is, int) {
is >> initial_ >> final_
>> alpha_ >> iunit(pTmin_,GeV) >> comptonWeight_ >> BGFWeight_ >> gluon_
>> comptonInt_ >> bgfInt_ >> procProb_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEPP2HiggsVBF,MEfftoffH>
describeHerwigMEPP2HiggsVBF("Herwig::MEPP2HiggsVBF", "HwMEHadron.so");
void MEPP2HiggsVBF::Init() {
static ClassDocumentation<MEPP2HiggsVBF> documentation
("The MEPP2HiggsVBF class implements Higgs production via vector-boson fusion");
static Reference<MEPP2HiggsVBF,ShowerAlpha> interfaceShowerAlphaQCD
("ShowerAlphaQCD",
"The object calculating the strong coupling constant",
&MEPP2HiggsVBF::alpha_, false, false, true, false, false);
static Parameter<MEPP2HiggsVBF,Energy> interfacepTMin
("pTMin",
"The minimum pT",
&MEPP2HiggsVBF::pTmin_, GeV, 1.*GeV, 0.0*GeV, 10.0*GeV,
false, false, Interface::limited);
static Parameter<MEPP2HiggsVBF,double> interfaceComptonWeight
("ComptonWeight",
"Weight for the overestimate ofthe compton channel",
&MEPP2HiggsVBF::comptonWeight_, 50.0, 0.0, 100.0,
false, false, Interface::limited);
static Parameter<MEPP2HiggsVBF,double> interfaceBGFWeight
("BGFWeight",
"Weight for the overestimate of the BGF channel",
&MEPP2HiggsVBF::BGFWeight_, 100.0, 0.0, 1000.0,
false, false, Interface::limited);
static Parameter<MEPP2HiggsVBF,double> interfaceProcessProbability
("ProcessProbability",
"The probabilty of the QCD compton process for the process selection",
&MEPP2HiggsVBF::procProb_, 0.3, 0.0, 1.,
false, false, Interface::limited);
}
RealEmissionProcessPtr MEPP2HiggsVBF::generateHardest(RealEmissionProcessPtr born,
ShowerInteraction inter) {
// check if generating QCD radiation
if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD &&
inter!=ShowerInteraction::ALL)
return RealEmissionProcessPtr();
pair<tPPtr,tPPtr> first,second;
pair<tcBeamPtr,tcBeamPtr> beams;
pair<tPPtr,tPPtr> hadrons;
// get the incoming particles
for(unsigned int ix=0;ix<born->bornIncoming().size();++ix) {
if(!first.first) {
first.first = born->bornIncoming()[ix];
hadrons.first = born->hadrons()[ix];
beams.first = dynamic_ptr_cast<tcBeamPtr>(born->hadrons()[ix]->dataPtr());
}
else {
second.first = born->bornIncoming()[ix];
hadrons.second = born->hadrons()[ix];
beams.second = dynamic_ptr_cast<tcBeamPtr>(born->hadrons()[ix]->dataPtr());
}
}
// and the outgoing
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]->id()==ParticleID::h0) {
higgs_ = born->bornOutgoing()[ix];
}
else {
if(abs(born->bornOutgoing()[ix]->id())>5) continue;
if(born->bornOutgoing()[ix]->colourLine()&&
born->bornOutgoing()[ix]->colourLine()==first.first->colourLine()) {
first.second = born->bornOutgoing()[ix];
continue;
}
if(born->bornOutgoing()[ix]->antiColourLine()&&
born->bornOutgoing()[ix]->antiColourLine()==first.first->antiColourLine()) {
first.second = born->bornOutgoing()[ix];
continue;
}
if(born->bornOutgoing()[ix]->colourLine()&&
born->bornOutgoing()[ix]->colourLine()==second.first->colourLine()) {
second.second = born->bornOutgoing()[ix];
continue;
}
if(born->bornOutgoing()[ix]->antiColourLine()&&
born->bornOutgoing()[ix]->antiColourLine()==second.first->antiColourLine()) {
second.second = born->bornOutgoing()[ix];
continue;
}
}
}
// loop over the two possible emitting systems
q_ [0] = first .second->momentum()-first .first->momentum();
q2_[0] = -q_[0].m2();
q_ [1] = second.second->momentum()-second.first->momentum();
q2_[1] = -q_[1].m2();
for(unsigned int ix=0;ix<2;++ix) {
if(ix==1) {
swap(first,second);
swap(beams.first,beams.second);
swap(hadrons.first,hadrons.second);
}
// check beam, all particles
assert(beams.first && higgs_ &&
first .first && first.second &&
second.first && second.second);
// beam and pdf
beam_[ix] = beams.first;
pdf_ [ix] = beam_[ix]->pdf();
assert(beam_[ix] && pdf_[ix] );
// Particle data objects
partons_[ix][0] = first. first->dataPtr();
partons_[ix][1] = first.second->dataPtr();
partons_[ix][2] = second. first->dataPtr();
partons_[ix][3] = second.second->dataPtr();
// extract the born variables
xB_[ix] = first.first->momentum().rho()/hadrons.first->momentum().rho();
Lorentz5Momentum pb = first.first->momentum();
Axis axis(q_[ix].vect().unit());
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot_[ix] = LorentzRotation();
if(axis.perp2()>1e-20) {
rot_[ix].setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot_[ix].rotateX(Constants::pi);
}
if(abs(1.-q_[ix].e()/q_[ix].vect().mag())>1e-6)
rot_[ix].boostZ( q_[ix].e()/q_[ix].vect().mag());
pb *= rot_[ix];
if(pb.perp2()/GeV2>1e-20) {
Boost trans = -1./pb.e()*pb.vect();
trans.setZ(0.);
rot_[ix].boost(trans);
}
// momenta of the particles
phiggs_ [ix] = rot_[ix]*higgs_->momentum();
pother_ [ix][0] = rot_[ix]*second. first->momentum();
pother_ [ix][1] = rot_[ix]*second.second->momentum();
psystem_[ix][0] = rot_[ix]* first. first->momentum();
psystem_[ix][1] = rot_[ix]* first.second->momentum();
q_[ix] *= rot_[ix];
pTCompton_[ix] = pTBGF_[ix] = ZERO;
// generate a compton point
generateCompton(ix);
// generate a BGF point
generateBGF(ix);
}
// no valid emissions, return
if(pTCompton_[0]<ZERO && pTCompton_[1]<ZERO&&
pTBGF_ [0]<ZERO && pTBGF_ [1]<ZERO) {
born->pT()[ShowerInteraction::QCD] = pTmin_;
return born;
}
// find the maximum pT emission
unsigned int system = 0;
bool isCompton = false;
Energy pTmax = -GeV;
for(unsigned int ix=0;ix<2;++ix) {
if(pTCompton_[ix]>pTmax) {
pTmax = pTCompton_[ix];
isCompton = true;
system = ix;
}
if(pTBGF_[ix]>pTmax) {
pTmax = pTBGF_[ix];
isCompton = false;
system = ix;
}
}
if(system==0) {
swap(first,second);
swap(beams.first,beams.second);
swap(hadrons.first,hadrons.second);
}
// the non emitting particles
PPtr spectin =second.first ->dataPtr()->produceParticle(second.first ->momentum());
PPtr spectout=second.second->dataPtr()->produceParticle(second.second->momentum());
spectout->incomingColour(spectin,spectout->id()<0);
PPtr higgs = higgs_->dataPtr()->produceParticle(higgs_->momentum());
rot_[system].invert();
PPtr newout,newin,emitted;
bool FSR = false;
bool isQuark = first.first->colourLine();
// compton hardest
if(isCompton) {
for(unsigned int ix=0;ix<ComptonMomenta_[system].size();++ix) {
ComptonMomenta_[system][ix].transform(rot_[system]);
}
newout = partons_[system][1]->produceParticle(ComptonMomenta_[system][1]);
emitted = gluon_ ->produceParticle(ComptonMomenta_[system][2]);
newin = partons_[system][0]->produceParticle(ComptonMomenta_[system][0]);
FSR = !ComptonISFS_[system];
emitted->incomingColour(newin,!isQuark);
emitted->colourConnect(newout,!isQuark);
}
// BGF hardest
else {
for(unsigned int ix=0;ix<BGFMomenta_[system].size();++ix) {
BGFMomenta_[system][ix].transform(rot_[system]);
}
FSR = false;
newin = gluon_ ->produceParticle(BGFMomenta_[system][0]);
emitted = partons_[system][0]->CC()->produceParticle(BGFMomenta_[system][2]);
newout = partons_[system][1] ->produceParticle(BGFMomenta_[system][1]);
emitted->incomingColour(newin, isQuark);
newout ->incomingColour(newin,!isQuark);
}
pair<double,double> x;
pair<unsigned int,unsigned int> radiators;
if(born->bornIncoming()[0]!=first.first) {
born->incoming().push_back(spectin);
born->incoming().push_back(newin);
x.first = born->bornIncoming()[0]->momentum().rho()/born->hadrons()[0]->momentum().rho();
x.second = newin ->momentum().rho()/born->hadrons()[1]->momentum().rho();
radiators.first = 1;
}
else {
born->incoming().push_back(newin);
born->incoming().push_back(spectin);
x.first = newin ->momentum().rho()/born->hadrons()[0]->momentum().rho();
x.second = born->bornIncoming()[1]->momentum().rho()/born->hadrons()[1]->momentum().rho();
radiators.first = 0;
}
born->x(x);
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]==second.second) {
born->outgoing().push_back(spectout);
}
else if(born->bornOutgoing()[ix]==first.second) {
radiators.second = born->outgoing().size()+2;
born->outgoing().push_back(newout);
}
else
born->outgoing().push_back(higgs);
}
if(FSR) swap(radiators.first,radiators.second);
born->emitter (radiators.first );
born->spectator(radiators.second);
born->emitted(born->outgoing().size()+2);
// radiated particle
born->outgoing().push_back(emitted);
born->pT()[ShowerInteraction::QCD] = isCompton ? pTCompton_[system] : pTBGF_[system];
born->interaction(ShowerInteraction::QCD);
return born;
}
void MEPP2HiggsVBF::generateCompton(unsigned int system) {
// calculate the A coefficient for the correlations
acoeff_ = A(partons_[system][0],partons_[system][1],
partons_[system][2],partons_[system][3]);
// maximum value of the xT
double xT = sqrt((1.-xB_[system])/xB_[system]);
double xTMin = 2.*pTmin_/sqrt(q2_[system]);
double zp;
// prefactor
double a = alpha_->overestimateValue()*comptonWeight_/Constants::twopi;
// loop to generate kinematics
double wgt(0.),xp(0.);
l_ = 2.*pother_[system][0]/sqrt(q2_[system]);
m_ = 2.*pother_[system][1]/sqrt(q2_[system]);
vector<double> azicoeff;
do {
wgt = 0.;
// intergration variables dxT/xT^3
xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT));
// dz
zp = UseRandom::rnd();
xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp));
// check allowed
if(xp<xB_[system]||xp>1.) continue;
// phase-space piece of the weight
wgt = 8.*(1.-xp)*zp/comptonWeight_;
// PDF piece of the weight
Energy2 mu2 = q2_[system]*((1.-xp)*(1-zp)*zp/xp+1.);
double pdf = pdf_[system]->xfx(beam_[system],partons_[system][0],
mu2 ,xB_[system]/xp)/
pdf_[system]->xfx(beam_[system],partons_[system][0],
scale(),xB_[system] );
wgt *= max(pdf,0.);
// me piece of the weight
// double me = comptonME(system,xT,xp,zp,phi);
double x2 = 1.-(1.-zp)/xp;
azicoeff = ComptonME(xp,x2,xT,l_,m_);
double me = 4./3.*alpha_->ratio(0.25*q2_[system]*sqr(xT))*
(azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4]);
wgt *= me;
if(wgt>1.||wgt<-1e-8) {
ostringstream wstring;
wstring << "MEPP2HiggsVBF::generateCompton() "
<< "Weight greater than one or less than zero"
<< "wgt = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(xT>xTMin&&UseRandom::rnd()>wgt);
if(xT<=xTMin) {
pTCompton_[system]=-GeV;
return;
}
// generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi)),sphi(sin(phi));
phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi
+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
+azicoeff[3]*sphi+azicoeff[4]*sqr(sphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in MEPP2HiggsVBF"
<< "::generateCompton() to"
<< " generate phi" << Exception::eventerror;
// momenta for the configuration
Energy Q(sqrt(q2_[system]));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
pTCompton_[system] = 0.5*Q*xT;
ComptonMomenta_[system].resize(3);
ComptonMomenta_[system][0] = p0;
ComptonMomenta_[system][1] = p1;
ComptonMomenta_[system][2] = p2;
ComptonISFS_[system] = zp>xp;
}
double MEPP2HiggsVBF::comptonME(unsigned int system, double xT,
double xp, double zp, double phi) {
// scale and prefactors
double CFfact = 4./3.*alpha_->ratio(0.25*q2_[system]*sqr(xT));
Energy Q(sqrt(q2_[system]));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
//set NLO momenta
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
Lorentz5Momentum qnlo = p2+p1-p0;
// Breit frame variables
Lorentz5Momentum r1 = -p0/x1;
Lorentz5Momentum r2 = p1/x2;
// electroweak parameters
double c0L,c1L,c0R,c1R;
// W
if(partons_[system][0]->id()!=partons_[system][1]->id()) {
c0L = sqrt(0.5);
c0R = 0;
c1L = sqrt(0.5);
c1R = 0;
}
// Z
else {
if(abs(partons_[system][0]->id())%2==0) {
c0L =
generator()->standardModel()->vu()+
generator()->standardModel()->au();
c0R =
generator()->standardModel()->vu()-
generator()->standardModel()->au();
}
else {
c0L =
generator()->standardModel()->vd()+
generator()->standardModel()->ad();
c0R =
generator()->standardModel()->vd()-
generator()->standardModel()->ad();
}
if(abs(partons_[system][2]->id())%2==0) {
c1L =
generator()->standardModel()->vu()+
generator()->standardModel()->au();
c1R =
generator()->standardModel()->vu()-
generator()->standardModel()->au();
}
else {
c1L =
generator()->standardModel()->vd()+
generator()->standardModel()->ad();
c1R =
generator()->standardModel()->vd()-
generator()->standardModel()->ad();
}
c0L *= 0.25;
c0R *= 0.25;
c1L *= 0.25;
c1R *= 0.25;
}
// Matrix element variables
double G1 = sqr(c0L*c1L)+sqr(c0R*c1R);
double G2 = sqr(c0L*c1R)+sqr(c0R*c1L);
Energy4 term1,term2,loME;
if(partons_[system][0]->id()>0) {
if(partons_[system][2]->id()>0) {
term1 = loMatrixElement(r1 ,pother_[system][0],
qnlo+r1 ,pother_[system][1],G1,G2);
term2 = loMatrixElement(r2-qnlo ,pother_[system][0],
r2 ,pother_[system][1],G1,G2);
loME = loMatrixElement(psystem_[system][0],pother_[system][0],
psystem_[system][1],pother_[system][1],G1,G2);
}
else {
term1 = loMatrixElement(r1 ,pother_[system][1],
qnlo+r1 ,pother_[system][0],G1,G2);
term2 = loMatrixElement(r2-qnlo ,pother_[system][1],
r2 ,pother_[system][0],G1,G2);
loME = loMatrixElement(psystem_[system][0],pother_[system][1],
psystem_[system][1],pother_[system][0],G1,G2);
}
}
else {
if(partons_[system][2]->id()>0) {
term1 = loMatrixElement(qnlo+r1 ,pother_[system][0],
r1 ,pother_[system][1],G1,G2);
term2 = loMatrixElement(r2 ,pother_[system][0],
r2-qnlo ,pother_[system][1],G1,G2);
loME = loMatrixElement(psystem_[system][1],pother_[system][0],
psystem_[system][0],pother_[system][1],G1,G2);
}
else {
term1 = loMatrixElement(qnlo+r1,pother_[system][1],r1 ,
pother_[system][0],G1,G2);
term2 = loMatrixElement(r2 ,pother_[system][1],r2-qnlo,
pother_[system][0],G1,G2);
loME = loMatrixElement(psystem_[system][1],pother_[system][1],
psystem_[system][0],pother_[system][0],G1,G2);
}
}
double R1 = term1/loME;
double R2 = sqr(x2)/(sqr(x2)+sqr(xT))*(term2/loME);
// debuggingMatrixElement(false,
// partons_[system][0],partons_[system][1],
// partons_[system][2],partons_[system][3],
// psystem_[system][0],psystem_[system][1],
// pother_ [system][0],pother_ [system][1],
// p0,p1,p2,phiggs_[system],q2_[system],scale(),
// 8.*Constants::pi/(1.-xp)/(1.-zp)*(R1+sqr(xp)*(sqr(x2)+sqr(xT))*R2));
// cerr << "testing pieces A " << R1 << " " << sqr(xp)*(sqr(x2)+sqr(xT)) << " " << R2 << "\n";
return CFfact*(R1+sqr(xp)*(sqr(x2)+sqr(xT))*R2);
}
void MEPP2HiggsVBF::generateBGF(unsigned int system) {
// maximum value of the xT
double xT = (1.-xB_[system])/xB_[system];
double xTMin = 2.*pTmin_/sqrt(q2_[system]);
double zp;
// prefactor
double a = alpha_->overestimateValue()*BGFWeight_/Constants::twopi;
// loop to generate kinematics
double wgt(0.),xp(0.);
l_ = 2.*pother_[system][0]/sqrt(q2_[system]);
m_ = 2.*pother_[system][1]/sqrt(q2_[system]);
vector<double> azicoeff;
do {
wgt = 0.;
// intergration variables dxT/xT^3
xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT));
// dzp
zp = UseRandom::rnd();
xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp));
// check allowed
if(xp<xB_[system]||xp>1.) continue;
// phase-space piece of the weight
wgt = 8.*sqr(1.-xp)*zp/BGFWeight_;
// PDF piece of the weight
Energy2 mu2 = q2_[system]*((1.-xp)*(1-zp)*zp/xp+1.);
wgt *= pdf_[system]->xfx(beam_[system],gluon_ ,
mu2 ,xB_[system]/xp)/
pdf_[system]->xfx(beam_[system],partons_[system][0],
scale(),xB_[system]);
// me piece of the weight
//double me = BGFME(system,xT,xp,zp,phi);
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
azicoeff = BGFME(xp,x2,x3,xT,l_,m_);
double me = 0.5*alpha_->ratio(0.25*q2_[system]*sqr(xT))*
(azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4]);
wgt *= me;
if(wgt>1.||wgt<-1e-8) {
ostringstream wstring;
wstring << "MEPP2HiggsVBF::generateBGF() "
<< "Weight greater than one or less than zero"
<< "wgt = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(xT>xTMin&&UseRandom::rnd()>wgt);
if(xT<=xTMin) {
pTBGF_[system] = -GeV;
return;
}
// generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi)),sphi(sin(phi));
phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi
+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
+azicoeff[3]*sphi+azicoeff[4]*sqr(sphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in MEPP2HiggsVBF"
<< "::generateBGF() to"
<< " generate phi" << Exception::eventerror;
// momenta for the configuration
Energy Q(sqrt(q2_[system]));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
pTBGF_[system] = 0.5*Q*xT;
BGFMomenta_[system].resize(3);
BGFMomenta_[system][0] = p0;
BGFMomenta_[system][1] = p1;
BGFMomenta_[system][2] = p2;
}
double MEPP2HiggsVBF::BGFME(unsigned int system, double xT,
double xp, double zp, double phi) {
// scale and prefactors
double TRfact = 0.5*alpha_->ratio(0.25*q2_[system]*sqr(xT));
Energy Q(sqrt(q2_[system]));
double x1 = -1./xp;
double x2 = 1.-(1.-zp)/xp;
double x3 = 2.+x1-x2;
// Set NLO momenta
Lorentz5Momentum p1( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi),
-0.5*Q*x2, 0.5*Q*sqrt(sqr(xT)+sqr(x2)));
Lorentz5Momentum p2(-0.5*Q*xT*cos(phi), -0.5*Q*xT*sin(phi),
-0.5*Q*x3, 0.5*Q*sqrt(sqr(xT)+sqr(x3)));
Lorentz5Momentum p0(ZERO,ZERO,-0.5*Q*x1,-0.5*Q*x1);
Lorentz5Momentum qnlo = p2+p1-p0;
// Breit frame variables
Lorentz5Momentum r2 = p1/x2;
Lorentz5Momentum r3 = -p2/x3;
// electroweak parameters
double c0L,c1L,c0R,c1R;
// W
if(partons_[system][0]->id()!=partons_[system][1]->id()) {
c0L = sqrt(0.5);
c0R = 0;
c1L = sqrt(0.5);
c1R = 0;
}
// Z
else {
if(abs(partons_[system][0]->id())%2==0) {
c0L =
generator()->standardModel()->vu()+
generator()->standardModel()->au();
c0R =
generator()->standardModel()->vu()-
generator()->standardModel()->au();
}
else {
c0L =
generator()->standardModel()->vd()+
generator()->standardModel()->ad();
c0R =
generator()->standardModel()->vd()-
generator()->standardModel()->ad();
}
if(abs(partons_[system][2]->id())%2==0) {
c1L =
generator()->standardModel()->vu()+
generator()->standardModel()->au();
c1R =
generator()->standardModel()->vu()-
generator()->standardModel()->au();
}
else {
c1L =
generator()->standardModel()->vd()+
generator()->standardModel()->ad();
c1R =
generator()->standardModel()->vd()-
generator()->standardModel()->ad();
}
c0L *= 0.25;
c0R *= 0.25;
c1L *= 0.25;
c1R *= 0.25;
}
// Matrix element variables
double G1 = sqr(c0L*c1L)+sqr(c0R*c1R);
double G2 = sqr(c0L*c1R)+sqr(c0R*c1L);
Energy4 term2,term3,loME;
if(partons_[system][0]->id()>0) {
if(partons_[system][2]->id()>0) {
term2 = loMatrixElement(r2-qnlo,pother_[system][0],
r2 ,pother_[system][1],G1,G2);
term3 = loMatrixElement(r3 ,pother_[system][0],
qnlo+r3,pother_[system][1],G1,G2);
loME = loMatrixElement(psystem_[system][0],pother_[system][0],
psystem_[system][1],pother_[system][1],G1,G2);
}
else {
term2 = loMatrixElement(r2-qnlo,pother_[system][1],
r2 ,pother_[system][0],G1,G2);
term3 = loMatrixElement(r3 ,pother_[system][1],
qnlo+r3,pother_[system][0],G1,G2);
loME = loMatrixElement(psystem_[system][0],pother_[system][1],
psystem_[system][1],pother_[system][0],G1,G2);
}
}
else {
if(partons_[system][2]->id()>0) {
term2 = loMatrixElement(r2 ,pother_[system][0],
r2-qnlo,pother_[system][1],G1,G2);
term3 = loMatrixElement(qnlo+r3,pother_[system][0],
r3 ,pother_[system][1],G1,G2);
loME = loMatrixElement(psystem_[system][1],pother_[system][0],
psystem_[system][0],pother_[system][1],G1,G2);
}
else {
term2 = loMatrixElement(r2 ,pother_[system][1],
r2-qnlo,pother_[system][0],G1,G2);
term3 = loMatrixElement(qnlo+r3,pother_[system][1],
r3 ,pother_[system][0],G1,G2);
loME = loMatrixElement(psystem_[system][1],pother_[system][1],
psystem_[system][0],pother_[system][0],G1,G2);
}
}
double R3 = sqr(x3)/(sqr(x3)+sqr(xT))*(term3/loME);
double R2 = sqr(x2)/(sqr(x2)+sqr(xT))*(term2/loME);
// debuggingMatrixElement(true,
// partons_[system][0],partons_[system][1],
// partons_[system][2],partons_[system][3],
// psystem_[system][0],psystem_[system][1],
// pother_ [system][0],pother_ [system][1],
// p0,p1,p2,phiggs_[system],q2_[system],
// 8.*Constants::pi/zp/(1.-zp)*(sqr(xp)*(sqr(x3)+sqr(xT))*R3+
// sqr(xp)*(sqr(x2)+sqr(xT))*R2));
return TRfact*
(sqr(xp)*(sqr(x3)+sqr(xT))*R3+
sqr(xp)*(sqr(x2)+sqr(xT))*R2);
}
Energy4 MEPP2HiggsVBF::loMatrixElement(const Lorentz5Momentum &p1,
const Lorentz5Momentum &p2,
const Lorentz5Momentum &q1,
const Lorentz5Momentum &q2,
double G1, double G2) const {
return G1*(p1*p2)*(q1*q2) + G2*(p1*q2)*(q1*p2);
}
void MEPP2HiggsVBF::initializeMECorrection(RealEmissionProcessPtr born,
double & initial,
double & final) {
systems_.clear();
for(unsigned int ix=0;ix<born->bornIncoming().size();++ix) {
if(QuarkMatcher::Check(born->bornIncoming()[ix]->data())) {
systems_.push_back(tChannelPair());
systems_.back().hadron = born->hadrons()[ix];
systems_.back().beam = dynamic_ptr_cast<tcBeamPtr>(systems_.back().hadron->dataPtr());
systems_.back().incoming = born->bornIncoming()[ix];
systems_.back().pdf = systems_.back().beam->pdf();
}
}
vector<PPtr> outgoing;
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]->id()==ParticleID::h0)
higgs_ = born->bornOutgoing()[ix];
else if(QuarkMatcher::Check(born->bornOutgoing()[ix]->data()))
outgoing.push_back(born->bornOutgoing()[ix]);
}
assert(outgoing.size()==2&&higgs_);
// match up the quarks
for(unsigned int ix=0;ix<systems_.size();++ix) {
if(systems_[ix].incoming->colourLine()) {
for(unsigned int iy=0;iy<outgoing.size();++iy) {
if(outgoing[iy]->colourLine()==systems_[ix].incoming->colourLine()) {
systems_[ix].outgoing=outgoing[iy];
break;
}
}
}
else {
for(unsigned int iy=0;iy<outgoing.size();++iy) {
if(outgoing[iy]->antiColourLine()==systems_[ix].incoming->antiColourLine()) {
systems_[ix].outgoing=outgoing[iy];
break;
}
}
}
}
assert(systems_[0].outgoing&&systems_[1].outgoing);
assert(systems_.size()==2);
initial = initial_;
final = final_;
}
RealEmissionProcessPtr MEPP2HiggsVBF::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) {
static const double eps = 1e-6;
// select emitting line
if(UseRandom::rndbool()) swap(systems_[0],systems_[1]);
// extract the born variables
q_[0] = systems_[0].outgoing->momentum()-systems_[0].incoming->momentum();
q2_[0] = -q_[0].m2();
Energy Q = sqrt(q2_[0]);
xB_[0] = systems_[0].incoming->momentum().rho()/systems_[0].hadron->momentum().rho();
// construct lorentz transform from lab to breit frame
Lorentz5Momentum phadron = systems_[0].hadron->momentum();
phadron.setMass(0.*GeV);
phadron.rescaleEnergy();
Lorentz5Momentum pcmf = phadron+0.5/xB_[0]*q_[0];
pcmf.rescaleMass();
LorentzRotation rot(-pcmf.boostVector());
Lorentz5Momentum pbeam = rot*phadron;
Axis axis(pbeam.vect().unit());
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
Lorentz5Momentum pout = rot*(systems_[1].outgoing->momentum()+higgs_->momentum());
rot.rotateZ(-atan2(pout.y(),pout.x()));
// calculate the A coefficient for the correlations
acoeff_ = A(systems_[0].incoming->dataPtr(),systems_[0].outgoing->dataPtr(),
systems_[1].incoming->dataPtr(),systems_[1].outgoing->dataPtr());
vector<double> azicoeff;
// select the type of process
bool BGF = UseRandom::rnd()>procProb_;
double wgt,xp,zp,x1,x2,x3,xperp;
l_ = 2.*(rot*systems_[1].incoming->momentum())/Q;
m_ = 2.*(rot*systems_[1].outgoing->momentum())/Q;
// compton process
if(!BGF) {
wgt = generateComptonPoint(xp,zp);
if(xp<eps) return RealEmissionProcessPtr();
// common pieces
Energy2 mu2 = q2_[0]*((1.-xp)*(1-zp)*zp/xp+1);
wgt *= 2./3./Constants::pi*alpha_->value(mu2)/procProb_;
// PDF piece
wgt *= systems_[0].pdf->xfx(systems_[0].beam,
systems_[0].incoming->dataPtr(),mu2 ,xB_[0]/xp)/
systems_[0].pdf->xfx(systems_[0].beam,
systems_[0].incoming->dataPtr(),scale(),xB_[0] );
// numerator factors
wgt /= (1.-xp)*(1.-zp);
// other bits
xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
x1 = -1./xp;
x2 = 1.-(1.-zp)/xp;
x3 = 2.+x1-x2;
// matrix element pieces
azicoeff = ComptonME(xp,x2,xperp,l_,m_);
}
else {
wgt = generateBGFPoint(xp,zp);
if(xp<1e-6) return RealEmissionProcessPtr();
// common pieces
Energy2 mu2 = q2_[0]*((1.-xp)*(1-zp)*zp/xp+1);
wgt *= 0.25/Constants::pi*alpha_->value(mu2)/(1.-procProb_);
// PDF piece
wgt *= systems_[0].pdf->xfx(systems_[0].beam,
gluon_ ,mu2 ,xB_[0]/xp)/
systems_[0].pdf->xfx(systems_[0].beam,
systems_[0].incoming->dataPtr(),scale(),xB_[0] );
// numerator factors
wgt /= (1.-zp);
// other bits
xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
x1 = -1./xp;
x2 = 1.-(1.-zp)/xp;
x3 = 2.+x1-x2;
// matrix element pieces
azicoeff = BGFME(xp,x2,x3,xperp,l_,m_);
}
// compute the azimuthal average of the weight
wgt *= azicoeff[0]+0.5*(azicoeff[2]+azicoeff[4]);
// finally factor as picked one line
wgt *= 2.;
// decide whether or not to accept the weight
if(UseRandom::rnd()>wgt) return RealEmissionProcessPtr();
// if accepted generate generate phi
unsigned int itry(0);
double phimax = std::accumulate(azicoeff.begin(),azicoeff.end(),0.);
double phiwgt,phi;
do {
phi = UseRandom::rnd()*Constants::twopi;
double cphi(cos(phi)),sphi(sin(phi));
phiwgt = azicoeff[0]+azicoeff[5]*sphi*cphi
+azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
+azicoeff[3]*sphi+azicoeff[4]*sqr(sphi);
++itry;
}
while (phimax*UseRandom::rnd() > phiwgt && itry<200);
if(itry==200) throw Exception() << "Too many tries in VBFMECorrection"
<< "::applyHardMatrixElementCorrection() to"
<< " generate phi" << Exception::eventerror;
// compute the new incoming and outgoing momenta
Lorentz5Momentum p1 = Lorentz5Momentum( 0.5*Q*xperp*cos(phi), 0.5*Q*xperp*sin(phi),
-0.5*Q*x2,0.*GeV,0.*GeV);
p1.rescaleEnergy();
Lorentz5Momentum p2 = Lorentz5Momentum(-0.5*Q*xperp*cos(phi),-0.5*Q*xperp*sin(phi),
-0.5*Q*x3,0.*GeV,0.*GeV);
p2.rescaleEnergy();
Lorentz5Momentum pin(0.*GeV,0.*GeV,-0.5*x1*Q,-0.5*x1*Q,0.*GeV);
// debugging code to test vs helicity amplitude expression for matrix elements
// double cphi(cos(phi)),sphi(sin(phi));
// double old = (azicoeff[0]+azicoeff[5]*sphi*cphi
// +azicoeff[1]*cphi+azicoeff[2]*sqr(cphi)
// +azicoeff[3]*sphi+azicoeff[4]*sqr(sphi));
// if(!BGF) {
// old *= 8.*Constants::pi/(1.-xp)/(1.-zp);
// }
// else {
// old *= 8.*Constants::pi/zp/(1.-zp);
// }
// debuggingMatrixElement(BGF,
// systems_[0].incoming->dataPtr(),
// systems_[0].outgoing->dataPtr(),
// systems_[1].incoming->dataPtr(),
// systems_[1].outgoing->dataPtr(),
// rot*systems_[0].incoming->momentum(),
// rot*systems_[0].outgoing->momentum(),
// rot*systems_[1].incoming->momentum(),
// rot*systems_[1].outgoing->momentum(),
// pin,p1,p2,rot*higgs_->momentum(),
// q2_[0],scale(),old);
// we need inverse of the rotation, i.e back to lab from breit
rot.invert();
// transform the momenta to lab frame
pin *= rot;
p1 *= rot;
p2 *= rot;
// test to ensure outgoing particles can be put on-shell
if(!BGF) {
if(p1.e()<systems_[0].outgoing->dataPtr()->constituentMass()) return RealEmissionProcessPtr();
if(p2.e()<gluon_ ->constituentMass()) return RealEmissionProcessPtr();
}
else {
if(p1.e()<systems_[0].outgoing->dataPtr() ->constituentMass()) return RealEmissionProcessPtr();
if(p2.e()<systems_[0].incoming->dataPtr()->CC()->constituentMass()) return RealEmissionProcessPtr();
}
// stats for weights > 1
if(wgt>1.) {
++nover_;
if(!BGF) maxwgt_.first = max(maxwgt_.first ,wgt);
else maxwgt_.second = max(maxwgt_.second,wgt);
}
// create the new particles and add to ShowerTree
bool isQuark = systems_[0].incoming->colourLine();
bool FSR= false;
PPtr newin,newout,emitted;
if(!BGF) {
newin = systems_[0].incoming->dataPtr()->produceParticle(pin);
emitted = gluon_ ->produceParticle(p2 );
newout = systems_[0].outgoing->dataPtr()->produceParticle(p1 );
emitted->incomingColour(newin,!isQuark);
emitted->colourConnect(newout,!isQuark);
FSR = xp>zp;
}
else {
newin = gluon_ ->produceParticle(pin);
emitted = systems_[0].incoming->dataPtr()->CC()->produceParticle(p2 );
newout = systems_[0].outgoing->dataPtr() ->produceParticle(p1 );
emitted->incomingColour(newin, isQuark);
newout ->incomingColour(newin,!isQuark);
FSR = false;
}
pair<double,double> x;
pair<unsigned int,unsigned int> radiators;
if(born->bornIncoming()[0]!=systems_[0].incoming) {
born->incoming().push_back(born->bornIncoming()[0]);
born->incoming().push_back(newin);
x.first = born->bornIncoming()[0]->momentum().rho()/born->hadrons()[0]->momentum().rho();
x.second = x.first = xB_[0]/xp;
radiators.first = 1;
}
else {
born->incoming().push_back(newin);
born->incoming().push_back(born->bornIncoming()[1]);
x.first = xB_[0]/xp;
x.second = born->bornIncoming()[1]->momentum().rho()/born->hadrons()[1]->momentum().rho();
radiators.first = 0;
}
born->x(x);
for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) {
if(born->bornOutgoing()[ix]!=systems_[0].outgoing) {
born->outgoing().push_back(born->bornOutgoing()[ix]);
}
else {
radiators.second = born->outgoing().size()+2;
born->outgoing().push_back(newout);
}
}
if(FSR) swap(radiators.first,radiators.second);
born->emitter (radiators.first );
born->spectator(radiators.second);
born->emitted(born->outgoing().size()+2);
// radiated particle
born->outgoing().push_back(emitted);
born->interaction(ShowerInteraction::QCD);
return born;
}
double MEPP2HiggsVBF::A(tcPDPtr qin1, tcPDPtr qout1,
tcPDPtr qin2, tcPDPtr ) {
double output;
// charged current
if(qin1->id()!=qout1->id()) {
output = 2;
}
// neutral current
else {
double cvl,cal,cvq,caq;
if(abs(qin2->id())%2==0) {
cvl = generator()->standardModel()->vu();
cal = generator()->standardModel()->au();
}
else {
cvl = generator()->standardModel()->vd();
cal = generator()->standardModel()->ad();
}
if(abs(qin1->id())%2==0) {
cvq = generator()->standardModel()->vu();
caq = generator()->standardModel()->au();
}
else {
cvq = generator()->standardModel()->vd();
caq = generator()->standardModel()->ad();
}
output = 8.*cvl*cal*cvq*caq/(sqr(cvl)+sqr(cal))/(sqr(cvq)+sqr(caq));
}
if(qin1->id()<0) output *= -1.;
if(qin2->id()<0) output *= -1;
return output;
}
double MEPP2HiggsVBF::generateComptonPoint(double &xp, double & zp) {
static const double maxwgt = 50.;
double wgt,xperp2,x2;
do {
xp = UseRandom::rnd();
double zpmin = xp, zpmax = 1./(1.+xp*(1.-xp));
zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
if(UseRandom::rndbool()) swap(xp,zp);
xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp;
x2 = 1.-(1.-zp)/xp;
wgt *= 2.*(1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp);
if(wgt>maxwgt)
if(wgt>maxwgt) {
ostringstream wstring;
wstring << "MEPP2HiggsVBF::generateComptonPoint() "
<< "Weight greater than maximum"
<< "wgt = " << wgt << " maxwgt = " << maxwgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(wgt<UseRandom::rnd()*maxwgt);
return comptonInt_/((1.+sqr(xp)*(sqr(x2)+1.5*xperp2))/(1.-xp)/(1.-zp));
}
double MEPP2HiggsVBF::generateBGFPoint(double &xp, double & zp) {
static const double maxwgt = 25.;
double wgt;
double x2,x3,xperp2;
do {
xp = UseRandom::rnd();
double zpmax = 1./(1.+xp*(1.-xp)), zpmin = 1.-zpmax;
zp = 1.-pow((1.-zpmin)/(1.-zpmax),UseRandom::rnd())*(1.-zpmax);
wgt = log((1.-zpmin)/(1.-zpmax))*(1.-zp);
double x1 = -1./xp;
x2 = 1.-(1.-zp)/xp;
x3 = 2.+x1-x2;
xperp2 = 4.*(1.-xp)*(1.-zp)*zp/xp;
wgt *= sqr(xp)/(1.-zp)*(sqr(x3)+sqr(x2)+3.*xperp2);
if(wgt>maxwgt) {
ostringstream wstring;
wstring << "DISBase::generateBGFPoint "
<< "Weight greater than maximum "
<< "wgt = " << wgt << " maxwgt = 1\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
while(wgt<UseRandom::rnd()*maxwgt);
return bgfInt_/sqr(xp)*(1.-zp)/(sqr(x3)+sqr(x2)+3.*xperp2);
}
bool MEPP2HiggsVBF::softMatrixElementVeto(PPtr parent,
PPtr progenitor,
const bool & fs,
const Energy & highestpT,
const vector<tcPDPtr> & ids,
const double & z,
const Energy & scale,
const Energy & pT) {
bool veto = !UseRandom::rndbool(fs ? 1./final_ : 1./initial_);
// check if me correction should be applied
long id[2]={progenitor->id(),parent->id()};
if(id[0]!=id[1]||id[1]==ParticleID::g) return veto;
// if not from the right side
if(progenitor!=systems_[0].incoming &&
progenitor!=systems_[0].outgoing) return veto;
// check if hardest so far
if(pT<highestpT) return veto;
double kappa(sqr(scale)/q2_[0]);
double zk((1.-z)*kappa);
// final-state
double wgt(0.);
if(fs) {
double zp=z,xp=1./(1.+z*zk);
double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
double x2 = 1.-(1.-zp)/xp;
vector<double> azicoeff = ComptonME(xp,x2,xperp,l_,m_);
wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])*
xp/(1.+sqr(z))/final_;
if(wgt<.0||wgt>1.) {
ostringstream wstring;
wstring << "Soft ME correction weight too large or "
<< "negative for FSR in MEPP2HiggsVBF::"
<< "softMatrixElementVeto() soft weight "
<< " xp = " << xp << " zp = " << zp
<< " weight = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
else {
double xp = 2.*z/(1.+zk+sqrt(sqr(1.+zk)-4.*z*zk));
double zp = 0.5* (1.-zk+sqrt(sqr(1.+zk)-4.*z*zk));
double xperp = sqrt(4.*(1.-xp)*(1.-zp)*zp/xp);
double x1 = -1./xp, x2 = 1.-(1.-zp)/xp, x3 = 2.+x1-x2;
// compton
if(ids[0]->id()!=ParticleID::g) {
vector<double> azicoeff = ComptonME(xp,x2,xperp,l_,m_);
wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])*
xp*(1.-z)/(1.-xp)/(1.+sqr(z))/(1.-zp+xp-2.*xp*(1.-zp));
}
// BGF
else {
vector<double> azicoeff = BGFME(xp,x2,x3,xperp,l_,m_);
wgt = (azicoeff[0]+0.5*azicoeff[2]+0.5*azicoeff[4])*
xp/(1.-zp+xp-2.*xp*(1.-zp))/(sqr(z)+sqr(1.-z));
}
wgt /=initial_;
if(wgt<.0||wgt>1.) {
ostringstream wstring;
wstring << "Soft ME correction weight too large or "
<< "negative for ISR in MEPP2HiggsVBF::"
<< "softMatrixElementVeto() soft weight "
<< " xp = " << xp << " zp = " << zp
<< " weight = " << wgt << "\n";
generator()->logWarning( Exception(wstring.str(),
Exception::warning) );
}
}
// return whether or not vetoed
return !UseRandom::rndbool(wgt);
}
vector<double> MEPP2HiggsVBF::ComptonME(double xp, double x2, double xperp,
LorentzVector<double> l,
LorentzVector<double> m) {
vector<double> output(6,0.);
double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
// no phi dependence
output[0] = l.t()*m.t()-l.z()*m.z()*sqr(cos2)+0.5*acoeff_*cos2*(l.t()*m.z()-l.z()*m.t());
// cos(phi)
output[1] = sin2*(-l.x()*m.t()-l.t()*m.x()
+ 0.5*acoeff_*cos2*(l.z()*m.x()-m.z()*l.x()));
// cos(phi)^2
output[2] = +sqr(sin2)*l.x()*m.x();
// sin(phi)
output[3] = sin2*(-l.t()*m.y()-l.y()*m.t()
+ 0.5*acoeff_*cos2*(l.z()*m.y()-m.z()*l.y()));
// sin(phi)^2
output[4] = +sqr(sin2)*l.y()*m.y();
// sin(phi)cos(phi)
output[5] = +sqr(sin2)*(m.y()*l.x()+m.x()*l.y());
// additional factors
double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff_*(l.t()*m.z()-l.z()*m.t());
double fact = sqr(xp)*(sqr(x2)+sqr(xperp))/denom;
for(unsigned int ix=0;ix<output.size();++ix) output[ix] *=fact;
output[0] += 1.;
return output;
}
vector<double> MEPP2HiggsVBF::BGFME(double xp, double x2, double x3,
double xperp,
LorentzVector<double> l,
LorentzVector<double> m) {
vector<double> output(6,0.);
double denom = -l.z()*m.z()+l.t()*m.t()+0.5*acoeff_*(l.t()*m.z()-l.z()*m.t());
double cos2 = x2 /sqrt(sqr(x2)+sqr(xperp));
double sin2 = xperp/sqrt(sqr(x2)+sqr(xperp));
double fact2 = sqr(xp)*(sqr(x2)+sqr(xperp))/denom;
double cos3 = x3 /sqrt(sqr(x3)+sqr(xperp));
double sin3 = xperp/sqrt(sqr(x3)+sqr(xperp));
double fact3 = sqr(xp)*(sqr(x3)+sqr(xperp))/denom;
// no phi dependence
output[0] =
fact2*(l.t()*m.t()-l.z()*m.z()*sqr(cos2)
+ 0.5*acoeff_*cos2*(l.t()*m.z()-l.z()*m.t())) +
fact3*(l.t()*m.t()-l.z()*m.z()*sqr(cos3)
- 0.5*acoeff_*cos3*(l.t()*m.z()-l.z()*m.t()));
// cos(phi)
output[1] =
fact2*sin2*( - l.x()*m.t()-l.t()*m.x()
+ 0.5*acoeff_*cos2*(l.z()*m.x()-m.z()*l.x())) -
fact3*sin3*( - l.x()*m.t()-l.t()*m.x()
- 0.5*acoeff_*cos3*(l.z()*m.x()-m.z()*l.x())) ;
// cos(phi)^2
output[2] = (fact2*sqr(sin2)+fact3*sqr(sin3))*l.x()*m.x();
// sin(phi)
output[3] =
fact2*sin2*( - l.t()*m.y()-l.y()*m.t()
+ 0.5*acoeff_*cos2*(l.z()*m.y()-m.z()*l.y())) -
fact3*sin3*( - l.t()*m.y()-l.y()*m.t()
- 0.5*acoeff_*cos3*(l.z()*m.y()-m.z()*l.y()));
// sin(phi)^2
output[4] = (fact2*sqr(sin2)+fact3*sqr(sin3))*l.y()*m.y();
// sin(phi)cos(phi)
output[5] = (fact2*sqr(sin2)+fact3*sqr(sin3))*(m.y()*l.x()+m.x()*l.y());
// return the answer
return output;
}
diff --git a/MatrixElement/Hadron/MEPP2QQHiggs.cc b/MatrixElement/Hadron/MEPP2QQHiggs.cc
--- a/MatrixElement/Hadron/MEPP2QQHiggs.cc
+++ b/MatrixElement/Hadron/MEPP2QQHiggs.cc
@@ -1,636 +1,636 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2QQH class.
//
#include "MEPP2QQHiggs.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "Herwig/Utilities/Kinematics.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2QQHiggs::MEPP2QQHiggs() : quarkFlavour_(6), process_(0), shapeOpt_(2),
mh_(), wh_(), alpha_(1.1)
{}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEPP2QQHiggs,HwMEBase>
describeHerwigMEPP2QQHiggs("Herwig::MEPP2QQHiggs", "HwMEHadron.so");
void MEPP2QQHiggs::Init() {
static ClassDocumentation<MEPP2QQHiggs> documentation
("The MEPP2QQHiggs class implements the matrix elements for the "
"production of the Higgs boson in association with a heavy quark-antiquark pair");
static Switch<MEPP2QQHiggs,unsigned int> interfaceQuarkType
("QuarkType",
"The type of quark",
&MEPP2QQHiggs::quarkFlavour_, 6, false, false);
static SwitchOption interfaceQuarkTypeBottom
(interfaceQuarkType,
"Bottom",
"Produce bottom-antibottom",
5);
static SwitchOption interfaceQuarkTypeTop
(interfaceQuarkType,
"Top",
"Produce top-antitop",
6);
static Switch<MEPP2QQHiggs,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEPP2QQHiggs::process_, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcess1
(interfaceProcess,
"gg",
"Include only gg -> QQbarH processes",
1);
static SwitchOption interfaceProcessqbarqbarqbarqbar
(interfaceProcess,
"qqbar",
"Include only qbar qbar -> QQbarH processes",
2);
static Switch<MEPP2QQHiggs,unsigned int> interfaceShapeOption
("ShapeScheme",
"Option for the treatment of the Higgs resonance shape",
&MEPP2QQHiggs::shapeOpt_, 2, false, false);
static SwitchOption interfaceStandardShapeFixed
(interfaceShapeOption,
"FixedBreitWigner",
"Breit-Wigner s-channel resonance",
1);
static SwitchOption interfaceStandardShapeRunning
(interfaceShapeOption,
"MassGenerator",
"Use the mass generator to give the shape",
2);
static SwitchOption interfaceStandardShapeOnShell
(interfaceShapeOption,
"OnShell",
"Produce an on-shell Higgs boson",
0);
static Parameter<MEPP2QQHiggs,double> interfaceAlpha
("Alpha",
"Power for the generation of the tranverse mass in the pT mapping",
&MEPP2QQHiggs::alpha_, 1.1, 0.0, 10.0,
false, false, Interface::limited);
}
Energy2 MEPP2QQHiggs::scale() const {
return sHat();
// return sqr(mePartonData()[2]->mass()+mePartonData()[3]->mass()+
// mePartonData()[4]->mass());
}
int MEPP2QQHiggs::nDim() const {
return 4 + int(shapeOpt_>0);
}
unsigned int MEPP2QQHiggs::orderInAlphaS() const {
return 2;
}
unsigned int MEPP2QQHiggs::orderInAlphaEW() const {
return 1;
}
IBPtr MEPP2QQHiggs::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2QQHiggs::fullclone() const {
return new_ptr(*this);
}
void MEPP2QQHiggs::setKinematics() {
HwMEBase::setKinematics();
}
void MEPP2QQHiggs::persistentOutput(PersistentOStream & os) const {
os << quarkFlavour_ << process_ << shapeOpt_
<< ounit(mh_,GeV) << ounit(wh_,GeV) << hmass_
<< GGGVertex_ << QQGVertex_ << QQHVertex_
<< gluon_ << higgs_ << quark_ << antiquark_
<< alpha_;
}
void MEPP2QQHiggs::persistentInput(PersistentIStream & is, int) {
is >> quarkFlavour_ >> process_ >> shapeOpt_
>> iunit(mh_,GeV) >> iunit(wh_,GeV) >> hmass_
>> GGGVertex_ >> QQGVertex_ >> QQHVertex_
>> gluon_ >> higgs_ >> quark_ >> antiquark_
>> alpha_;
}
void MEPP2QQHiggs::doinit() {
HwMEBase::doinit();
// stuff for the higgs mass
higgs_=getParticleData(ParticleID::h0);
mh_ = higgs_->mass();
wh_ = higgs_->width();
if(higgs_->massGenerator()) {
hmass_=dynamic_ptr_cast<GenericMassGeneratorPtr>(higgs_->massGenerator());
}
if(shapeOpt_==2&&!hmass_)
throw InitException()
<< "If using the mass generator for the line shape in MEPP2QQHiggs::doinit()"
<< "the mass generator must be an instance of the GenericMassGenerator class"
<< Exception::runerror;
// get the vertex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(!hwsm) throw InitException() << "Wrong type of StandardModel object in "
<< "MEPP2QQHiggs::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
GGGVertex_ = hwsm->vertexGGG();
QQGVertex_ = hwsm->vertexFFG();
QQHVertex_ = hwsm->vertexFFH();
// get the particle data objects
gluon_=getParticleData(ParticleID::g);
for(int ix=1;ix<=6;++ix) {
quark_.push_back( getParticleData( ix));
antiquark_.push_back(getParticleData(-ix));
}
}
bool MEPP2QQHiggs::generateKinematics(const double * r) {
jacobian(1.);
// CMS energy
Energy rs = sqrt(sHat());
// quark mass
Energy mq(quark_[quarkFlavour_-1]->mass());
// generate the higgs mass
Energy mh(mh_);
if(shapeOpt_!=0) {
Energy mhmax = min(rs-2.*mq,higgs_->massMax());
Energy mhmin = max(ZERO ,higgs_->massMin());
if(mhmax<=mhmin) return false;
double rhomin = atan2((sqr(mhmin)-sqr(mh_)), mh_*wh_);
double rhomax = atan2((sqr(mhmax)-sqr(mh_)), mh_*wh_);
mh = sqrt(mh_*wh_*tan(rhomin+r[4]*(rhomax-rhomin))+sqr(mh_));
jacobian(jacobian()*(rhomax-rhomin));
}
if(rs<mh+2.*mq) return false;
// limits for virtual quark mass
Energy2 mmin(sqr(mq+mh)),mmax(sqr(rs-mq));
double rhomin,rhomax;
if(alpha_==0.) {
rhomin = mmin/sqr(mq);
rhomax = mmax/sqr(mq);
}
else if(alpha_==1.) {
rhomax = log((mmax-sqr(mq))/sqr(mq));
rhomin = log((mmin-sqr(mq))/sqr(mq));
}
else {
rhomin = pow((mmax-sqr(mq))/sqr(mq),1.-alpha_);
rhomax = pow((mmin-sqr(mq))/sqr(mq),1.-alpha_);
jacobian(jacobian()/(alpha_-1.));
}
// branch for mass smoothing
Energy2 m132,m232;
Energy p1,p2;
// first branch
if(r[1]<=0.5) {
double rtemp = 2.*r[1];
double rho = rhomin+rtemp*(rhomax-rhomin);
if(alpha_==0)
m132 = sqr(mq)*rho;
else if(alpha_==1)
m132 = sqr(mq)*(exp(rho)+1.);
else
m132 = sqr(mq)*(pow(rho,1./(1.-alpha_))+1.);
Energy m13 = sqrt(m132);
try {
p1 = SimplePhaseSpace::getMagnitude(sHat(), m13, mq);
p2 = SimplePhaseSpace::getMagnitude(m132,mq,mh);
} catch ( ImpossibleKinematics ) {
return false;
}
Energy ptmin = lastCuts().minKT(mePartonData()[3]);
double ctmin = -1.0, ctmax = 1.0;
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/p1);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
double cos1 = getCosTheta(ctmin,ctmax,r[0]);
double sin1(sqrt(1.-sqr(cos1)));
double phi1 = Constants::twopi*UseRandom::rnd();
Lorentz5Momentum p13(sin1*p1*cos(phi1),sin1*p1*sin(phi1),cos1*p1,
sqrt(sqr(p1)+m132),m13);
meMomenta()[3].setVect(Momentum3(-sin1*p1*cos(phi1),-sin1*p1*sin(phi1),-cos1*p1));
meMomenta()[3].setMass(mq);
meMomenta()[3].rescaleEnergy();
bool test=Kinematics::twoBodyDecay(p13,mq,mh,-1.+2*r[2],r[3]*Constants::twopi,
meMomenta()[2],meMomenta()[4]);
if(!test) return false;
m232 = (meMomenta()[3]+meMomenta()[4]).m2();
double D = 2./(pow(sqr(mq)/(m132-sqr(mq)),alpha_)+
pow(sqr(mq)/(m232-sqr(mq)),alpha_));
jacobian(0.5*jacobian()*rs/m13*sqr(mq)*D*(rhomax-rhomin)/sHat());
}
// second branch
else {
double rtemp = 2.*(r[1]-0.5);
double rho = rhomin+rtemp*(rhomax-rhomin);
if(alpha_==0)
m232 = sqr(mq)*rho;
else if(alpha_==1)
m232 = sqr(mq)*(exp(rho)+1.);
else
m232 = sqr(mq)*(pow(rho,1./(1.-alpha_))+1.);
Energy m23 = sqrt(m232);
try {
p1 = SimplePhaseSpace::getMagnitude(sHat(), m23, mq);
p2 = SimplePhaseSpace::getMagnitude(m232,mq,mh);
} catch ( ImpossibleKinematics ) {
return false;
}
Energy ptmin = lastCuts().minKT(mePartonData()[2]);
double ctmin = -1.0, ctmax = 1.0;
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/p1);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
double cos1 = getCosTheta(ctmin,ctmax,r[0]);
double sin1(sqrt(1.-sqr(cos1)));
double phi1 = Constants::twopi*UseRandom::rnd();
Lorentz5Momentum p23(-sin1*p1*cos(phi1),-sin1*p1*sin(phi1),-cos1*p1,
sqrt(sqr(p1)+m232),m23);
meMomenta()[2].setVect(Momentum3(sin1*p1*cos(phi1),sin1*p1*sin(phi1),cos1*p1));
meMomenta()[2].setMass(mq);
meMomenta()[2].rescaleEnergy();
bool test=Kinematics::twoBodyDecay(p23,mq,mh,-1.+2*r[2],r[3]*Constants::twopi,
meMomenta()[3],meMomenta()[4]);
if(!test) return false;
m132 = (meMomenta()[2]+meMomenta()[4]).m2();
double D = 2./(pow(sqr(mq)/(m132-sqr(mq)),alpha_)+
pow(sqr(mq)/(m232-sqr(mq)),alpha_));
jacobian(0.5*jacobian()*rs/m23*sqr(mq)*D*(rhomax-rhomin)/sHat());
}
// calculate jacobian
jacobian(0.125*jacobian()*p1*p2/sHat());
// check cuts
vector<LorentzMomentum> out;
tcPDVector tout;
for(unsigned int ix=2;ix<5;++ix) {
out .push_back(meMomenta()[ix]);
tout.push_back(mePartonData()[ix]);
}
return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]);
}
CrossSection MEPP2QQHiggs::dSigHatDR() const {
using Constants::pi;
// jacobian factor for the higgs
InvEnergy2 bwfact;
Energy moff = meMomenta()[4].mass();
if(shapeOpt_==1) {
bwfact = mePartonData()[4]->generateWidth(moff)*moff/pi/
(sqr(sqr(moff)-sqr(mh_))+sqr(mh_*wh_));
}
- else {
+ else if(shapeOpt_==2) {
bwfact = hmass_->BreitWignerWeight(moff);
}
double jac1 = shapeOpt_==0 ?
1. : double(bwfact*(sqr(sqr(moff)-sqr(mh_))+sqr(mh_*wh_))/(mh_*wh_));
return sqr(hbarc)*me2()*jacobian()*jac1/sHat()/pow(Constants::twopi,3);
}
void MEPP2QQHiggs::getDiagrams() const {
tPDPtr Q = quark_[quarkFlavour_-1];
tPDPtr QB = antiquark_[quarkFlavour_-1];
// gg -> q qbar h0 subprocesses
if(process_==0||process_==1) {
// first t-channel
add(new_ptr((Tree2toNDiagram(3), gluon_, QB, gluon_,
1, Q, 4, Q , 2, QB, 4, higgs_, -1)));
add(new_ptr((Tree2toNDiagram(4), gluon_, QB, QB, gluon_,
1, Q, 3, QB, 2, higgs_, -2)));
add(new_ptr((Tree2toNDiagram(3),gluon_,QB,gluon_,
1, Q, 2, QB, 5, QB, 5, higgs_, -3)));
// interchange
add(new_ptr((Tree2toNDiagram(3),gluon_,Q,gluon_,
2, Q, 4, Q , 1, QB, 4, higgs_, -4)));
add(new_ptr((Tree2toNDiagram(4),gluon_,Q,Q,gluon_,
3, Q, 1, QB, 2, higgs_, -5)));
add(new_ptr((Tree2toNDiagram(3),gluon_,Q,gluon_,
2, Q, 1, QB, 5, QB, 5, higgs_, -6)));
// s-channel
add(new_ptr((Tree2toNDiagram(2),gluon_,gluon_, 1, gluon_,
3, Q, 4, Q, 3, QB, 4, higgs_, -7)));
add(new_ptr((Tree2toNDiagram(2),gluon_,gluon_, 1, gluon_,
3,Q, 3, QB, 5, QB, 5, higgs_, -8)));
}
// q qbar -> q qbar
if(process_==0||process_==2) {
for(unsigned int ix=1;ix<5;++ix) {
// gluon s-channel
add(new_ptr((Tree2toNDiagram(2),quark_[ix-1], antiquark_[ix-1],
1, gluon_, 3, Q, 4, Q , 3, QB, 4, higgs_, -9)));
add(new_ptr((Tree2toNDiagram(2),quark_[ix-1], antiquark_[ix-1],
1, gluon_, 3, Q, 3, QB, 5, QB, 5, higgs_, -10)));
}
}
}
double MEPP2QQHiggs::me2() const {
// total matrix element
double me(0.);
// gg initiated processes
if(mePartonData()[0]->id()==ParticleID::g) {
VectorWaveFunction g1w(meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction g2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qw(meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction qbarw(meMomenta()[3],mePartonData()[3],outgoing);
ScalarWaveFunction higgs(meMomenta()[4],mePartonData()[4],1.,outgoing);
vector<VectorWaveFunction> g1,g2;
vector<SpinorBarWaveFunction> q;
vector<SpinorWaveFunction> qbar;
for(unsigned int ix=0;ix<2;++ix) {
g1w.reset(2*ix);g1.push_back(g1w);
g2w.reset(2*ix);g2.push_back(g2w);
qw.reset(ix);q.push_back(qw);
qbarw.reset(ix);qbar.push_back(qbarw);
}
// calculate the matrix element
me=ggME(g1,g2,q,qbar,higgs,0);
}
// q qbar initiated
else {
SpinorWaveFunction q1w(meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction q2w(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction q3w(meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction q4w(meMomenta()[3],mePartonData()[3],outgoing);
ScalarWaveFunction higgs(meMomenta()[4],mePartonData()[4],1.,outgoing);
vector<SpinorWaveFunction> q1,q4;
vector<SpinorBarWaveFunction> q2,q3;
for(unsigned int ix=0;ix<2;++ix) {
q1w.reset(ix);q1.push_back(q1w);
q2w.reset(ix);q2.push_back(q2w);
q3w.reset(ix);q3.push_back(q3w);
q4w.reset(ix);q4.push_back(q4w);
}
// calculate the matrix element
me = qqME(q1,q2,q3,q4,higgs,0);
}
return me*sHat()*UnitRemoval::InvE2;
}
double MEPP2QQHiggs::ggME(vector<VectorWaveFunction> &g1,
vector<VectorWaveFunction> &g2,
vector<SpinorBarWaveFunction> & q,
vector<SpinorWaveFunction> & qbar,
ScalarWaveFunction & hwave,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
Energy mass = q[0].mass();
// matrix element to be stored
if(iflow!=0) me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin0));
// calculate the matrix element
double output(0.),sumflow[2]={0.,0.};
double sumdiag[8]={0.,0.,0.,0.,0.,0.,0.,0.};
Complex diag[8],flow[2];
VectorWaveFunction interv;
SpinorWaveFunction inters,QBoff;
SpinorBarWaveFunction intersb,Qoff;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
interv = GGGVertex_->evaluate(mt,5,gluon_,g1[ihel1],g2[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
Qoff = QQHVertex_->evaluate(mt,3,q[ohel1].particle()->CC(),
q[ohel1],hwave,mass);
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
QBoff = QQHVertex_->evaluate(mt,3,qbar[ohel2].particle()->CC(),
qbar[ohel2],hwave,mass);
// 1st diagram
inters = QQGVertex_->evaluate(mt,1,qbar[ohel2].particle()->CC(),
qbar[ohel2],g2[ihel2],mass);
diag[0] = QQGVertex_->evaluate(mt,inters,Qoff,g1[ihel1]);
// 2nd diagram
intersb = QQGVertex_->evaluate(mt,1,q[ohel1].particle()->CC(),
q[ohel1],g1[ihel1],mass);
diag[1] = QQHVertex_->evaluate(mt,inters,intersb,hwave);
// 3rd diagram
diag[2] = QQGVertex_->evaluate(mt,QBoff,intersb,g2[ihel2]);
// 4th diagram
inters = QQGVertex_->evaluate(mt,1,qbar[ohel2].particle()->CC(),
qbar[ohel2],g1[ihel1],mass);
diag[3] = QQGVertex_->evaluate(mt,inters,Qoff,g2[ihel2]);
// 5th diagram
intersb = QQGVertex_->evaluate(mt,1,q[ohel1].particle()->CC(),
q[ohel1],g2[ihel2],mass);
diag[4] = QQHVertex_->evaluate(mt,inters,intersb,hwave);
// 6th diagram
diag[5] = QQGVertex_->evaluate(mt,QBoff,intersb,g1[ihel1]);
// 7th diagram
diag[6] = QQGVertex_->evaluate(mt,qbar[ohel2],Qoff ,interv);
// 8th diagram
diag[7] = QQGVertex_->evaluate(mt,QBoff ,q[ohel1],interv);
// colour flows
flow[0]=diag[0]+diag[1]+diag[2]+(diag[6]+diag[7]);
flow[1]=diag[3]+diag[4]+diag[5]-(diag[6]+diag[7]);
// sums
for(unsigned int ix=0;ix<8;++ix) sumdiag[ix] += norm(diag[ix]);
for(unsigned int ix=0;ix<2;++ix) sumflow[ix] += norm(flow[ix]);
// total
output +=real(flow[0]*conj(flow[0])+flow[1]*conj(flow[1])
-0.25*flow[0]*conj(flow[1]));
// store the me if needed
if(iflow!=0) me_(2*ihel1,2*ihel2,ohel1,ohel2,0)=flow[iflow-1];
}
}
}
}
// select a colour flow
flow_ = 1 + UseRandom::rnd2(sumflow[0],sumflow[1]);
if(flow_==1) sumdiag[0]=sumdiag[1]=sumdiag[2]=0.;
else sumdiag[3]=sumdiag[4]=sumdiag[5]=0.;
// select a diagram from that flow
double prob = UseRandom::rnd();
for(unsigned int ix=0;ix<8;++ix) {
if(prob<=sumdiag[ix]) {
diagram_=1+ix;
break;
}
prob -= sumdiag[ix];
}
// final part of colour and spin factors
return output/48.;
}
double MEPP2QQHiggs::qqME(vector<SpinorWaveFunction> & q1,
vector<SpinorBarWaveFunction> & q2,
vector<SpinorBarWaveFunction> & q3,
vector<SpinorWaveFunction> & q4,
ScalarWaveFunction & hwave,
unsigned int iflow) const {
// scale
Energy2 mt(scale());
Energy mass = q3[0].mass();
// matrix element to be stored
if(iflow!=0) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin0));
// calculate the matrix element
double output(0.),sumdiag[2]={0.,0.};
Complex diag[2];
VectorWaveFunction interv;
SpinorWaveFunction QBoff;
SpinorBarWaveFunction Qoff;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
interv = QQGVertex_->evaluate(mt,5,gluon_,q1[ihel1],q2[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
Qoff = QQHVertex_->evaluate(mt,3,q3[ohel1].particle()->CC(),
q3[ohel1],hwave,mass);
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
QBoff = QQHVertex_->evaluate(mt,3,q4[ohel2].particle()->CC(),
q4[ohel2],hwave,mass);
// 1st diagram
diag[0] = QQGVertex_->evaluate(mt,q4[ohel2],Qoff,interv);
// 2nd diagram
diag[1] = QQGVertex_->evaluate(mt,QBoff,q3[ohel1],interv);
// sum of diagrams
for(unsigned int ix=0;ix<2;++ix) sumdiag[ix] += norm(diag[ix]);
diag[0] += diag[1];
output += norm(diag[0]);
if(iflow!=0) me_(ihel1,ihel2,ohel1,ohel2,0) = diag[0];
}
}
}
}
// only 1 colour flow
flow_=1;
// select a diagram
diagram_ = 9+UseRandom::rnd2(sumdiag[0],sumdiag[1]);
// final part of colour and spin factors
return output/18.;
}
Selector<const ColourLines *>
MEPP2QQHiggs::colourGeometries(tcDiagPtr diag) const {
// colour lines for gg -> Q Qbar H
static const ColourLines cgg[10]=
{ColourLines("1 4 5, -1 -2 3 , -3 -6 "),
ColourLines("1 5 , -1 -2 -3 4, -4 -6 "),
ColourLines("1 4 , -1 -2 3 , -3 -5 -6"),
ColourLines("3 4 5, 1 2 -3 , -1 -6 "),
ColourLines("4 5 , 1 2 3 -4, -1 -6"),
ColourLines("3 4 , 1 2 -3 , -1 -5 -6"),
ColourLines("1 3 4 5, -1 2, -2 -3 -6"),
ColourLines("2 3 4 5, 1 -2, -1 -3 -6"),
ColourLines("1 3 4, -1 2, -2 -3 -5 -6"),
ColourLines("2 3 4, 1 -2, -1 -3 -5 -6")};
// colour lines for q qbar -> Q Qbar H
static const ColourLines cqq[2]=
{ColourLines("1 3 4 5, -2 -3 -6"),
ColourLines("1 3 4 , -2 -3 -5 -6")};
// select the colour flow (as all ready picked just insert answer)
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
// gg -> q qbar subprocess
case 1: case 2: case 3: case 4: case 5: case 6:
sel.insert(1.0, &cgg[abs(diag->id())-1]);
break;
case 7:
sel.insert(1.0, &cgg[5 + flow_]);
break;
case 8:
sel.insert(1.0, &cgg[7 + flow_]);
break;
// q qbar -> q qbar subprocess
case 9: case 10:
sel.insert(1.0, &cqq[abs(diag->id())-9]);
break;
}
return sel;
}
Selector<MEBase::DiagramIndex>
MEPP2QQHiggs::diagrams(const DiagramVector & diags) const {
// select the diagram, this is easy for us as we have already done it
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
if(diags[i]->id()==-int(diagram_)) sel.insert(1.0, i);
else sel.insert(0., i);
}
return sel;
}
void MEPP2QQHiggs::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
for(unsigned int ix=0;ix<3;++ix) hard.push_back(sub->outgoing()[ix]);
// identify the process and calculate the matrix element
if(hard[0]->id()<0) swap(hard[0],hard[1]);
if(hard[2]->id()==ParticleID::h0) swap(hard[2],hard[4]);
if(hard[3]->id()==ParticleID::h0) swap(hard[3],hard[4]);
if(hard[2]->id()<0) swap(hard[2],hard[3]);
if(hard[0]->id()==ParticleID::g) {
vector<VectorWaveFunction> g1,g2;
vector<SpinorBarWaveFunction> q;
vector<SpinorWaveFunction> qbar;
// off-shell wavefunctions for the spin correlations
VectorWaveFunction( g1,hard[0],incoming,false,true,true);
VectorWaveFunction( g2,hard[1],incoming,false,true,true);
SpinorBarWaveFunction(q ,hard[2],outgoing,true ,true);
SpinorWaveFunction( qbar,hard[3],outgoing,true ,true);
ScalarWaveFunction hwave( hard[4],outgoing,true);
g1[1]=g1[2];g2[1]=g2[2];
ggME(g1,g2,q,qbar,hwave,flow_);
}
// q qbar -> Q Qbar Higgs
else {
vector<SpinorWaveFunction> q1,q4;
vector<SpinorBarWaveFunction> q2,q3;
// off-shell for spin correlations
SpinorWaveFunction( q1,hard[0],incoming,false,true);
SpinorBarWaveFunction(q2,hard[1],incoming,false,true);
SpinorBarWaveFunction(q3,hard[2],outgoing,true ,true);
SpinorWaveFunction( q4,hard[3],outgoing,true ,true);
ScalarWaveFunction hwave( hard[4],outgoing,true);
qqME(q1,q2,q3,q4,hwave,flow_);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<5;++ix)
hard[ix]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2SingleTop.cc b/MatrixElement/Hadron/MEPP2SingleTop.cc
--- a/MatrixElement/Hadron/MEPP2SingleTop.cc
+++ b/MatrixElement/Hadron/MEPP2SingleTop.cc
@@ -1,659 +1,663 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2SingleTop class.
//
#include "MEPP2SingleTop.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2SingleTop::MEPP2SingleTop() : process_(1), maxflavour_(5), topOption_(1),
wOption_(1)
{}
IBPtr MEPP2SingleTop::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2SingleTop::fullclone() const {
return new_ptr(*this);
}
void MEPP2SingleTop::doinit() {
HwMEBase::doinit();
vector<unsigned int> massopt(2,0);
massopt[0] = topOption_;
if(process_==1) {
massopt[1]= 0;
}
else if(process_==2) {
massopt[1]= 1;
}
else if(process_==3) {
massopt[1]= wOption_;
}
massOption(massopt);
// mass option
rescalingOption(2);
// get the vertices we need
// get a pointer to the standard model object in the run
static const tcHwSMPtr hwsm
= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if (!hwsm) throw InitException() << "hwsm pointer is null in"
<< " MEPP2SingleTop::doinit()"
<< Exception::abortnow;
// get pointers to all required Vertex objects
FFWvertex_ = hwsm->vertexFFW();
FFGvertex_ = hwsm->vertexFFG();
}
void MEPP2SingleTop::persistentOutput(PersistentOStream & os) const {
os << process_ << FFWvertex_ << FFGvertex_ << maxflavour_
<< topOption_ << wOption_;
}
void MEPP2SingleTop::persistentInput(PersistentIStream & is, int) {
is >> process_ >> FFWvertex_ >> FFGvertex_ >> maxflavour_
>> topOption_ >> wOption_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEPP2SingleTop,HwMEBase>
describeHerwigMEPP2SingleTop("Herwig::MEPP2SingleTop", "HwMEHadron.so");
void MEPP2SingleTop::Init() {
static ClassDocumentation<MEPP2SingleTop> documentation
("The MEPP2SingleTop class implements the production of "
"a single top quark.");
static Switch<MEPP2SingleTop,unsigned int> interfaceProcess
("Process",
"The process to generate",
&MEPP2SingleTop::process_, 1, false, false);
static SwitchOption interfaceProcesstChannel
(interfaceProcess,
"tChannel",
"Generate t-channel W exchange processes",
1);
static SwitchOption interfaceProcesssChannel
(interfaceProcess,
"sChannel",
"Generate s-channel W exchange processes",
2);
static SwitchOption interfaceProcesstW
(interfaceProcess,
"tW",
"Generate top production in association with a W boson",
3);
static Parameter<MEPP2SingleTop,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the non-top quarks",
&MEPP2SingleTop::maxflavour_, 5, 1, 5,
false, false, Interface::limited);
static Switch<MEPP2SingleTop,int> interfaceTopMassOption
("TopMassOption",
"Option for the treatment of the top quark masses",
&MEPP2SingleTop::topOption_, 1, false, false);
static SwitchOption interfaceTopMassOptionOnMassShell
(interfaceTopMassOption,
"OnMassShell",
"The top is produced on its mass shell",
1);
static SwitchOption interfaceTopMassOptionOffShell
(interfaceTopMassOption,
"OffShell",
"The top is generated off-shell using the mass and width generator.",
2);
static Switch<MEPP2SingleTop,int> interfaceWMassOption
("WMassOption",
"Option for the treatment of the top quark masses",
&MEPP2SingleTop::wOption_, 1, false, false);
static SwitchOption interfaceWMassOptionOnMassShell
(interfaceWMassOption,
"OnMassShell",
"The W is produced on its mass shell",
1);
static SwitchOption interfaceWMassOptionOffShell
(interfaceWMassOption,
"OffShell",
"The W is generated off-shell using the mass and width generator.",
2);
}
Energy2 MEPP2SingleTop::scale() const{
if(process_==2)
return sHat();
Energy2 s(0.5*sHat()),u(0.5*(uHat()-meMomenta()[3].mass2())),
t(0.5*(tHat()-meMomenta()[2].mass2()));
return 4.*s*t*u/(s*s+t*t+u*u);
}
unsigned int MEPP2SingleTop::orderInAlphaS() const {
return process_!=3 ? 0 : 1;
}
unsigned int MEPP2SingleTop::orderInAlphaEW() const {
return process_!=3 ? 2 : 1;
}
void MEPP2SingleTop::getDiagrams() const {
tcPDPtr g = getParticleData(ParticleID::g);
tcPDPtr Wp = getParticleData(ParticleID::Wplus );
tcPDPtr Wm = getParticleData(ParticleID::Wminus);
tcPDPtr tp = getParticleData(ParticleID::t);
tcPDPtr tb = tp->CC();
// light particles
typedef std::vector<pair<tcPDPtr,tcPDPtr> > Pairvector;
Pairvector lightPair;
switch(maxflavour_) {
case 5:
lightPair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::cbar)));
lightPair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
case 4:
lightPair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::cbar)));
lightPair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::cbar)));
+ [[fallthrough]];
case 3:
lightPair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
case 2:
lightPair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
default:
;
}
// top partner
vector<tcPDPtr> topPartner;
for(long ix=1;ix<=maxflavour_;ix+=2)
topPartner.push_back(getParticleData(ix));
// t-channel
if(process_==1) {
for (Pairvector::const_iterator light = lightPair.begin();
light != lightPair.end(); ++light) {
// lights
tcPDPtr qNeg1 = light->first;
tcPDPtr qNeg2 = light->second->CC();
tcPDPtr qPos1 = light->first ->CC();
tcPDPtr qPos2 = light->second;
if(SM().CKM(*qNeg2,*qNeg1)<1e-30) continue;
for(unsigned int ix=0;ix<topPartner.size();++ix) {
if(SM().CKM(*tp,*topPartner[ix])<1e-30) continue;
// diagrams
add(new_ptr((Tree2toNDiagram(3), topPartner[ix] ,
Wp, qNeg2, 1, tp, 2, qNeg1, -1)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix] ,
Wp, qPos1, 1, tp, 2, qPos2, -2)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix]->CC(),
Wm, qNeg1, 1, tb, 2, qNeg2, -3)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix]->CC(),
Wm, qPos2, 1, tb, 2, qPos1, -4)));
}
}
}
else if(process_==2) {
Pairvector::const_iterator light = lightPair.begin();
for (; light != lightPair.end(); ++light) {
// lights
tcPDPtr qNeg1 = light->first ;
tcPDPtr qNeg2 = light->second;
tcPDPtr qPos1 = qNeg2->CC();
tcPDPtr qPos2 = qNeg1->CC();
if(SM().CKM(*qPos1,*qNeg1)<1e-30) continue;
for(unsigned int ix=0;ix<topPartner.size();++ix) {
if(SM().CKM(*tp,*topPartner[ix])<1e-30) continue;
// diagrams
add(new_ptr((Tree2toNDiagram(2), qNeg1, qNeg2, 1, Wm,
3, tb, 3, topPartner[ix] , -11)));
add(new_ptr((Tree2toNDiagram(2), qPos1, qPos2, 1, Wp,
3, tp, 3, topPartner[ix]->CC(), -12)));
}
}
}
else if(process_==3) {
for(unsigned int ix=0;ix<topPartner.size();++ix) {
if(SM().CKM(*tp,*topPartner[ix])<1e-30) continue;
add(new_ptr((Tree2toNDiagram(2), topPartner[ix], g,
1, topPartner[ix], 3, tp, 3, Wm, -21)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix], tp, g,
3, tp, 1, Wm, -22)));
add(new_ptr((Tree2toNDiagram(2), topPartner[ix]->CC(), g,
1, topPartner[ix]->CC(), 3, tb, 3, Wp, -23)));
add(new_ptr((Tree2toNDiagram(3), topPartner[ix]->CC(), tb, g,
3, tb, 1, Wp, -24)));
}
}
else
assert(false);
}
Selector<MEBase::DiagramIndex>
MEPP2SingleTop::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
// only one diagram for t- and s-channel processes
if ( abs(diags[i]->id()) <20 )
sel.insert(1.0, i);
else if ( abs(diags[i]->id()) <23 )
sel.insert(meInfo()[abs(diags[i]->id())-21],i);
else
sel.insert(meInfo()[abs(diags[i]->id())-23],i);
}
return sel;
}
Selector<const ColourLines *>
MEPP2SingleTop::colourGeometries(tcDiagPtr diag) const {
// t-channel
static ColourLines ct[4]={ColourLines(" 1 4, 3 5"),
ColourLines(" 1 4, -3 -5"),
ColourLines("-1 -4, 3 5"),
ColourLines("-1 -4, -3 -5")};
// s-channel
static ColourLines cs[2]={ColourLines("1 -2, -4 5"),
ColourLines("1 -2, 4 -5")};
// tW
static ColourLines ctw[4]={ColourLines(" 1 -2, 2 3 4"),
ColourLines(" 1 2 -3, 3 4"),
ColourLines("-1 2, -2 -3 -4"),
ColourLines("-1 -2 3, -3 -4")};
// select the right one
Selector<const ColourLines *> sel;
int id = abs(diag->id());
switch (id) {
case 1: case 2: case 3: case 4:
sel.insert(1.0, &ct[id-1]);
break;
case 11: case 12:
sel.insert(1.0, &cs[id-11]);
break;
case 21: case 22: case 23: case 24:
sel.insert(1.0, &ctw[id-21]);
break;
default:
assert(false);
};
return sel;
}
double MEPP2SingleTop::me2() const {
if(process_==1) {
vector<SpinorWaveFunction> f1,f2;
vector<SpinorBarWaveFunction> a1,a2;
SpinorWaveFunction sf1,sf2;
SpinorBarWaveFunction sa1,sa2;
if(mePartonData()[0]->id()>0) {
sf1 = SpinorWaveFunction (meMomenta()[0],mePartonData()[0],incoming);
sa1 = SpinorBarWaveFunction(meMomenta()[2],mePartonData()[2],outgoing);
}
else {
sa1 = SpinorBarWaveFunction(meMomenta()[0],mePartonData()[0],incoming);
sf1 = SpinorWaveFunction (meMomenta()[2],mePartonData()[2],outgoing);
}
if(mePartonData()[1]->id()>0) {
sf2 = SpinorWaveFunction (meMomenta()[1],mePartonData()[1],incoming);
sa2 = SpinorBarWaveFunction(meMomenta()[3],mePartonData()[3],outgoing);
}
else {
sa2 = SpinorBarWaveFunction(meMomenta()[1],mePartonData()[1],incoming);
sf2 = SpinorWaveFunction (meMomenta()[3],mePartonData()[3],outgoing);
}
for(unsigned int ix=0;ix<2;++ix) {
sf1.reset(ix); f1.push_back(sf1);
sf2.reset(ix); f2.push_back(sf2);
sa1.reset(ix); a1.push_back(sa1);
sa2.reset(ix); a2.push_back(sa2);
}
return tChannelME(f1,a1,f2,a2,false);
}
else if(process_==2) {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction q (meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbar(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction f;
SpinorWaveFunction fbar;
if(mePartonData()[2]->id()==ParticleID::t) {
f = SpinorBarWaveFunction(meMomenta()[2],mePartonData()[2],outgoing);
fbar = SpinorWaveFunction (meMomenta()[3],mePartonData()[3],outgoing);
}
else {
f = SpinorBarWaveFunction(meMomenta()[3],mePartonData()[3],outgoing);
fbar = SpinorWaveFunction (meMomenta()[2],mePartonData()[2],outgoing);
}
for(unsigned int ix=0;ix<2;++ix) {
q.reset(ix) ; fin.push_back(q);
qbar.reset(ix); ain.push_back(qbar);
f.reset(ix) ;fout.push_back(f);
fbar.reset(ix);aout.push_back(fbar);
}
return sChannelME(fin,ain,fout,aout,false);
}
else {
SpinorWaveFunction sf;
SpinorBarWaveFunction sa;
vector<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> gl,vec;
if(mePartonData()[0]->id()>0) {
sf = SpinorWaveFunction (meMomenta()[0],mePartonData()[0],incoming);
sa = SpinorBarWaveFunction(meMomenta()[2],mePartonData()[2],outgoing);
}
else {
sa = SpinorBarWaveFunction(meMomenta()[0],mePartonData()[0],incoming);
sf = SpinorWaveFunction (meMomenta()[2],mePartonData()[2],outgoing);
}
VectorWaveFunction gluon(meMomenta()[1],mePartonData()[1],incoming);
VectorWaveFunction wbos (meMomenta()[3],mePartonData()[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
sf.reset(ix); f1.push_back(sf);
sa.reset(ix); a1.push_back(sa);
gluon.reset(2*ix); gl.push_back(gluon);
wbos.reset(ix); vec.push_back(wbos);
}
wbos.reset(2);
vec.push_back(wbos);
return tWME(f1,gl,a1,vec,false);
}
}
double MEPP2SingleTop::sChannelME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool calc) const {
// matrix element to be stored
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// positive or negative W boson
bool positive = mePartonData()[0]->iCharge() + mePartonData()[1]->iCharge() > 0;
tcPDPtr wBoson = positive ?
getParticleData(ParticleID::Wplus) : getParticleData(ParticleID::Wminus);
// sum over helicities to get the matrix element
double me = 0.;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
VectorWaveFunction inter = FFWvertex_->evaluate(scale(),1,wBoson,fin[ihel1],ain[ihel2]);
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
Complex diag = FFWvertex_->evaluate(scale(),aout[ohel2],fout[ohel1],inter);
// sum over helicities
me += norm(diag);
if(calc) {
if(fout[ohel1].id()==ParticleID::t)
newme(ihel1,ihel2,ohel1,ohel2) = diag;
else
newme(ihel1,ihel2,ohel2,ohel1) = diag;
}
}
}
}
}
// results
// spin and colour factor
double colspin=1./12.;
if(abs(fout[0].id())<=6) colspin*=3.;
if(calc) me_.reset(newme);
return me*colspin;
}
double MEPP2SingleTop::tChannelME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<SpinorWaveFunction> & f2,
vector<SpinorBarWaveFunction> & a2,
bool calc) const {
// matrix element to be stored
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
tcPDPtr wBoson = getParticleData(ParticleID::Wplus);
// sum over helicities to get the matrix element
double me = 0.;
unsigned int ihel[4];
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ohel1=0;ohel1<2;++ohel1) {
VectorWaveFunction inter = FFWvertex_->evaluate(scale(),3,wBoson,
f1[ihel1],a1[ohel1]);
ihel[0] = ihel1;
ihel[2] = ohel1;
if(f1[ihel1].direction()==outgoing) swap(ihel[0],ihel[2]);
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
Complex diag = FFWvertex_->evaluate(scale(),f2[ihel2],a2[ohel2],inter);
// sum over helicities
me += norm(diag);
ihel[1] = ihel2;
ihel[3] = ohel2;
if(f2[ihel2].direction()==outgoing) swap(ihel[1],ihel[3]);
if(calc)
newme(ihel[0],ihel[1],ihel[2],ihel[3]) = diag;
}
}
}
}
// results
// spin and colour factor
double colspin = 1./4.;
if(calc) me_.reset(newme);
// Energy mt = getParticleData(ParticleID::t)->mass();
// Energy mw = getParticleData(ParticleID::Wplus)->mass();
// double test1
// = 0.25*sqr(4.*Constants::pi*SM().alphaEM(scale())/SM().sin2ThetaW())*
// sHat()*(sHat()-sqr(mt))/sqr(tHat()-sqr(mw));
// double test2
// = 0.25*sqr(4.*Constants::pi*SM().alphaEM(scale())/SM().sin2ThetaW())*
// uHat()*(uHat()-sqr(mt))/sqr(tHat()-sqr(mw));
return me*colspin;
}
double MEPP2SingleTop::tWME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorBarWaveFunction> & fout,
vector<VectorWaveFunction> & Wout,
bool calc) const {
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1));
double me[3]={0.,0.,0.};
Complex diag[2];
Energy2 mt=scale();
for(unsigned int ihel=0;ihel<2;++ihel) {
for(unsigned int ghel=0;ghel<2;++ghel) {
for(unsigned int ohel=0;ohel<2;++ohel) {
for(unsigned int whel=0;whel<3;++whel) {
if(fin[ihel].direction()==incoming) {
// 1st diagram
SpinorWaveFunction inters =
FFGvertex_->evaluate(mt,5,mePartonData()[0],
fin[ihel],gin[ghel]);
diag[0]= FFWvertex_->evaluate(mt,inters,fout[ohel],Wout[whel]);
// 2nd diagram
SpinorBarWaveFunction interb =
FFGvertex_->evaluate(mt,3,mePartonData()[2],
fout[ohel],gin[ghel]);
diag[1]= FFWvertex_->evaluate(mt,fin[ihel],interb,Wout[whel]);
}
else {
// 1st diagram
SpinorBarWaveFunction interb =
FFGvertex_->evaluate(mt,5,mePartonData()[0],
fout[ihel],gin[ghel]);
diag[0]= FFWvertex_->evaluate(mt,fin[ohel],interb,Wout[whel]);
// 2nd diagram
SpinorWaveFunction inters =
FFGvertex_->evaluate(mt,3,mePartonData()[2],
fin[ohel],gin[ghel]);
diag[1]= FFWvertex_->evaluate(mt,inters,fout[ihel],Wout[whel]);
}
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
if(calc)
me_(ihel,ghel,ohel,whel) = diag[0];
}
}
}
}
// results
// initial state spin and colour average
double colspin=1./24./4.;
// and C_F N_c from matrix element
colspin *=4.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix] *= colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0];
}
void MEPP2SingleTop::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);
hard.push_back(sub->outgoing()[1]);
if(mePartonData()[0]->id()!=hard[0]->id()) {
swap(hard[0],hard[1]);
}
if(mePartonData()[2]->id()!=hard[2]->id()) {
swap(hard[2],hard[3]);
}
// on-shell for matrix element
vector<Lorentz5Momentum> momenta;
cPDVector data;
for(unsigned int ix=0;ix<4;++ix) {
momenta.push_back(hard[ix]->momentum());
data .push_back(hard[ix]->dataPtr());
}
rescaleMomenta(momenta,data);
if(process_==1) {
vector<SpinorWaveFunction> f1,f2;
vector<SpinorBarWaveFunction> a1,a2;
// off-shell wavefunctions for the spin correlations (and on shell for matrix elements)
SpinorWaveFunction sf1,sf2;
SpinorBarWaveFunction sa1,sa2;
if(hard[0]->id()>0) {
SpinorWaveFunction (f1,hard[0],incoming,false,true);
SpinorBarWaveFunction(a1,hard[2],outgoing,true,true);
sf1 = SpinorWaveFunction (rescaledMomenta()[0],data[0],incoming);
sa1 = SpinorBarWaveFunction(rescaledMomenta()[2],data[2],outgoing);
}
else {
SpinorBarWaveFunction(a1,hard[0],incoming,false,true);
SpinorWaveFunction (f1,hard[2],outgoing,true,true);
sa1 = SpinorBarWaveFunction(rescaledMomenta()[0],data[0],incoming);
sf1 = SpinorWaveFunction (rescaledMomenta()[2],data[2],outgoing);
}
if(hard[1]->id()>0) {
SpinorWaveFunction (f2,hard[1],incoming,false,true);
SpinorBarWaveFunction(a2,hard[3],outgoing,true,true);
sf2 = SpinorWaveFunction (rescaledMomenta()[1],data[1],incoming);
sa2 = SpinorBarWaveFunction(rescaledMomenta()[3],data[3],outgoing);
}
else {
SpinorBarWaveFunction(a2,hard[1],incoming,false,true);
SpinorWaveFunction (f2,hard[3],outgoing,true,true);
sa2 = SpinorBarWaveFunction(rescaledMomenta()[1],data[1],incoming);
sf2 = SpinorWaveFunction (rescaledMomenta()[3],data[3],outgoing);
}
for(unsigned int ix=0;ix<2;++ix) {
sf1.reset(ix); f1[ix] = sf1;
sf2.reset(ix); f2[ix] = sf2;
sa1.reset(ix); a1[ix] = sa1;
sa2.reset(ix); a2[ix] = sa2;
}
tChannelME(f1,a1,f2,a2,true);
}
else if(process_==2) {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction (fin,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain,hard[1],incoming,false,true);
SpinorWaveFunction q (rescaledMomenta()[0],data[0],incoming);
SpinorBarWaveFunction qbar(rescaledMomenta()[1],data[1],incoming);
SpinorBarWaveFunction f;
SpinorWaveFunction fbar;
if(hard[2]->id()==ParticleID::t) {
SpinorBarWaveFunction(fout,hard[2],outgoing,true,true);
SpinorWaveFunction (aout,hard[3],outgoing,true,true);
f = SpinorBarWaveFunction(rescaledMomenta()[2],data[2],outgoing);
fbar = SpinorWaveFunction (rescaledMomenta()[3],data[3],outgoing);
}
else {
SpinorBarWaveFunction(fout,hard[3],outgoing,true,true);
SpinorWaveFunction (aout,hard[2],outgoing,true,true);
f = SpinorBarWaveFunction(rescaledMomenta()[3],data[3],outgoing);
fbar = SpinorWaveFunction (rescaledMomenta()[2],data[2],outgoing);
}
for(unsigned int ix=0;ix<2;++ix) {
q.reset(ix) ; fin[ix] = q;
qbar.reset(ix); ain[ix] = qbar;
f.reset(ix) ;fout[ix] = f;
fbar.reset(ix);aout[ix] = fbar;
}
sChannelME(fin,ain,fout,aout,true);
}
else {
SpinorWaveFunction sf;
SpinorBarWaveFunction sa;
vector<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> gl,vec;
if(hard[0]->id()>0) {
SpinorWaveFunction (f1,hard[0],incoming,false,true);
SpinorBarWaveFunction(a1,hard[2],outgoing,true ,true);
sf = SpinorWaveFunction (rescaledMomenta()[0],data[0],incoming);
sa = SpinorBarWaveFunction(rescaledMomenta()[2],data[2],outgoing);
}
else {
SpinorBarWaveFunction(a1,hard[0],incoming,false,true);
SpinorWaveFunction (f1,hard[2],outgoing,true ,true);
sa = SpinorBarWaveFunction(rescaledMomenta()[0],data[0],incoming);
sf = SpinorWaveFunction (rescaledMomenta()[2],data[2],outgoing);
}
VectorWaveFunction(gl,hard[1],incoming,false,true ,true);
VectorWaveFunction(vec,hard[3],outgoing,true,false,true);
VectorWaveFunction gluon(rescaledMomenta()[1],data[1],incoming);
VectorWaveFunction wbos (rescaledMomenta()[3],data[3],outgoing);
gl[1]=gl[2];
for(unsigned int ix=0;ix<2;++ix) {
sf.reset(ix); f1[ix] = sf;
sa.reset(ix); a1[ix] = sa;
gluon.reset(2*ix); gl[ix] = gluon;
wbos.reset(ix); vec[ix] = wbos;
}
wbos.reset(2);
vec[2] = wbos;
tWME(f1,gl,a1,vec,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[ix]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2VGamma.cc b/MatrixElement/Hadron/MEPP2VGamma.cc
--- a/MatrixElement/Hadron/MEPP2VGamma.cc
+++ b/MatrixElement/Hadron/MEPP2VGamma.cc
@@ -1,382 +1,386 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2VGamma class.
//
#include "MEPP2VGamma.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2VGamma::MEPP2VGamma() : process_(0), maxflavour_(5), massOption_(2)
{}
unsigned int MEPP2VGamma::orderInAlphaS() const {
return 0;
}
unsigned int MEPP2VGamma::orderInAlphaEW() const {
return 2;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEPP2VGamma,HwMEBase>
describeHerwigMEPP2VGamma("Herwig::MEPP2VGamma", "HwMEHadron.so");
void MEPP2VGamma::Init() {
static ClassDocumentation<MEPP2VGamma> documentation
("The MEPP2VGamma class simulates the production of"
" W+/-gamma and Z0gamma in hadron-hadron collisions"
" using the 2->2 matrix elements");
static Switch<MEPP2VGamma,unsigned int> interfaceProcess
("Process",
"Which processes to include",
&MEPP2VGamma::process_, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all the processes",
0);
static SwitchOption interfaceProcessWGamma
(interfaceProcess,
"WGamma",
"Only include W+/-gamma",
1);
static SwitchOption interfaceProcessZGamma
(interfaceProcess,
"ZGamma",
"Only include ZGamma",
2);
static Parameter<MEPP2VGamma,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour allowed for the incoming quarks",
&MEPP2VGamma::maxflavour_, 5, 2, 5,
false, false, Interface::limited);
static Switch<MEPP2VGamma,unsigned int> interfaceMassOption
("MassOption",
"Option for the treatment of the boson masses",
&MEPP2VGamma::massOption_, 1, false, false);
static SwitchOption interfaceMassOptionOnMassShell
(interfaceMassOption,
"OnMassShell",
"The boson is produced on its mass shell",
1);
static SwitchOption interfaceMassOption2
(interfaceMassOption,
"OffShell",
"The bosons are generated off-shell using the mass and width generator.",
2);
}
void MEPP2VGamma::persistentOutput(PersistentOStream & os) const {
os << FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_
<< process_ << massOption_;
}
void MEPP2VGamma::persistentInput(PersistentIStream & is, int) {
is >> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_
>> process_ >> massOption_;
}
Energy2 MEPP2VGamma::scale() const {
return sHat();
}
IBPtr MEPP2VGamma::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2VGamma::fullclone() const {
return new_ptr(*this);
}
void MEPP2VGamma::doinit() {
HwMEBase::doinit();
// mass option
vector<unsigned int> mopt(2,1);
mopt[0]=massOption_;
massOption(mopt);
rescalingOption(2);
// get the vertices we need
// get a pointer to the standard model object in the run
static const tcHwSMPtr hwsm
= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if (!hwsm) throw InitException() << "hwsm pointer is null in"
<< " MEPP2VGamma::doinit()"
<< Exception::abortnow;
// get pointers to all required Vertex objects
FFZvertex_ = hwsm->vertexFFZ();
FFPvertex_ = hwsm->vertexFFP();
WWWvertex_ = hwsm->vertexWWW();
FFWvertex_ = hwsm->vertexFFW();
}
Selector<const ColourLines *>
MEPP2VGamma::colourGeometries(tcDiagPtr diag) const {
static ColourLines cs("1 -2");
static ColourLines ct("1 2 -3");
Selector<const ColourLines *> sel;
if(diag->id()<-2) sel.insert(1.0, &cs);
else sel.insert(1.0, &ct);
return sel;
}
void MEPP2VGamma::getDiagrams() const {
typedef std::vector<pair<tcPDPtr,tcPDPtr> > Pairvector;
tcPDPtr wPlus = getParticleData(ParticleID::Wplus );
tcPDPtr wMinus = getParticleData(ParticleID::Wminus);
tcPDPtr z0 = getParticleData(ParticleID::Z0 );
tcPDPtr gamma = getParticleData(ParticleID::gamma);
// W+/- gamma
if(process_==0||process_==1) {
// possible parents
Pairvector parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxflavour_) {
case 5:
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
case 4:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::cbar)));
+ [[fallthrough]];
case 3:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
case 2:
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
default:
;
}
// W+ gamma
for(unsigned int ix=0;ix<parentpair.size();++ix) {
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].second->CC(),
parentpair[ix].first, parentpair[ix].first->CC(),
1, wPlus, 2, gamma, -1)));
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].second->CC(),
parentpair[ix].second->CC() , parentpair[ix].first->CC(),
2, wPlus, 1, gamma, -2)));
add(new_ptr((Tree2toNDiagram(2), parentpair[ix].second->CC(),
parentpair[ix].first->CC(), 1, wPlus, 3, wPlus, 3, gamma, -3)));
}
// W- gamma
for(unsigned int ix=0;ix<parentpair.size();++ix) {
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].first,
parentpair[ix].second->CC(),
parentpair[ix].second, 1, wMinus, 2, gamma, -1)));
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].first, parentpair[ix].first ,
parentpair[ix].second, 2, wMinus, 1, gamma, -2)));
add(new_ptr((Tree2toNDiagram(2), parentpair[ix].first,
parentpair[ix].second, 1, wMinus, 3, wMinus, 3, gamma, -3)));
}
}
if(process_==0||process_==2) {
for(int ix=1;ix<=maxflavour_;++ix) {
tcPDPtr qk = getParticleData(ix);
tcPDPtr qb = qk->CC();
add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 1, z0, 2, gamma, -1)));
add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, z0, 1, gamma, -2)));
}
}
}
Selector<MEBase::DiagramIndex>
MEPP2VGamma::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i )
sel.insert(meInfo()[abs(diags[i]->id()) - 1], i);
return sel;
}
double MEPP2VGamma::me2() const {
// setup momenta and particle data for the external wavefunctions
// incoming
SpinorWaveFunction em_in( meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction ep_in( meMomenta()[1],mePartonData()[1],incoming);
// outgoing
VectorWaveFunction v1_out(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction v2_out(meMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> v1,v2;
// calculate the wavefunctions
for(unsigned int ix=0;ix<3;++ix) {
if(ix<2) {
em_in.reset(ix);
f1.push_back(em_in);
ep_in.reset(ix);
a1.push_back(ep_in);
}
v1_out.reset(ix);
v1.push_back(v1_out);
if(ix!=1) {
v2_out.reset(ix);
v2.push_back(v2_out);
}
}
if(mePartonData()[2]->id()==ParticleID::Z0) {
return ZGammaME(f1,a1,v1,v2,false);
}
else {
return WGammaME(f1,a1,v1,v2,false);
}
}
double MEPP2VGamma::ZGammaME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(3,0.0);
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
vector<Complex> diag(2,0.0);
SpinorWaveFunction inter;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel1=0;ohel1<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
inter = FFZvertex_->evaluate(scale(),5,f1[ihel1].particle()->CC(),
f1[ihel1],v1[ohel1]);
diag[0] = FFPvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
inter = FFPvertex_->evaluate(scale(),5,f1[ihel1].particle()->CC(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFZvertex_->evaluate(scale(),inter,a1[ihel2],v1[ohel1]);
// individual diagrams
for (size_t ii=0; ii<2; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
DVector save(3);
for (size_t i = 0; i < 3; ++i) {
save[i] = 0.25 * me[i];
}
meInfo(save);
return 0.25*output/3.;
}
double MEPP2VGamma::WGammaME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(3,0.0);
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
vector<Complex> diag(3,0.0);
SpinorWaveFunction inter;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
VectorWaveFunction interW =
FFWvertex_->evaluate(scale(),3,v1[0].particle(),
f1[ihel1],a1[ihel2]);
for(unsigned int ohel1=0;ohel1<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<2;++ohel2) {
// t-channel diagrams
inter = FFWvertex_->evaluate(scale(),5,a1[ihel1].particle(),
f1[ihel1],v1[ohel1]);
diag[0] = FFPvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
inter = FFPvertex_->evaluate(scale(),5,f1[ihel1].particle()->CC(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFWvertex_->evaluate(scale(),inter,a1[ihel2],v1[ohel1]);
// s-channel diagram
diag[2] = WWWvertex_->evaluate(scale(),interW,v1[ohel1],v2[ohel2]);
// individual diagrams
for (size_t ii=0; ii<3; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1]+diag[2];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
DVector save(3);
for (size_t i = 0; i < 3; ++i) save[i] = 0.25 * me[i];
meInfo(save);
// spin and colour factors
output *= 0.25/3.;
// testing code
// int iu = abs(mePartonData()[0]->id());
// int id = abs(mePartonData()[1]->id());
// if(iu%2!=0) swap(iu,id);
// iu = (iu-2)/2;
// id = (id-1)/2;
// double ckm = SM().CKM(iu,id);
// InvEnergy4 dsigdt = Constants::pi*sqr(SM().alphaEM(scale()))
// /6./sqr(sHat())/SM().sin2ThetaW()*sqr(1./(1.+tHat()/uHat())-1./3.)*
// (sqr(tHat())+sqr(uHat())+2.*sqr(getParticleData(ParticleID::Wplus)->mass())*sHat())/
// tHat()/uHat();
// double test = 16.*ckm*Constants::pi*sqr(sHat())*dsigdt;
// cerr << "testing W gamma " << test << " " << output << " "
// << (test-output)/(test+output) << "\n";
return output;
}
void MEPP2VGamma::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);
hard.push_back(sub->outgoing()[1]);
// order of particles
unsigned int order[4]={0,1,2,3};
if(hard[order[0]]->id()<0) swap(order[0],order[1]);
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qb;
SpinorWaveFunction (q ,hard[order[0]],incoming,false);
SpinorBarWaveFunction(qb,hard[order[1]],incoming,false);
vector<VectorWaveFunction> w1,w2;
if(hard[order[2]]->id()==ParticleID::gamma)
swap(order[2],order[3]);
VectorWaveFunction (w1,hard[order[2]],outgoing,true ,false);
VectorWaveFunction (w2,hard[order[3]],outgoing,true ,true );
w2[1]=w2[2];
// q qbar -> Z gamma
if(hard[order[2]]->id()==ParticleID::Z0) {
ZGammaME(q,qb,w1,w2,true);
}
// q qbar -> W gamma
else {
WGammaME(q,qb,w1,w2,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2VV.cc b/MatrixElement/Hadron/MEPP2VV.cc
--- a/MatrixElement/Hadron/MEPP2VV.cc
+++ b/MatrixElement/Hadron/MEPP2VV.cc
@@ -1,543 +1,547 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2VV class.
//
#include "MEPP2VV.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2VV::MEPP2VV() : process_(0), maxflavour_(5), massOption_(2)
{}
unsigned int MEPP2VV::orderInAlphaS() const {
return 0;
}
unsigned int MEPP2VV::orderInAlphaEW() const {
return 2;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEPP2VV,HwMEBase>
describeHerwigMEPP2VV("Herwig::MEPP2VV", "HwMEHadron.so");
void MEPP2VV::Init() {
static ClassDocumentation<MEPP2VV> documentation
("The MEPP2VV class simulates the production of W+W-, "
"W+/-Z0 and Z0Z0 in hadron-hadron collisions using the 2->2"
" matrix elements");
static Switch<MEPP2VV,unsigned int> interfaceProcess
("Process",
"Which processes to include",
&MEPP2VV::process_, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all the processes",
0);
static SwitchOption interfaceProcessWW
(interfaceProcess,
"WW",
"Only include W+W-",
1);
static SwitchOption interfaceProcessWZ
(interfaceProcess,
"WZ",
"Only include W+/-Z",
2);
static SwitchOption interfaceProcessZZ
(interfaceProcess,
"ZZ",
"Only include ZZ",
3);
static SwitchOption interfaceProcessWpZ
(interfaceProcess,
"WpZ",
"Only include W+ Z",
4);
static SwitchOption interfaceProcessWmZ
(interfaceProcess,
"WmZ",
"Only include W- Z",
5);
static Parameter<MEPP2VV,int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour allowed for the incoming quarks",
&MEPP2VV::maxflavour_, 5, 2, 5,
false, false, Interface::limited);
static Switch<MEPP2VV,unsigned int> interfaceMassOption
("MassOption",
"Option for the treatment of the boson masses",
&MEPP2VV::massOption_, 1, false, false);
static SwitchOption interfaceMassOptionOnMassShell
(interfaceMassOption,
"OnMassShell",
"The boson is produced on its mass shell",
1);
static SwitchOption interfaceMassOption2
(interfaceMassOption,
"OffShell",
"The bosons are generated off-shell using the mass and width generator.",
2);
}
void MEPP2VV::persistentOutput(PersistentOStream & os) const {
os << FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_
<< process_ << massOption_ << maxflavour_;
}
void MEPP2VV::persistentInput(PersistentIStream & is, int) {
is >> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_
>> process_ >> massOption_ >> maxflavour_;
}
Energy2 MEPP2VV::scale() const {
return sHat();
}
IBPtr MEPP2VV::clone() const {
return new_ptr(*this);
}
IBPtr MEPP2VV::fullclone() const {
return new_ptr(*this);
}
void MEPP2VV::doinit() {
HwMEBase::doinit();
// mass option
massOption(vector<unsigned int>(2,massOption_));
rescalingOption(2);
// get the vertices we need
// get a pointer to the standard model object in the run
static const tcHwSMPtr hwsm
= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if (!hwsm) throw InitException() << "hwsm pointer is null in"
<< " MEPP2VV::doinit()"
<< Exception::abortnow;
// get pointers to all required Vertex objects
FFZvertex_ = hwsm->vertexFFZ();
FFPvertex_ = hwsm->vertexFFP();
WWWvertex_ = hwsm->vertexWWW();
FFWvertex_ = hwsm->vertexFFW();
}
double MEPP2VV::getCosTheta(double ctmin, double ctmax, const double r) {
double rand = r;
Energy2 m12 = sqr(meMomenta()[2].mass());
Energy2 m22 = sqr(meMomenta()[3].mass());
Energy2 D1 = sHat()-m12-m22;
Energy4 lambda = sqr(D1) - 4*m12*m22;
double D = D1 / sqrt(lambda);
if(mePartonData()[2]->id()==ParticleID::Z0&&
mePartonData()[3]->id()==ParticleID::Z0) {
double prob = 0.5;
double costh;
double fraction1 = (D-ctmax)/(D-ctmin);
double fraction2 = (D+ctmin)/(D+ctmax);
if(rand<=prob) {
rand /=prob;
costh = D - (D - ctmin) * pow(fraction1, rand);
}
else {
rand = (rand-prob)/(1.-prob);
costh =-D + (D + ctmax) * pow(fraction2, rand);
}
jacobian(1./(prob /((costh - D) * log(fraction1))-
(1.-prob)/((costh + D) * log(fraction2))));
return costh;
}
else {
double fraction = (D-ctmax)/(D-ctmin);
double costh = D - (D - ctmin) * pow(fraction, rand);
jacobian((costh - D) * log(fraction));
return costh;
}
}
Selector<const ColourLines *>
MEPP2VV::colourGeometries(tcDiagPtr diag) const {
static ColourLines cs("1 -2");
static ColourLines ct("1 2 -3");
Selector<const ColourLines *> sel;
if(abs(diag->partons()[2]->id())==24&&abs(diag->partons()[3]->id())==24) {
if(diag->id()<=-4) sel.insert(1.0, &cs);
else sel.insert(1.0, &ct);
}
else if(abs(diag->partons()[2]->id())==24&&diag->partons()[3]->id()==23) {
if(diag->id()==-3) sel.insert(1.0, &cs);
else sel.insert(1.0, &ct);
}
else {
sel.insert(1.0, &ct);
}
return sel;
}
void MEPP2VV::getDiagrams() const {
typedef std::vector<pair<tcPDPtr,tcPDPtr> > Pairvector;
tcPDPtr wPlus = getParticleData(ParticleID::Wplus );
tcPDPtr wMinus = getParticleData(ParticleID::Wminus);
tcPDPtr z0 = getParticleData(ParticleID::Z0 );
tcPDPtr gamma = getParticleData(ParticleID::gamma);
// W+ W-
if(process_==0||process_==1) {
for(int ix=1;ix<=maxflavour_;++ix) {
tcPDPtr qk = getParticleData(ix);
tcPDPtr w1 = ix%2==0 ? wPlus : wMinus;
tcPDPtr w2 = ix%2!=0 ? wPlus : wMinus;
for(int iy=1;iy<=maxflavour_;++iy) {
if(abs(ix-iy)%2!=0) continue;
tcPDPtr qb = getParticleData(-iy);
// s channel photon
add(new_ptr((Tree2toNDiagram(2), qk, qb, 1, gamma, 3, w1, 3, w2, -4)));
// s-channel Z
add(new_ptr((Tree2toNDiagram(2), qk, qb, 1, z0, 3, w1, 3, w2, -5)));
// t-channel
if(ix%2==0) {
int idiag=0;
for(int iz=1;iz<=5;iz+=2) {
--idiag;
tcPDPtr tc = getParticleData(iz);
add(new_ptr((Tree2toNDiagram(3), qk, tc, qb, 1, w1, 2, w2, idiag)));
}
}
else {
int idiag=0;
for(int iz=2;iz<=6;iz+=2) {
--idiag;
tcPDPtr tc = getParticleData(iz);
add(new_ptr((Tree2toNDiagram(3), qk, tc, qb, 1, w1, 2, w2, idiag)));
}
}
}
}
}
// W+/- Z
if(process_==0||process_==2||process_==4||process_==5) {
// possible parents
Pairvector parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxflavour_) {
case 5:
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
case 4:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::cbar)));
+ [[fallthrough]];
case 3:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
case 2:
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
default:
;
}
// W+ Z
if(process_==0||process_==2||process_==4) {
for(unsigned int ix=0;ix<parentpair.size();++ix) {
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].second->CC(),
parentpair[ix].first, parentpair[ix].first->CC(),
1, wPlus, 2, z0, -1)));
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].second->CC(),
parentpair[ix].second->CC() , parentpair[ix].first->CC(),
2, wPlus, 1, z0, -2)));
add(new_ptr((Tree2toNDiagram(2), parentpair[ix].second->CC(),
parentpair[ix].first->CC(), 1, wPlus, 3, wPlus, 3, z0, -3)));
}
}
// W- Z
if(process_==0||process_==2||process_==5) {
for(unsigned int ix=0;ix<parentpair.size();++ix) {
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].first,
parentpair[ix].second->CC(),
parentpair[ix].second, 1, wMinus, 2, z0, -1)));
add(new_ptr((Tree2toNDiagram(3), parentpair[ix].first,
parentpair[ix].first , parentpair[ix].second, 2, wMinus, 1, z0, -2)));
add(new_ptr((Tree2toNDiagram(2), parentpair[ix].first,
parentpair[ix].second, 1, wMinus, 3, wMinus, 3, z0, -3)));
}
}
}
// Z Z
if(process_==0||process_==3) {
for(int ix=1;ix<=maxflavour_;++ix) {
tcPDPtr qk = getParticleData(ix);
tcPDPtr qb = qk->CC();
add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 1, z0, 2, z0, -1)));
add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, z0, 1, z0, -2)));
}
}
}
Selector<MEBase::DiagramIndex>
MEPP2VV::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i )
sel.insert(meInfo()[abs(diags[i]->id())-1], i);
return sel;
}
double MEPP2VV::me2() const {
// setup momenta and particle data for the external wavefunctions
// incoming
SpinorWaveFunction em_in( meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction ep_in( meMomenta()[1],mePartonData()[1],incoming);
// outgoing
VectorWaveFunction v1_out(meMomenta()[2],mePartonData()[2],outgoing);
VectorWaveFunction v2_out(meMomenta()[3],mePartonData()[3],outgoing);
vector<SpinorWaveFunction> f1;
vector<SpinorBarWaveFunction> a1;
vector<VectorWaveFunction> v1,v2;
// calculate the wavefunctions
for(unsigned int ix=0;ix<3;++ix) {
if(ix<2) {
em_in.reset(ix);
f1.push_back(em_in);
ep_in.reset(ix);
a1.push_back(ep_in);
}
v1_out.reset(ix);
v1.push_back(v1_out);
v2_out.reset(ix);
v2.push_back(v2_out);
}
if(mePartonData()[2]->id()==ParticleID::Z0&&
mePartonData()[3]->id()==ParticleID::Z0) {
return ZZME(f1,a1,v1,v2,false);
}
else if(abs(mePartonData()[2]->id())==ParticleID::Wplus&&
abs(mePartonData()[3]->id())==ParticleID::Wplus) {
return WWME(f1,a1,v1,v2,false);
}
else {
return WZME(f1,a1,v1,v2,false);
}
}
double MEPP2VV::WWME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(5,0.0);
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
// particle data for the t-channel intermediate
tcPDPtr tc[3];
if(f1[0].particle()->id()%2==0) {
for (int ix=0;ix<3;++ix) tc[ix] = getParticleData(1+2*ix);
}
else {
for (int ix=0;ix<3;++ix) tc[ix] = getParticleData(2+2*ix);
}
tcPDPtr gamma = getParticleData(ParticleID::gamma);
tcPDPtr z0 = getParticleData(ParticleID::Z0);
vector<Complex> diag(5,0.0);
VectorWaveFunction interP,interZ;
bool sChannel =
f1[0].particle()->id() == -a1[0].particle()->id();
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
if(sChannel) {
interP = FFPvertex_->evaluate(scale(),3,gamma,f1[ihel1],a1[ihel2]);
interZ = FFZvertex_->evaluate(scale(),3,z0 ,f1[ihel1],a1[ihel2]);
}
for(unsigned int ohel1=0;ohel1<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<3;++ohel2) {
// s-channel photon
diag[3] = sChannel ?
WWWvertex_->evaluate(scale(),interP,v2[ohel2],v1[ohel1]) : 0.;
// s-channel Z0
diag[4] = sChannel ?
WWWvertex_->evaluate(scale(),interZ,v2[ohel2],v1[ohel1]) : 0.;
// t-channel
for(unsigned int ix=0;ix<3;++ix) {
SpinorWaveFunction inter =
FFWvertex_->evaluate(scale(),(abs(tc[ix]->id())!=6 ? 5 : 1),
tc[ix],f1[ihel1],v1[ohel1]);
diag[ix] =
FFWvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
}
// individual diagrams
for (size_t ii=0; ii<5; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1]+diag[2]+diag[3]+diag[4];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
DVector save(5);
for (size_t i = 0; i < 5; ++i) {
save[i] = 0.25 * me[i];
}
meInfo(save);
return 0.25*output/3.;
}
double MEPP2VV::WZME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(5,0.0);
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
vector<Complex> diag(3,0.0);
SpinorWaveFunction inter;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
VectorWaveFunction interW =
FFWvertex_->evaluate(scale(),3,v1[0].particle(),
f1[ihel1],a1[ihel2]);
for(unsigned int ohel1=0;ohel1<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<3;++ohel2) {
// t-channel diagrams
inter = FFWvertex_->evaluate(scale(),5,a1[ihel1].particle(),
f1[ihel1],v1[ohel1]);
diag[0] = FFZvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
inter = FFZvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFWvertex_->evaluate(scale(),inter,a1[ihel2],v1[ohel1]);
// s-channel diagram
diag[2] = WWWvertex_->evaluate(scale(),interW,v1[ohel1],v2[ohel2]);
// individual diagrams
for (size_t ii=0; ii<3; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1]+diag[2];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
DVector save(5);
for (size_t i = 0; i < 5; ++i) {
save[i] = 0.25 * me[i];
}
meInfo(save);
return 0.25*output/3.;
}
double MEPP2VV::ZZME(vector<SpinorWaveFunction> & f1,
vector<SpinorBarWaveFunction> & a1,
vector<VectorWaveFunction> & v1,
vector<VectorWaveFunction> & v2,
bool calc) const {
double output(0.);
vector<double> me(5,0.0);
if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1));
vector<Complex> diag(2,0.0);
SpinorWaveFunction inter;
for(unsigned int ihel1=0;ihel1<2;++ihel1) {
for(unsigned int ihel2=0;ihel2<2;++ihel2) {
for(unsigned int ohel1=0;ohel1<3;++ohel1) {
for(unsigned int ohel2=0;ohel2<3;++ohel2) {
inter = FFZvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1],v1[ohel1]);
diag[0] = FFZvertex_->evaluate(scale(),inter,a1[ihel2],v2[ohel2]);
inter = FFZvertex_->evaluate(scale(),5,f1[ihel1].particle(),
f1[ihel1] ,v2[ohel2]);
diag[1] = FFZvertex_->evaluate(scale(),inter,a1[ihel2],v1[ohel1]);
// individual diagrams
for (size_t ii=0; ii<2; ++ii) me[ii] += std::norm(diag[ii]);
// full matrix element
diag[0] += diag[1];
output += std::norm(diag[0]);
// storage of the matrix element for spin correlations
if(calc) me_(ihel1,ihel2,ohel1,ohel2) = diag[0];
}
}
}
}
// identical particle factor
output /= 2.;
DVector save(5);
for (size_t i = 0; i < 5; ++i) {
save[i] = 0.25 * me[i];
}
meInfo(save);
return 0.25*output/3.;
}
void MEPP2VV::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);
hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);
hard.push_back(sub->outgoing()[1]);
// order of particles
unsigned int order[4]={0,1,2,3};
if(hard[order[0]]->id()<0) swap(order[0],order[1]);
vector<SpinorWaveFunction> q;
vector<SpinorBarWaveFunction> qb;
SpinorWaveFunction (q ,hard[order[0]],incoming,false);
SpinorBarWaveFunction(qb,hard[order[1]],incoming,false);
vector<VectorWaveFunction> w1,w2;
// q qbar -> Z Z
if(hard[order[2]]->id()==ParticleID::Z0&&
hard[order[3]]->id()==ParticleID::Z0) {
VectorWaveFunction (w1,hard[order[2]],outgoing,true ,false);
VectorWaveFunction (w2,hard[order[3]],outgoing,true ,false);
ZZME(q,qb,w1,w2,true);
}
// q qbar -> W W
else if(abs(hard[order[2]]->id())==ParticleID::Wplus&&
abs(hard[order[3]]->id())==ParticleID::Wplus) {
if((hard[order[0]]->id()%2==1&&hard[order[2]]->id()==ParticleID::Wplus)||
(hard[order[0]]->id()%2==0&&hard[order[2]]->id()==ParticleID::Wminus))
swap(order[2],order[3]);
VectorWaveFunction (w1,hard[order[2]],outgoing,true ,false);
VectorWaveFunction (w2,hard[order[3]],outgoing,true ,false);
WWME(q,qb,w1,w2,true);
}
// q qbar -> W Z
else {
if(abs(hard[order[2]]->id())!=ParticleID::Wplus)
swap(order[2],order[3]);
VectorWaveFunction (w1,hard[order[2]],outgoing,true ,false);
VectorWaveFunction (w2,hard[order[3]],outgoing,true ,false);
WZME(q,qb,w1,w2,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(me_);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEPP2WH.cc b/MatrixElement/Hadron/MEPP2WH.cc
--- a/MatrixElement/Hadron/MEPP2WH.cc
+++ b/MatrixElement/Hadron/MEPP2WH.cc
@@ -1,153 +1,157 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2WH class.
//
#include "MEPP2WH.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
using namespace Herwig;
MEPP2WH::MEPP2WH() : _plusminus(0)
{}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEPP2WH,MEfftoVH>
describeHerwigMEPP2WH("Herwig::MEPP2WH", "HwMEHadron.so");
void MEPP2WH::persistentOutput(PersistentOStream & os) const {
os << _plusminus;
}
void MEPP2WH::persistentInput(PersistentIStream & is, int) {
is >> _plusminus;
}
void MEPP2WH::Init() {
static ClassDocumentation<MEPP2WH> documentation
("The MEPP2WH class implements the matrix element for the Bjorken"
" process q qbar -> WH");
static Switch<MEPP2WH,unsigned int> interfacePlusMinus
("Wcharge",
"Which intermediate W bosons to include",
&MEPP2WH::_plusminus, 0, false, false);
static SwitchOption interfacePlusMinusAll
(interfacePlusMinus,
"Both",
"Include W+ and W-",
0);
static SwitchOption interfacePlusMinusPlus
(interfacePlusMinus,
"Plus",
"Only include W+",
1);
static SwitchOption interfacePlusMinusMinus
(interfacePlusMinus,
"Minus",
"Only include W-",
2);
}
void MEPP2WH::getDiagrams() const {
// which intgermediates to include
bool wplus =_plusminus==0||_plusminus==1;
bool wminus=_plusminus==0||_plusminus==2;
tPDPtr higgs = getParticleData(ParticleID::h0);
// possible parents
vector<PDPair> parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(maxFlavour()) {
case 5:
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::b),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
case 4:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::cbar)));
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::cbar)));
+ [[fallthrough]];
case 3:
parentpair.push_back(make_pair(getParticleData(ParticleID::s),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
case 2:
parentpair.push_back(make_pair(getParticleData(ParticleID::d),
getParticleData(ParticleID::ubar)));
+ [[fallthrough]];
default:
;
}
// possible children
typedef Selector<tDMPtr> DecaySelector;
// for W+
DecaySelector wpdec = getParticleData(ParticleID::Wplus)->decaySelector();
vector<PDPair> wpdecays;
for(DecaySelector::const_iterator cit=wpdec.begin();cit!=wpdec.end();++cit) {
if(cit->second->orderedProducts().size()!=2) continue;
if(cit->second->orderedProducts()[0]->id()>0)
wpdecays.push_back(make_pair(cit->second->orderedProducts()[0],
cit->second->orderedProducts()[1]));
else
wpdecays.push_back(make_pair(cit->second->orderedProducts()[1],
cit->second->orderedProducts()[0]));
}
// for W-
DecaySelector wmdec = getParticleData(ParticleID::Wminus)->decaySelector();
vector<PDPair> wmdecays;
for(DecaySelector::const_iterator cit=wmdec.begin();cit!=wmdec.end();++cit) {
if(cit->second->orderedProducts().size()!=2) continue;
if(cit->second->orderedProducts()[0]->id()>0)
wmdecays.push_back(make_pair(cit->second->orderedProducts()[0],
cit->second->orderedProducts()[1]));
else
wmdecays.push_back(make_pair(cit->second->orderedProducts()[1],
cit->second->orderedProducts()[0]));
}
vector<PDPair>::const_iterator parent = parentpair.begin();
for (; parent != parentpair.end(); ++parent) {
// W- modes
if(wminus) {
for(unsigned int ix=0;ix<wmdecays.size();++ix) {
add(new_ptr((Tree2toNDiagram(2), parent->first, parent->second,
1, WMinus(), 3, higgs, 3, WMinus(),
5, wmdecays[ix].first,5, wmdecays[ix].second,-1)));
}
}
// W+ modes
if(wplus) {
for(unsigned int ix=0;ix<wpdecays.size();++ix) {
add(new_ptr((Tree2toNDiagram(2), parent->second->CC(), parent->first->CC(),
1, WPlus(), 3, higgs, 3, WPlus(), 5, wpdecays[ix].first,
5, wpdecays[ix].second, -1)));
}
}
}
}
void MEPP2WH::doinit() {
// get the vedrtex pointers from the SM object
tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel());
if(!hwsm)
throw InitException() << "Wrong type of StandardModel object in "
<< "MEPP2WH::doinit() the Herwig"
<< " version must be used"
<< Exception::runerror;
// set the vertex
setWWHVertex(hwsm->vertexWWH());
higgs(getParticleData(ParticleID::h0));
MEfftoVH::doinit();
}
diff --git a/MatrixElement/Hadron/MEPP2WJet.cc b/MatrixElement/Hadron/MEPP2WJet.cc
--- a/MatrixElement/Hadron/MEPP2WJet.cc
+++ b/MatrixElement/Hadron/MEPP2WJet.cc
@@ -1,838 +1,842 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEPP2WJet class.
//
#include "MEPP2WJet.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/MatrixElement/HardVertex.h"
using namespace Herwig;
MEPP2WJet::MEPP2WJet() : _process(0), _maxflavour(5), _plusminus(0),
_wdec(0), _widthopt(1)
{}
void MEPP2WJet::doinit() {
HwMEBase::doinit();
_wplus = getParticleData(ThePEG::ParticleID::Wplus );
_wminus = getParticleData(ThePEG::ParticleID::Wminus);
// cast the SM pointer to the Herwig SM pointer
ThePEG::Ptr<Herwig::StandardModel>::transient_const_pointer
hwsm=ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardModel>
::transient_const_pointer>(standardModel());
// do the initialisation
if(!hwsm)
throw InitException() << "Must be Herwig::StandardModel in MEPP2WJet::doinit()"
<< Exception::runerror;
// set the vertex pointers
_theFFWVertex = hwsm->vertexFFW();
_theQQGVertex = hwsm->vertexFFG();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEPP2WJet,HwMEBase>
describeHerwigMEPP2WJet("Herwig::MEPP2WJet", "HwMEHadron.so");
void MEPP2WJet::Init() {
static ClassDocumentation<MEPP2WJet> documentation
("The MEPP2WJet class implements the matrix element for W + jet production");
static Parameter<MEPP2WJet,unsigned int> interfaceMaxFlavour
( "MaxFlavour",
"The heaviest incoming quark flavour this matrix element is allowed to handle "
"(if applicable).",
&MEPP2WJet::_maxflavour, 5, 0, 8, false, false, true);
static Switch<MEPP2WJet,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&MEPP2WJet::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcessqqbar
(interfaceProcess,
"qqbar",
"Only include q qbar -> W g process",
1);
static SwitchOption interfaceProcessqg
(interfaceProcess,
"qg",
"Only include the q g -> W q process",
2);
static SwitchOption interfaceProcessqbarg
(interfaceProcess,
"qbarg",
"Only include the qbar g -> W qbar process",
3);
static Switch<MEPP2WJet,unsigned int> interfacePlusMinus
("Wcharge",
"Which intermediate W bosons to include",
&MEPP2WJet::_plusminus, 0, false, false);
static SwitchOption interfacePlusMinusAll
(interfacePlusMinus,
"Both",
"Include W+ and W-",
0);
static SwitchOption interfacePlusMinusPlus
(interfacePlusMinus,
"Plus",
"Only include W+",
1);
static SwitchOption interfacePlusMinusMinus
(interfacePlusMinus,
"Minus",
"Only include W-",
2);
static Switch<MEPP2WJet,unsigned int> interfaceWDecay
("WDecay",
"Which processes to include",
&MEPP2WJet::_wdec, 0, false, false);
static SwitchOption interfaceWDecayAll
(interfaceWDecay,
"All",
"Include all SM fermions as outgoing particles",
0);
static SwitchOption interfaceWDecayQuarks
(interfaceWDecay,
"Quarks",
"Only include outgoing quarks",
1);
static SwitchOption interfaceWDecayLeptons
(interfaceWDecay,
"Leptons",
"All include outgoing leptons",
2);
static SwitchOption interfaceWDecayElectron
(interfaceWDecay,
"Electron",
"Only include outgoing e nu_e",
3);
static SwitchOption interfaceWDecayMuon
(interfaceWDecay,
"Muon",
"Only include outgoing mu nu_mu",
4);
static SwitchOption interfaceWDecayTau
(interfaceWDecay,
"Tau",
"Only include outgoing tauu nu_tau",
5);
static SwitchOption interfaceWDecayUpDown
(interfaceWDecay,
"UpDown",
"Only include outgoing u dbar/ d ubar",
6);
static SwitchOption interfaceWDecayUpStrange
(interfaceWDecay,
"UpStrange",
"Only include outgoing u sbar/ s ubar",
7);
static SwitchOption interfaceWDecayUpBottom
(interfaceWDecay,
"UpBottom",
"Only include outgoing u bbar/ b ubar",
8);
static SwitchOption interfaceWDecayCharmDown
(interfaceWDecay,
"CharmDown",
"Only include outgoing c dbar/ d cbar",
9);
static SwitchOption interfaceWDecayCharmStrange
(interfaceWDecay,
"CharmStrange",
"Only include outgoing c sbar/ s cbar",
10);
static SwitchOption interfaceWDecayCharmBottom
(interfaceWDecay,
"CharmBottom",
"Only include outgoing c bbar/ b cbar",
11);
static Switch<MEPP2WJet,unsigned int> interfaceWidthOption
("WidthOption",
"The option for handling the width of the off-shell W boson",
&MEPP2WJet::_widthopt, 1, false, false);
static SwitchOption interfaceWidthOptionFixedDenominator
(interfaceWidthOption,
"FixedDenominator",
"Use a fixed with in the W propagator but the full matrix element"
" in the numerator",
1);
static SwitchOption interfaceWidthOptionAllRunning
(interfaceWidthOption,
"AllRunning",
"Use a running width in the W propagator and the full matrix "
"element in the numerator",
2);
}
void MEPP2WJet::getDiagrams() const {
// which intgermediates to include
bool wplus = _plusminus==0 || _plusminus==1;
bool wminus = _plusminus==0 || _plusminus==2;
// possible incoming and outgoing particles
typedef std::vector<pair<long,long> > Pairvector;
// possible parents
Pairvector parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(_maxflavour) {
case 5:
parentpair.push_back(make_pair(ParticleID::b, ParticleID::cbar));
parentpair.push_back(make_pair(ParticleID::b, ParticleID::ubar));
+ [[fallthrough]];
case 4:
parentpair.push_back(make_pair(ParticleID::s, ParticleID::cbar));
parentpair.push_back(make_pair(ParticleID::d, ParticleID::cbar));
+ [[fallthrough]];
case 3:
parentpair.push_back(make_pair(ParticleID::s, ParticleID::ubar));
+ [[fallthrough]];
case 2:
parentpair.push_back(make_pair(ParticleID::d, ParticleID::ubar));
+ [[fallthrough]];
default:
;
}
// possible children
Pairvector childpair;
childpair.reserve(9);
childpair.push_back(make_pair(ParticleID::eminus, ParticleID::nu_ebar));
childpair.push_back(make_pair(ParticleID::muminus, ParticleID::nu_mubar));
childpair.push_back(make_pair(ParticleID::tauminus, ParticleID::nu_taubar));
childpair.push_back(make_pair(ParticleID::d, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::s, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::b, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::d, ParticleID::cbar));
childpair.push_back(make_pair(ParticleID::s, ParticleID::cbar));
childpair.push_back(make_pair(ParticleID::b, ParticleID::cbar));
// gluon for diagrams
tcPDPtr g = getParticleData(ParticleID::g);
// loop over the children
bool lepton,quark;
Pairvector::const_iterator child = childpair.begin();
for (; child != childpair.end(); ++child) {
// allowed leptonic decay
lepton=child->first>10&&
(_wdec==0||_wdec==2||
(abs(child->first)-5)/2==int(_wdec));
// allowed quark decay
quark =abs(child->second)<10&&
(_wdec==0||_wdec==1||
(abs(child->second)==2&&(abs(child->first)+11)/2==int(_wdec))||
(abs(child->second)==4&&(abs(child->first)+17)/2==int(_wdec)));
// if decay not allowed skip
if(!(quark||lepton)) continue;
// decay products
tcPDPtr lNeg1 = getParticleData(child->first);
tcPDPtr lNeg2 = getParticleData(child->second);
tcPDPtr lPos1 = lNeg2->CC();
tcPDPtr lPos2 = lNeg1->CC();
Pairvector::const_iterator parent = parentpair.begin();
for (; parent != parentpair.end(); ++parent) {
// parents
tcPDPtr qNeg1 = getParticleData(parent->first);
tcPDPtr qNeg2 = getParticleData(parent->second);
tcPDPtr qPos1 = qNeg2->CC();
tcPDPtr qPos2 = qNeg1->CC();
// diagrams
// q qbar annhilation processes
if(_process==0||_process==1) {
// q qbar -> W- g
if(wminus) {
add(new_ptr((Tree2toNDiagram(3), qNeg1, qNeg2, qNeg2, 1, _wminus,
2, g, 4, lNeg1, 4, lNeg2, -1)));
add(new_ptr((Tree2toNDiagram(3), qNeg1, qNeg1, qNeg2, 2, _wminus,
1, g, 4, lNeg1, 4, lNeg2, -2)));
}
// q qbar -> W+ g
if(wplus) {
add(new_ptr((Tree2toNDiagram(3), qPos1, qPos2, qPos2, 1, _wplus,
2, g, 4, lPos1, 4, lPos2, -3)));
add(new_ptr((Tree2toNDiagram(3), qPos1, qPos1, qPos2, 2, _wplus,
1, g, 4, lPos1, 4, lPos2, -4)));
}
}
// q g compton
if(_process==0||_process==2) {
if(wminus) {
add(new_ptr((Tree2toNDiagram(3), qNeg1, qPos1, g , 1, _wminus,
2, qPos1, 4, lNeg1, 4, lNeg2, -5)));
add(new_ptr((Tree2toNDiagram(2), qNeg1, g, 1, qNeg1, 3, _wminus,
3, qPos1, 4, lNeg1, 4, lNeg2, -6)));
}
if(wplus) {
add(new_ptr((Tree2toNDiagram(3), qPos1, qNeg1, g, 1, _wplus,
2, qNeg1, 4, lPos1, 4, lPos2, -7)));
add(new_ptr((Tree2toNDiagram(2), qPos1, g, 1, qNeg1, 3, _wplus,
3, qNeg1, 4, lPos1, 4, lPos2, -8)));
}
}
// qbar g compton
if(_process==0||_process==3) {
if(wminus) {
add(new_ptr((Tree2toNDiagram(3), qNeg2, qPos2, g, 1, _wminus,
2, qPos2, 4, lNeg1, 4, lNeg2, -9 )));
add(new_ptr((Tree2toNDiagram(2), qNeg2, g, 1, qNeg2, 3, _wminus,
3, qPos2, 4, lNeg1, 4, lNeg2, -10)));
}
if(wplus) {
add(new_ptr((Tree2toNDiagram(3), qPos2, qNeg2, g, 1, _wplus,
2, qNeg2, 4, lPos1, 4, lPos2, -11)));
add(new_ptr((Tree2toNDiagram(2), qPos2, g, 1, qPos2, 3, _wplus,
3, qNeg2, 4, lPos1, 4, lPos2, -12)));
}
}
}
}
}
unsigned int MEPP2WJet::orderInAlphaS() const {
return 1;
}
unsigned int MEPP2WJet::orderInAlphaEW() const {
return 2;
}
void MEPP2WJet::persistentOutput(PersistentOStream & os) const {
os << _theFFWVertex << _theQQGVertex << _wplus << _widthopt
<< _wminus << _process << _maxflavour << _plusminus << _wdec;
}
void MEPP2WJet::persistentInput(PersistentIStream & is, int) {
is >> _theFFWVertex >> _theQQGVertex >> _wplus >> _widthopt
>> _wminus >> _process >> _maxflavour >> _plusminus >> _wdec;
}
int MEPP2WJet::nDim() const {
return 5;
}
Selector<const ColourLines *>
MEPP2WJet::colourGeometries(tcDiagPtr diag) const {
// colour lines for q qbar -> W g
static const ColourLines cqqbar[4]={ColourLines("1 -2 5,-3 -5"),
ColourLines("1 5, -5 2 -3"),
ColourLines("1 -2 5,-3 -5,6 -7"),
ColourLines("1 5, -5 2 -3,6 -7")};
// colour lines for q g -> W q
static const ColourLines cqg [4]={ColourLines("1 2 -3,3 5"),
ColourLines("1 -2,2 3 5"),
ColourLines("1 2 -3,3 5,6 -7"),
ColourLines("1 -2,2 3 5,6 -7")};
// colour lines for qbar q -> W qbar
static const ColourLines cqbarg[4]={ColourLines("-1 -2 3,-3 -5"),
ColourLines("-1 2,-2 -3 -5"),
ColourLines("-1 -2 3,-3 -5,6 -7"),
ColourLines("-1 2,-2 -3 -5,6 -7")};
// select the correct line
unsigned int icol = mePartonData()[3]->coloured() ? 2 : 0;
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
case 1 : case 3:
sel.insert(1.0, &cqqbar[icol]);
break;
case 2 : case 4:
sel.insert(1.0, &cqqbar[icol+1]);
break;
case 5 : case 7:
sel.insert(1.0, &cqg[icol]);
break;
case 6 : case 8:
sel.insert(1.0, &cqg[icol+1]);
break;
case 9 : case 11:
sel.insert(1.0, &cqbarg[icol]);
break;
case 10 : case 12:
sel.insert(1.0, &cqbarg[icol+1]);
break;
}
return sel;
}
Selector<MEBase::DiagramIndex>
MEPP2WJet::diagrams(const DiagramVector & diags) const {
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
int id=abs(diags[i]->id());
if (id <= 2 ) sel.insert(meInfo()[id- 1],i);
else if(id <= 4 ) sel.insert(meInfo()[id- 3],i);
else if(id <= 6 ) sel.insert(meInfo()[id- 5],i);
else if(id <= 8 ) sel.insert(meInfo()[id- 7],i);
else if(id <= 10) sel.insert(meInfo()[id- 9],i);
else if(id <= 12) sel.insert(meInfo()[id-11],i);
}
return sel;
}
Energy2 MEPP2WJet::scale() const {
return _scale;
}
CrossSection MEPP2WJet::dSigHatDR() const {
return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc);
}
bool MEPP2WJet::generateKinematics(const double * r) {
// initialize jacobian
jacobian(1.);
// cms energy
Energy ecm=sqrt(sHat());
// find the right W pointer
tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ?
_wplus :_wminus;
// first generate the mass of the off-shell gauge boson
// minimum mass of the
tcPDVector ptemp;
ptemp.push_back(mePartonData()[3]);
ptemp.push_back(mePartonData()[4]);
Energy2 minMass2 = max(lastCuts().minSij(mePartonData()[3],mePartonData()[4]),
lastCuts().minS(ptemp));
// minimum pt of the jet
Energy ptmin = max(lastCuts().minKT(mePartonData()[2]),
lastCuts().minKT(wdata));
// maximum mass of the gauge boson so pt is possible
Energy2 maxMass2 = min(ecm*(ecm-2.*ptmin),lastCuts().maxS(ptemp));
if(maxMass2<=ZERO||minMass2<ZERO) return false;
// also impose the limits from the ParticleData object
minMass2 = max(minMass2,sqr(wdata->massMin()));
maxMass2 = min(maxMass2,sqr(wdata->massMax()));
// return if not kinematically possible
if(minMass2>maxMass2) return false;
// generation of the mass
Energy M(wdata->mass()),Gamma(wdata->width());
Energy2 M2(sqr(M)),MG(M*Gamma);
double rhomin = atan2((minMass2-M2),MG);
double rhomax = atan2((maxMass2-M2),MG);
_mw2=M2+MG*tan(rhomin+r[1]*(rhomax-rhomin));
Energy mw=sqrt(_mw2);
// jacobian
jacobian(jacobian()*(sqr(_mw2-M2)+sqr(MG))/MG*(rhomax-rhomin)/sHat());
// set the masses of the outgoing particles in the 2-2 scattering
meMomenta()[2].setMass(ZERO);
Lorentz5Momentum pw(mw);
// generate the polar angle of the hard scattering
double ctmin(-1.0), ctmax(1.0);
Energy q(ZERO);
try {
q = SimplePhaseSpace::getMagnitude(sHat(), meMomenta()[2].mass(),mw);
}
catch ( ImpossibleKinematics ) {
return false;
}
Energy2 pq = sqrt(sHat())*q;
if ( ptmin > ZERO ) {
double ctm = 1.0 - sqr(ptmin/q);
if ( ctm <= 0.0 ) return false;
ctmin = max(ctmin, -sqrt(ctm));
ctmax = min(ctmax, sqrt(ctm));
}
if ( ctmin >= ctmax ) return false;
double cth = getCosTheta(ctmin, ctmax, r[0]);
// momenta of particle in hard scattering
Energy pt = q*sqrt(1.0-sqr(cth));
double phi=2.0*Constants::pi*r[2];
meMomenta()[2].setVect(Momentum3( pt*sin(phi), pt*cos(phi), q*cth));
pw.setVect( Momentum3(-pt*sin(phi),-pt*cos(phi),-q*cth));
meMomenta()[2].rescaleEnergy();
pw.rescaleEnergy();
// set the scale
_scale = _mw2+sqr(pt);
// generate the momenta of the W decay products
meMomenta()[3].setMass(mePartonData()[3]->mass());
meMomenta()[4].setMass(mePartonData()[4]->mass());
Energy q2 = ZERO;
try {
q2 = SimplePhaseSpace::getMagnitude(_mw2, meMomenta()[3].mass(),
meMomenta()[4].mass());
} catch ( ImpossibleKinematics ) {
return false;
}
double cth2 =-1.+2.*r[3];
double phi2=Constants::twopi*r[4];
Energy pt2 =q2*sqrt(1.-sqr(cth2));
Lorentz5Momentum pl[2]={Lorentz5Momentum( pt2*cos(phi2), pt2*sin(phi2), q2*cth2,ZERO,
meMomenta()[3].mass()),
Lorentz5Momentum(-pt2*cos(phi2),-pt2*sin(phi2),-q2*cth2,ZERO,
meMomenta()[4].mass())};
pl[0].rescaleEnergy();
pl[1].rescaleEnergy();
Boost boostv(pw.boostVector());
pl[0].boost(boostv);
pl[1].boost(boostv);
meMomenta()[3] = pl[0];
meMomenta()[4] = pl[1];
// check passes all the cuts
vector<LorentzMomentum> out(3);
out[0] = meMomenta()[2];
out[1] = meMomenta()[3];
out[2] = meMomenta()[4];
tcPDVector tout(3);
tout[0] = mePartonData()[2];
tout[1] = mePartonData()[3];
tout[2] = mePartonData()[4];
if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) )
return false;
// jacobian
jacobian((pq/sHat())*Constants::pi*jacobian()/8./sqr(Constants::pi)*q2/mw);
return true;
}
double MEPP2WJet::me2() const {
InvEnergy2 output(ZERO);
// construct spinors for the leptons (always the same)
vector<SpinorBarWaveFunction> lm;
vector<SpinorWaveFunction> lp;
SpinorBarWaveFunction lmout(meMomenta()[3],mePartonData()[3],outgoing);
SpinorWaveFunction lpout(meMomenta()[4],mePartonData()[4],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
lmout.reset(ix);lm.push_back(lmout);
lpout.reset(ix);lp.push_back(lpout);
}
// q g to q W
if(mePartonData()[0]->id()<=6&&mePartonData()[0]->id()>0&&
mePartonData()[1]->id()==ParticleID::g) {
// polarization states for the particles
vector<SpinorWaveFunction> fin;
vector<VectorWaveFunction> gin;
vector<SpinorBarWaveFunction> fout;
SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction glin(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction qout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back(qin);
glin.reset(2*ix); gin.push_back(glin);
qout.reset(ix);fout.push_back(qout);
}
output=qgME(fin,gin,fout,lm,lp);
}
// qbar g to qbar W
else if(mePartonData()[0]->id()>=-6&&mePartonData()[0]->id()<0&&
mePartonData()[1]->id()==ParticleID::g) {
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gin;
vector<SpinorWaveFunction> aout;
SpinorBarWaveFunction qbin (meMomenta()[0],mePartonData()[0],incoming);
VectorWaveFunction glin (meMomenta()[1],mePartonData()[1],incoming);
SpinorWaveFunction qbout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qbin.reset(ix) ; ain.push_back(qbin);
glin.reset(2*ix) ; gin.push_back(glin);
qbout.reset(ix);aout.push_back(qbout);
}
output=qbargME(ain,gin,aout,lm,lp);
}
// q qbar to g W
else {
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gout;
SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming);
VectorWaveFunction glout(meMomenta()[2],mePartonData()[2],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
qin.reset(ix) ; fin.push_back(qin);
qbin.reset(ix) ; ain.push_back(qbin);
glout.reset(2*ix); gout.push_back(glout);
}
output=qqbarME(fin,ain,gout,lm,lp);
}
return output*sHat();
}
InvEnergy2 MEPP2WJet::qqbarME(vector<SpinorWaveFunction> & fin,
vector<SpinorBarWaveFunction> & ain,
vector<VectorWaveFunction> & gout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1,PDT::Spin1Half,
PDT::Spin1Half));
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// find the right W pointer
tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0
? _wplus :_wminus;
// compute the W current for speed
VectorWaveFunction bcurr[2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata,
lp[ohel3],lm[ohel2]);
}
}
double me[3]={0.,0.,0.};
Complex diag[2];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gout[ohel1]);
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[1],
ain[ihel2],gout[ohel1]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0] = _theFFWVertex->evaluate(_mw2,fin[ihel1],interb,
bcurr[ohel2][ohel3]);
diag[1] = _theFFWVertex->evaluate(_mw2,inters,ain[ihel2],
bcurr[ohel2][ohel3]);
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,ihel2,2*ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin=1./9./4.;
// and C_F N_c from matrix element
colspin *= 4.;
// colour factor for the W decay
if(mePartonData()[3]->coloured()) colspin*=3.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix]*=colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0] * UnitRemoval::InvE2;
}
InvEnergy2 MEPP2WJet::qgME(vector<SpinorWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half));
// find the right W pointer
tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ?
_wplus :_wminus;
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// compute the leptonic W current for speed
VectorWaveFunction bcurr[2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata,
lp[ohel3],lm[ohel2]);
}
}
// compute the matrix elements
double me[3]={0.,0.,0.};
Complex diag[2];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[2],
fout[ohel1],gin[ihel2]);
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gin[ihel2]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0]=_theFFWVertex->evaluate(_mw2,fin[ihel1],interb,
bcurr[ohel2][ohel3]);
diag[1]=_theFFWVertex->evaluate(_mw2,inters,fout[ohel1],
bcurr[ohel2][ohel3]);
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin=1./24./4.;
// and C_F N_c from matrix element
colspin *=4.;
// colour factor for the W decay
if(mePartonData()[3]->coloured()) colspin*=3.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix]*=colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0] * UnitRemoval::InvE2;
}
InvEnergy2 MEPP2WJet::qbargME(vector<SpinorBarWaveFunction> & fin,
vector<VectorWaveFunction> & gin,
vector<SpinorWaveFunction> & fout,
vector<SpinorBarWaveFunction> & lm,
vector<SpinorWaveFunction> & lp,
bool calc) const {
// if calculation spin corrections construct the me
if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1,
PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half));
// find the right W pointer
tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ?
_wplus :_wminus;
// some integers
unsigned int ihel1,ihel2,ohel1,ohel2,ohel3;
// compute the leptonic W current for speed
VectorWaveFunction bcurr[2][2];
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata,
lp[ohel3],lm[ohel2]);
}
}
// compute the matrix elements
double me[3]={0.,0.,0.};
Complex diag[2];
SpinorWaveFunction inters;
SpinorBarWaveFunction interb;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
// intermediates for the diagrams
inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[2]->CC(),
fout[ohel1],gin[ihel2]);
interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[0],
fin[ihel1],gin[ihel2]);
for(ohel2=0;ohel2<2;++ohel2) {
for(ohel3=0;ohel3<2;++ohel3) {
diag[0]= _theFFWVertex->evaluate(_mw2,inters,fin[ihel1],
bcurr[ohel2][ohel3]);
diag[1]= _theFFWVertex->evaluate(_mw2,fout[ohel1],interb,
bcurr[ohel2][ohel3]);
// diagram contributions
me[1] += norm(diag[0]);
me[2] += norm(diag[1]);
// total
diag[0] += diag[1];
me[0] += norm(diag[0]);
if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0];
}
}
}
}
}
// results
// initial state spin and colour average
double colspin=1./24./4.;
// and C_F N_c from matrix element
colspin *= 4.;
// colour factor for the W decay
if(mePartonData()[3]->coloured()) colspin*=3.;
DVector save;
for(unsigned int ix=0;ix<3;++ix) {
me[ix]*=colspin;
if(ix>0) save.push_back(me[ix]);
}
meInfo(save);
return me[0] * UnitRemoval::InvE2;
}
void MEPP2WJet::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard(5);
// incoming
hard[0]=sub->incoming().first;
hard[1]=sub->incoming().second;
if((hard[0]->id()<0&&hard[1]->id()<=6)||
hard[0]->id()==ParticleID::g) swap(hard[0],hard[1]);
// outgoing
for(unsigned int ix=0;ix<3;++ix) {
unsigned int iloc;
PPtr mother=sub->outgoing()[ix]->parents()[0];
if(mother&&abs(mother->id())==ParticleID::Wplus) {
if(sub->outgoing()[ix]->id()>0) iloc=3;
else iloc=4;
}
else iloc=2;
hard[iloc]=sub->outgoing()[ix];
}
// wavefunctions for the W decay products
vector<SpinorBarWaveFunction> lm;
vector<SpinorWaveFunction> lp;
SpinorBarWaveFunction(lm,hard[3],outgoing,true,true);
SpinorWaveFunction (lp,hard[4],outgoing,true,true);
// identify hard process and calculate matrix element
// q g to q W
if(hard[0]->id()<=6&&hard[0]->id()>0&&hard[1]->id()==ParticleID::g) {
vector<SpinorWaveFunction> fin;
vector<VectorWaveFunction> gin;
vector<SpinorBarWaveFunction> fout;
SpinorWaveFunction (fin ,hard[0],incoming,false,true);
VectorWaveFunction (gin ,hard[1],incoming,false,true,true);
SpinorBarWaveFunction (fout,hard[2],outgoing,true ,true);
gin[1]=gin[2];
qgME(fin,gin,fout,lm,lp,true);
}
// qbar g to qbar W
else if(hard[0]->id()>=-6&&hard[0]->id()<0&&hard[1]->id()==ParticleID::g) {
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gin;
vector<SpinorWaveFunction> aout;
SpinorBarWaveFunction(ain ,hard[0],incoming,false,true);
VectorWaveFunction (gin ,hard[1],incoming,false,true,true);
SpinorWaveFunction (aout,hard[2],outgoing,true ,true);
gin[1]=gin[2];
qbargME(ain,gin,aout,lm,lp,true);
}
// q qbar to g W
else {
vector<SpinorWaveFunction> fin;
vector<SpinorBarWaveFunction> ain;
vector<VectorWaveFunction> gout;
SpinorWaveFunction (fin ,hard[0],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[1],incoming,false,true);
VectorWaveFunction (gout,hard[2],outgoing,true ,true,true);
gout[1]=gout[2];
qqbarME(fin,ain,gout,lm,lp,true);
}
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<5;++ix)
(hard[ix]->spinInfo())->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Hadron/MEqq2W2ff.cc b/MatrixElement/Hadron/MEqq2W2ff.cc
--- a/MatrixElement/Hadron/MEqq2W2ff.cc
+++ b/MatrixElement/Hadron/MEqq2W2ff.cc
@@ -1,357 +1,361 @@
// -*- C++ -*-
//
// MEqq2W2ff.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MEqq2W2ff class.
//
#include "MEqq2W2ff.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/StandardModel/StandardModelBase.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/MatrixElement/HardVertex.h"
#include <cassert>
using namespace Herwig;
MEqq2W2ff::MEqq2W2ff() : _maxflavour(5), _plusminus(0), _process(0) {
massOption(vector<unsigned int>(2,1));
}
void MEqq2W2ff::doinit() {
DrellYanBase::doinit();
_wp=getParticleData(ThePEG::ParticleID::Wplus);
_wm=getParticleData(ThePEG::ParticleID::Wminus);
// cast the SM pointer to the Herwig SM pointer
tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast<tcHwSMPtr>(standardModel());
// do the initialisation
if(hwsm)
_theFFWVertex = hwsm->vertexFFW();
else
throw InitException() << "Must be the Herwig StandardModel class in "
<< "MEqq2W2ff::doinit" << Exception::abortnow;
}
void MEqq2W2ff::getDiagrams() const {
// which intgermediates to include
bool wplus =_plusminus==0||_plusminus==1;
bool wminus=_plusminus==0||_plusminus==2;
// possible incoming and outgoing particles
typedef std::vector<pair<long,long> > Pairvector;
// possible parents
Pairvector parentpair;
parentpair.reserve(6);
// don't even think of putting 'break' in here!
switch(_maxflavour) {
case 5:
parentpair.push_back(make_pair(ParticleID::b, ParticleID::cbar));
parentpair.push_back(make_pair(ParticleID::b, ParticleID::ubar));
+ [[fallthrough]];
case 4:
parentpair.push_back(make_pair(ParticleID::s, ParticleID::cbar));
parentpair.push_back(make_pair(ParticleID::d, ParticleID::cbar));
+ [[fallthrough]];
case 3:
parentpair.push_back(make_pair(ParticleID::s, ParticleID::ubar));
+ [[fallthrough]];
case 2:
parentpair.push_back(make_pair(ParticleID::d, ParticleID::ubar));
+ [[fallthrough]];
default:
;
}
// possible children
Pairvector childpair;
childpair.reserve(9);
childpair.push_back(make_pair(ParticleID::eminus, ParticleID::nu_ebar));
childpair.push_back(make_pair(ParticleID::muminus, ParticleID::nu_mubar));
childpair.push_back(make_pair(ParticleID::tauminus, ParticleID::nu_taubar));
childpair.push_back(make_pair(ParticleID::d, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::s, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::b, ParticleID::ubar));
childpair.push_back(make_pair(ParticleID::d, ParticleID::cbar));
childpair.push_back(make_pair(ParticleID::s, ParticleID::cbar));
childpair.push_back(make_pair(ParticleID::b, ParticleID::cbar));
// loop over the children
bool lepton,quark;
Pairvector::const_iterator child = childpair.begin();
for (; child != childpair.end(); ++child) {
assert(child->first > 0 && child->second < 0);
// allowed leptonic decay
lepton = child->first > 10 && (_process==0
|| _process==2
|| (child->first - 5)/2 == int(_process));
// allowed quark decay
quark = child->first < 10 && (_process==0
|| _process==1
|| (child->second == -2 && (child->first + 11)/2 == int(_process))
|| (child->second == -4 && (child->first + 17)/2 == int(_process))
);
// if decay not allowed skip
if(!(quark || lepton)) continue;
// decay products
tcPDPtr lNeg1 = getParticleData(child->first);
tcPDPtr lNeg2 = getParticleData(child->second);
tcPDPtr lPos1 = lNeg2->CC();
tcPDPtr lPos2 = lNeg1->CC();
Pairvector::const_iterator parent = parentpair.begin();
for (; parent != parentpair.end(); ++parent) {
// parents
tcPDPtr qNeg1 = getParticleData(parent->first);
tcPDPtr qNeg2 = getParticleData(parent->second);
tcPDPtr qPos1 = qNeg2->CC();
tcPDPtr qPos2 = qNeg1->CC();
// diagrams
if(wminus) add(new_ptr((Tree2toNDiagram(2),
qNeg1, qNeg2,
1, _wm,
3, lNeg1, 3, lNeg2, -1)));
if(wplus) add(new_ptr((Tree2toNDiagram(2),
qPos1, qPos2,
1, _wp,
3, lPos1, 3, lPos2, -2)));
}
}
}
Energy2 MEqq2W2ff::scale() const {
return sHat();
}
double MEqq2W2ff::me2() const {
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction q (meMomenta()[0],mePartonData()[0],incoming);
SpinorBarWaveFunction qbar(meMomenta()[1],mePartonData()[1],incoming);
SpinorBarWaveFunction f (meMomenta()[2],mePartonData()[2],outgoing);
SpinorWaveFunction fbar(meMomenta()[3],mePartonData()[3],outgoing);
for(unsigned int ix=0;ix<2;++ix) {
q.reset(ix) ; fin.push_back(q);
qbar.reset(ix); ain.push_back(qbar);
f.reset(ix) ;fout.push_back(f);
fbar.reset(ix);aout.push_back(fbar);
}
return qqbarME(fin,ain,fout,aout,false);
}
unsigned int MEqq2W2ff::orderInAlphaS() const {
return 0;
}
unsigned int MEqq2W2ff::orderInAlphaEW() const {
return 2;
}
Selector<MEBase::DiagramIndex>
MEqq2W2ff::diagrams(const DiagramVector &) const {
Selector<DiagramIndex> sel;
sel.insert(1.0, 0);
return sel;
}
Selector<const ColourLines *>
MEqq2W2ff::colourGeometries(tcDiagPtr) const {
static const ColourLines c1("1 -2");
static const ColourLines c2("1 -2,4 -5");
Selector<const ColourLines *> sel;
if(abs(mePartonData()[2]->id())<=6) sel.insert(1.0, &c2);
else sel.insert(1.0, &c1);
return sel;
}
void MEqq2W2ff::persistentOutput(PersistentOStream & os) const {
os << _maxflavour << _plusminus << _process << _theFFWVertex << _wp << _wm;
}
void MEqq2W2ff::persistentInput(PersistentIStream & is, int) {
is >> _maxflavour >> _plusminus >> _process >> _theFFWVertex >> _wp >> _wm;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<MEqq2W2ff,DrellYanBase>
describeHerwigMEqq2W2ff("Herwig::MEqq2W2ff", "HwMEHadron.so");
void MEqq2W2ff::Init() {
static ClassDocumentation<MEqq2W2ff> documentation
("The MEqq2W2ff class implements the matrix element for"
"q qbar to Standard Model fermions via W exchange using helicity amplitude"
"techniques");
static Parameter<MEqq2W2ff,unsigned int> interfaceMaxFlavour
( "MaxFlavour",
"The heaviest incoming quark flavour this matrix element is allowed to handle "
"(if applicable).",
&MEqq2W2ff::_maxflavour, 5, 0, 5, false, false, true);
static Switch<MEqq2W2ff,unsigned int> interfacePlusMinus
("Wcharge",
"Which intermediate W bosons to include",
&MEqq2W2ff::_plusminus, 0, false, false);
static SwitchOption interfacePlusMinusAll
(interfacePlusMinus,
"Both",
"Include W+ and W-",
0);
static SwitchOption interfacePlusMinusPlus
(interfacePlusMinus,
"Plus",
"Only include W+",
1);
static SwitchOption interfacePlusMinusMinus
(interfacePlusMinus,
"Minus",
"Only include W-",
2);
static Switch<MEqq2W2ff,unsigned int> interfaceProcess
("Process",
"Which processes to include",
&MEqq2W2ff::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all SM fermions as outgoing particles",
0);
static SwitchOption interfaceProcessQuarks
(interfaceProcess,
"Quarks",
"Only include outgoing quarks",
1);
static SwitchOption interfaceProcessLeptons
(interfaceProcess,
"Leptons",
"All include outgoing leptons",
2);
static SwitchOption interfaceProcessElectron
(interfaceProcess,
"Electron",
"Only include outgoing e nu_e",
3);
static SwitchOption interfaceProcessMuon
(interfaceProcess,
"Muon",
"Only include outgoing mu nu_mu",
4);
static SwitchOption interfaceProcessTau
(interfaceProcess,
"Tau",
"Only include outgoing tauu nu_tau",
5);
static SwitchOption interfaceProcessUpDown
(interfaceProcess,
"UpDown",
"Only include outgoing u dbar/ d ubar",
6);
static SwitchOption interfaceProcessUpStrange
(interfaceProcess,
"UpStrange",
"Only include outgoing u sbar/ s ubar",
7);
static SwitchOption interfaceProcessUpBottom
(interfaceProcess,
"UpBottom",
"Only include outgoing u bbar/ b ubar",
8);
static SwitchOption interfaceProcessCharmDown
(interfaceProcess,
"CharmDown",
"Only include outgoing c dbar/ d cbar",
9);
static SwitchOption interfaceProcessCharmStrange
(interfaceProcess,
"CharmStrange",
"Only include outgoing c sbar/ s cbar",
10);
static SwitchOption interfaceProcessCharmBottom
(interfaceProcess,
"CharmBottom",
"Only include outgoing c bbar/ b cbar",
11);
}
double MEqq2W2ff::qqbarME(vector<SpinorWaveFunction> & fin ,
vector<SpinorBarWaveFunction> & ain ,
vector<SpinorBarWaveFunction> & fout,
vector<SpinorWaveFunction> & aout,
bool calc) const {
// matrix element to be stored
ProductionMatrixElement newme(PDT::Spin1Half,PDT::Spin1Half,
PDT::Spin1Half,PDT::Spin1Half);
// positive or negative W boson
bool positive = mePartonData()[0]->iCharge()
+ mePartonData()[1]->iCharge() > 0;
unsigned int ihel1,ihel2,ohel1,ohel2;
// sum over helicities to get the matrix element
double me = 0.;
VectorWaveFunction inter;
for(ihel1=0;ihel1<2;++ihel1) {
for(ihel2=0;ihel2<2;++ihel2) {
for(ohel1=0;ohel1<2;++ohel1) {
for(ohel2=0;ohel2<2;++ohel2) {
Complex diag = 0.0;
if (positive) {
// the Wp exchange
inter = _theFFWVertex->evaluate(scale(),1,_wp,fin[ihel1],ain[ihel2]);
diag = _theFFWVertex->evaluate(scale(),aout[ohel2],fout[ohel1],inter);
}
else {
// the Wm exchange
inter = _theFFWVertex->evaluate(scale(),1,_wm,fin[ihel1],ain[ihel2]);
diag = _theFFWVertex->evaluate(scale(),aout[ohel2],fout[ohel1],inter);
}
// sum over helicities
me += real(diag*conj(diag));
if(calc) newme(ihel1,ihel2,ohel1,ohel2) = diag;
}
}
}
}
// results
// spin and colour factor
double colspin=1./12.;
if(abs(fout[0].id())<=6) colspin*=3.;
if(calc) _me.reset(newme);
return me*colspin;
}
void MEqq2W2ff::constructVertex(tSubProPtr sub) {
// extract the particles in the hard process
ParticleVector hard;
hard.push_back(sub->incoming().first);hard.push_back(sub->incoming().second);
hard.push_back(sub->outgoing()[0]);hard.push_back(sub->outgoing()[1]);
// order of particles
unsigned int order[4]={0,1,2,3};
if(hard[0]->id()<0){order[0]=1;order[1]=0;}
if(hard[2]->id()<0){order[2]=3;order[3]=2;}
vector<SpinorWaveFunction> fin,aout;
vector<SpinorBarWaveFunction> ain,fout;
SpinorWaveFunction( fin ,hard[order[0]],incoming,false,true);
SpinorBarWaveFunction(ain ,hard[order[1]],incoming,false,true);
SpinorBarWaveFunction(fout,hard[order[2]],outgoing,true ,true);
SpinorWaveFunction( aout,hard[order[3]],outgoing,true ,true);
qqbarME(fin,ain,fout,aout,true);
// construct the vertex
HardVertexPtr hardvertex=new_ptr(HardVertex());
// set the matrix element for the vertex
hardvertex->ME(_me);
// set the pointers and to and from the vertex
for(unsigned int ix=0;ix<4;++ix)
hard[order[ix]]->spinInfo()->productionVertex(hardvertex);
}
diff --git a/MatrixElement/Matchbox/Builtin/Amplitudes/Makefile.am b/MatrixElement/Matchbox/Builtin/Amplitudes/Makefile.am
--- a/MatrixElement/Matchbox/Builtin/Amplitudes/Makefile.am
+++ b/MatrixElement/Matchbox/Builtin/Amplitudes/Makefile.am
@@ -1,72 +1,72 @@
pkglib_LTLIBRARIES = HwMatchboxBuiltin.la
HwMatchboxBuiltin_la_LDFLAGS = \
-$(AM_LDFLAGS) -module -version-info 4:0:0
+$(AM_LDFLAGS) -module -version-info 4:1:0
nodist_HwMatchboxBuiltin_la_SOURCES = \
Amplitudes__all.cc
BUILT_SOURCES = Amplitudes__all.cc
CLEANFILES = Amplitudes__all.cc
Amplitudes__all.cc : $(DIR_H_FILES) $(DIR_CC_FILES) Makefile
@echo "Concatenating .cc files into $@"
@$(top_srcdir)/cat_with_cpplines $(DIR_CC_FILES) > $@
EXTRA_DIST = $(ALL_H_FILES) $(ALL_CC_FILES)
DIR_H_FILES = $(addprefix $(srcdir)/,$(ALL_H_FILES))
ALL_H_FILES = \
MatchboxCurrents.h \
MatchboxZGammaAmplitude.h \
MatchboxAmplitudellbarqqbargg.h \
MatchboxAmplitudellbarqqbarg.h \
MatchboxAmplitudellbarqqbar.h \
MatchboxAmplitudellbarqqbarqqbar.h \
MatchboxAmplitudelnuqqbargg.h \
MatchboxAmplitudelnuqqbarg.h \
MatchboxAmplitudelnuqqbar.h \
MatchboxAmplitudelnuqqbarqqbar.h \
MatchboxAmplitudehbbbarg.h \
MatchboxAmplitudehbbbar.h \
MatchboxAmplitudehggg.h \
MatchboxAmplitudehgg.h \
MatchboxAmplitudehqqbarg.h \
MatchboxAmplitudeqqbarttbar.h \
MatchboxAmplitudeqqbarttbarg.h \
MatchboxAmplitudeggttbar.h \
MatchboxAmplitudeggttbarg.h \
HelAmps_sm.h \
Parameters_sm.h \
MG_qqx2ttx.h \
MG_qqx2ttxg.h \
MG_gg2ttx.h \
MG_gg2ttxg.h
DIR_CC_FILES = $(addprefix $(srcdir)/,$(ALL_CC_FILES))
ALL_CC_FILES = \
MatchboxCurrents.cc \
MatchboxZGammaAmplitude.cc \
MatchboxAmplitudellbarqqbar.cc \
MatchboxAmplitudellbarqqbarg.cc \
MatchboxAmplitudellbarqqbargg.cc \
MatchboxAmplitudellbarqqbarqqbar.cc \
MatchboxAmplitudelnuqqbar.cc \
MatchboxAmplitudelnuqqbarg.cc \
MatchboxAmplitudelnuqqbargg.cc \
MatchboxAmplitudelnuqqbarqqbar.cc \
MatchboxAmplitudehbbbar.cc \
MatchboxAmplitudehbbbarg.cc \
MatchboxAmplitudehgg.cc \
MatchboxAmplitudehggg.cc \
MatchboxAmplitudehqqbarg.cc \
MatchboxAmplitudeqqbarttbar.cc \
MatchboxAmplitudeqqbarttbarg.cc \
MatchboxAmplitudeggttbar.cc \
MatchboxAmplitudeggttbarg.cc \
HelAmps_sm.cc \
Parameters_sm.cc \
MG_qqx2ttx.cc \
MG_qqx2ttxg.cc \
MG_gg2ttx.cc \
MG_gg2ttxg.cc
diff --git a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbar.cc b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbar.cc
--- a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbar.cc
+++ b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbar.cc
@@ -1,184 +1,192 @@
// -*- C++ -*-
//
// MatchboxAmplitudelnuqqbar.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MatchboxAmplitudelnuqqbar class.
//
#include "Herwig/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbar.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
using namespace Herwig;
MatchboxAmplitudelnuqqbar::MatchboxAmplitudelnuqqbar()
: theDiagonal(false) {}
MatchboxAmplitudelnuqqbar::~MatchboxAmplitudelnuqqbar() {}
void MatchboxAmplitudelnuqqbar::doinit() {
MatchboxAmplitude::doinit();
+ MZ = getParticleData(ParticleID::Z0)->hardProcessMass();
+ GZ = getParticleData(ParticleID::Z0)->hardProcessWidth();
MW = getParticleData(ParticleID::Wplus)->hardProcessMass();
GW = getParticleData(ParticleID::Wplus)->hardProcessWidth();
CA = SM().Nc();
CF = (SM().Nc()*SM().Nc()-1.)/(2.*SM().Nc());
theCKM = standardCKM(SM())->getUnsquaredMatrix(6);
nPoints(4);
}
void MatchboxAmplitudelnuqqbar::doinitrun() {
MatchboxAmplitude::doinitrun();
+ MZ = getParticleData(ParticleID::Z0)->hardProcessMass();
+ GZ = getParticleData(ParticleID::Z0)->hardProcessWidth();
+ MW = getParticleData(ParticleID::Wplus)->hardProcessMass();
+ GW = getParticleData(ParticleID::Wplus)->hardProcessWidth();
+ CA = SM().Nc();
+ CF = (SM().Nc()*SM().Nc()-1.)/(2.*SM().Nc());
nPoints(4);
}
IBPtr MatchboxAmplitudelnuqqbar::clone() const {
return new_ptr(*this);
}
IBPtr MatchboxAmplitudelnuqqbar::fullclone() const {
return new_ptr(*this);
}
bool MatchboxAmplitudelnuqqbar::canHandle(const PDVector& proc) const {
PDVector xproc = proc;
if ( xproc[0]->CC() )
xproc[0] = xproc[0]->CC();
if ( xproc[1]->CC() )
xproc[1] = xproc[1]->CC();
PDVector::iterator elektron = xproc.begin();
for ( ; elektron != xproc.end(); ++elektron )
if ( abs((*elektron)->id()) >= 11 && abs((*elektron)->id()) <= 16 && abs((*elektron)->id()) % 2 == 1 ) break;
if ( elektron == xproc.end() ) return false;
PDPtr e = *elektron;
xproc.erase(elektron);
PDVector::iterator neutrino = xproc.begin();
for ( ; neutrino != xproc.end(); ++neutrino )
if ( abs((*neutrino)->id()) >= 11 && abs((*neutrino)->id()) <= 16 && abs((*neutrino)->id()) % 2 == 0 ) break;
if ( neutrino == xproc.end() ) return false;
PDPtr n = *neutrino;
xproc.erase(neutrino);
PDVector::iterator quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 && abs((*quark)->id()) % 2 == 1 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr d = *quark;
xproc.erase(quark);
quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 && abs((*quark)->id()) % 2 == 0 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr u = *quark;
xproc.erase(quark);
if ( u->iCharge() + d->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(u) != SU2Helper::family(d) ) return false;
if ( SU2Helper::family(e) != SU2Helper::family(n) ) return false;
return xproc.empty();
}
void MatchboxAmplitudelnuqqbar::prepareAmplitudes(Ptr<MatchboxMEBase>::tcptr me) {
if ( !calculateTreeAmplitudes() ) {
MatchboxAmplitude::prepareAmplitudes(me);
return;
}
amplitudeScale(sqrt(lastSHat()));
setupLeptons(0,amplitudeMomentum(0),1,amplitudeMomentum(1));
momentum(2,amplitudeMomentum(2));
momentum(3,amplitudeMomentum(3));
MatchboxAmplitude::prepareAmplitudes(me);
}
Complex MatchboxAmplitudelnuqqbar::evaluate(size_t, const vector<int>& hel, Complex& largeN) {
if ( abs(hel[2]+hel[3]) != 2 ) {
largeN = 0.;
return 0.;
}
Complex ckmelement = 1.;
if ( !theDiagonal ) {
bool wPlus = ( abs(amplitudePartonData()[0]->id()) % 2 == 0 ) ?
amplitudePartonData()[1]->id() < 0:
amplitudePartonData()[0]->id() < 0;
pair<int,int> tmp(
SU2Helper::family(amplitudePartonData()[2])-1,
SU2Helper::family(amplitudePartonData()[3])-1);
if ( amplitudePartonData()[3]->id() < 0 ) swap(tmp.first,tmp.second);
ckmelement = theCKM[tmp.first][tmp.second];
if ( !wPlus ) ckmelement = conj(ckmelement);
}
Complex wPropergator =
1./Complex(((amplitudeMomentum(0)+amplitudeMomentum(1)).m2()-sqr(MW))/lastSHat(),MW*GW/lastSHat());
Complex wVertices =
2.*SM().alphaEMMZ()*Constants::pi/SM().sin2ThetaW()*ckmelement;
const LorentzVector<Complex>& leptonCurrent = llbarLeftCurrent(0,hel[0],1,hel[1]);
const LorentzVector<Complex>& quarkCurrent = qqbarLeftCurrent(2,hel[2],3,hel[3]);
Complex current = hel[2] == 1 ? Complex(0.,-1)*leptonCurrent.dot(quarkCurrent): 0.;
Complex res = current*wVertices*wPropergator;
largeN = res;
return res;
}
Complex MatchboxAmplitudelnuqqbar::evaluateOneLoop(size_t, const vector<int>& hel) {
if ( abs(hel[2]+hel[3]) != 2 ) return 0.;
Complex ckmelement = 1.;
if ( !theDiagonal ) {
bool wPlus = ( abs(amplitudePartonData()[0]->id()) % 2 == 0 ) ?
amplitudePartonData()[1]->id() < 0:
amplitudePartonData()[0]->id() < 0;
pair<int,int> tmp(
SU2Helper::family(amplitudePartonData()[2])-1,
SU2Helper::family(amplitudePartonData()[3])-1);
if ( amplitudePartonData()[3]->id() < 0 ) swap(tmp.first,tmp.second);
ckmelement = theCKM[tmp.first][tmp.second];
if ( !wPlus ) ckmelement = conj(ckmelement);
}
Complex wPropergator =
1./Complex(((amplitudeMomentum(0)+amplitudeMomentum(1)).m2()-sqr(MW))/lastSHat(),MW*GW/lastSHat());
Complex wVertices =
2.*SM().alphaEMMZ()*Constants::pi/SM().sin2ThetaW()*ckmelement;
const LorentzVector<Complex>& leptonCurrent = llbarLeftCurrent(0,hel[0],1,hel[1]);
const LorentzVector<Complex>& quarkCurrent = qqbarLeftOneLoopCurrent(2,hel[2],3,hel[3]);
Complex current = hel[2] == 1 ? Complex(0.,-1)*leptonCurrent.dot(quarkCurrent): 0.;
Complex res = (SM().alphaS()/(2.*Constants::pi))*current*wVertices*wPropergator;
return res;
}
void MatchboxAmplitudelnuqqbar::persistentOutput(PersistentOStream & os) const {
- os << theDiagonal << theCKM << ounit(MW,GeV) << ounit(GW,GeV) << CA << CF;
+ os << theDiagonal << theCKM ;
}
void MatchboxAmplitudelnuqqbar::persistentInput(PersistentIStream & is, int) {
- is >> theDiagonal >> theCKM >> iunit(MW,GeV) >> iunit(GW,GeV) >> CA >> CF;
+ is >> theDiagonal >> theCKM ;
}
DescribeClass<MatchboxAmplitudelnuqqbar,MatchboxAmplitude>
describeHerwigMatchboxAmplitudelnuqqbar("Herwig::MatchboxAmplitudelnuqqbar", "HwMatchboxBuiltin.so");
void MatchboxAmplitudelnuqqbar::Init() {
static ClassDocumentation<MatchboxAmplitudelnuqqbar> documentation
("MatchboxAmplitudelnuqqbar");
static Switch<MatchboxAmplitudelnuqqbar,bool> interfaceDiagonal
("Diagonal",
"Use a diagonal CKM matrix (ignoring the CKM object of the StandardModel).",
&MatchboxAmplitudelnuqqbar::theDiagonal, false, false, false);
static SwitchOption interfaceDiagonalYes
(interfaceDiagonal,
"Yes",
"Use a diagonal CKM matrix.",
true);
static SwitchOption interfaceDiagonalNo
(interfaceDiagonal,
"No",
"Use the CKM object as used by the StandardModel.",
false);
}
diff --git a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarg.cc b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarg.cc
--- a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarg.cc
+++ b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarg.cc
@@ -1,195 +1,203 @@
// -*- C++ -*-
//
// MatchboxAmplitudelnuqqbarg.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MatchboxAmplitudelnuqqbarg class.
//
#include "Herwig/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarg.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
using namespace Herwig;
MatchboxAmplitudelnuqqbarg::MatchboxAmplitudelnuqqbarg()
: theDiagonal(false) {}
MatchboxAmplitudelnuqqbarg::~MatchboxAmplitudelnuqqbarg() {}
void MatchboxAmplitudelnuqqbarg::doinit() {
MatchboxAmplitude::doinit();
+ MZ = getParticleData(ParticleID::Z0)->hardProcessMass();
+ GZ = getParticleData(ParticleID::Z0)->hardProcessWidth();
MW = getParticleData(ParticleID::Wplus)->hardProcessMass();
GW = getParticleData(ParticleID::Wplus)->hardProcessWidth();
CA = SM().Nc();
CF = (SM().Nc()*SM().Nc()-1.)/(2.*SM().Nc());
theCKM = standardCKM(SM())->getUnsquaredMatrix(6);
nPoints(5);
}
void MatchboxAmplitudelnuqqbarg::doinitrun() {
MatchboxAmplitude::doinitrun();
+ MZ = getParticleData(ParticleID::Z0)->hardProcessMass();
+ GZ = getParticleData(ParticleID::Z0)->hardProcessWidth();
+ MW = getParticleData(ParticleID::Wplus)->hardProcessMass();
+ GW = getParticleData(ParticleID::Wplus)->hardProcessWidth();
+ CA = SM().Nc();
+ CF = (SM().Nc()*SM().Nc()-1.)/(2.*SM().Nc());
nPoints(5);
}
IBPtr MatchboxAmplitudelnuqqbarg::clone() const {
return new_ptr(*this);
}
IBPtr MatchboxAmplitudelnuqqbarg::fullclone() const {
return new_ptr(*this);
}
bool MatchboxAmplitudelnuqqbarg::canHandle(const PDVector& proc) const {
PDVector xproc = proc;
if ( xproc[0]->CC() )
xproc[0] = xproc[0]->CC();
if ( xproc[1]->CC() )
xproc[1] = xproc[1]->CC();
PDVector::iterator elektron = xproc.begin();
for ( ; elektron != xproc.end(); ++elektron )
if ( abs((*elektron)->id()) >= 11 && abs((*elektron)->id()) <= 16 && abs((*elektron)->id()) % 2 == 1 ) break;
if ( elektron == xproc.end() ) return false;
PDPtr e = *elektron;
xproc.erase(elektron);
PDVector::iterator neutrino = xproc.begin();
for ( ; neutrino != xproc.end(); ++neutrino )
if ( abs((*neutrino)->id()) >= 11 && abs((*neutrino)->id()) <= 16 && abs((*neutrino)->id()) % 2 == 0 ) break;
if ( neutrino == xproc.end() ) return false;
PDPtr n = *neutrino;
xproc.erase(neutrino);
PDVector::iterator quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 && abs((*quark)->id()) % 2 == 1 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr d = *quark;
xproc.erase(quark);
quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 && abs((*quark)->id()) % 2 == 0 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr u = *quark;
xproc.erase(quark);
PDVector::iterator gluon = xproc.begin();
for ( ; gluon != xproc.end(); ++gluon )
if ( (*gluon)->id() == 21 ) break;
if ( gluon == xproc.end() ) return false;
xproc.erase(gluon);
if ( SU2Helper::family(e) != SU2Helper::family(n) ) return false;
if ( u->iCharge() + d->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(u) != SU2Helper::family(d) ) return false;
return xproc.empty();
}
void MatchboxAmplitudelnuqqbarg::prepareAmplitudes(Ptr<MatchboxMEBase>::tcptr me) {
if ( !calculateTreeAmplitudes() ) {
MatchboxAmplitude::prepareAmplitudes(me);
return;
}
amplitudeScale(sqrt(lastSHat()));
setupLeptons(0,amplitudeMomentum(0),1,amplitudeMomentum(1));
momentum(2,amplitudeMomentum(2));
momentum(3,amplitudeMomentum(3));
momentum(4,amplitudeMomentum(4));
MatchboxAmplitude::prepareAmplitudes(me);
}
Complex MatchboxAmplitudelnuqqbarg::evaluate(size_t, const vector<int>& hel, Complex& largeN) {
if ( abs(hel[2]+hel[3]) != 2 ) {
largeN = 0.;
return 0.;
}
Complex ckmelement = 1.;
if ( !theDiagonal ) {
bool wPlus = ( abs(amplitudePartonData()[0]->id()) % 2 == 0 ) ?
amplitudePartonData()[1]->id() < 0:
amplitudePartonData()[0]->id() < 0;
pair<int,int> tmp(
SU2Helper::family(amplitudePartonData()[2])-1,
SU2Helper::family(amplitudePartonData()[3])-1);
if ( amplitudePartonData()[3]->id() < 0 ) swap(tmp.first,tmp.second);
ckmelement = theCKM[tmp.first][tmp.second];
if ( !wPlus ) ckmelement = conj(ckmelement);
}
Complex wPropergator =
1./Complex(((amplitudeMomentum(0)+amplitudeMomentum(1)).m2()-sqr(MW))/lastSHat(),MW*GW/lastSHat());
Complex wVertices =
2.*SM().alphaEMMZ()*Constants::pi/SM().sin2ThetaW()*ckmelement;
Complex sVertex =
sqrt(4.*Constants::pi*SM().alphaS());
const LorentzVector<Complex>& leptonCurrent = llbarLeftCurrent(0,hel[0],1,hel[1]);
const LorentzVector<Complex>& quarkCurrent = qqbargLeftCurrent(2,hel[2],3,hel[3],4,hel[4]);
Complex current = hel[2] == 1 ? Complex(0.,-1)*leptonCurrent.dot(quarkCurrent): 0.;
Complex res = current*wVertices*wPropergator*sVertex;
largeN = res;
return res;
}
Complex MatchboxAmplitudelnuqqbarg::evaluateOneLoop(size_t, const vector<int>& hel) {
if ( abs(hel[2]+hel[3]) != 2 ) return 0.;
Complex ckmelement = 1.;
if ( !theDiagonal ) {
bool wPlus = ( abs(amplitudePartonData()[0]->id()) % 2 == 0 ) ?
amplitudePartonData()[1]->id() < 0:
amplitudePartonData()[0]->id() < 0;
pair<int,int> tmp(
SU2Helper::family(amplitudePartonData()[2])-1,
SU2Helper::family(amplitudePartonData()[3])-1);
if ( amplitudePartonData()[3]->id() < 0 ) swap(tmp.first,tmp.second);
ckmelement = theCKM[tmp.first][tmp.second];
if ( !wPlus ) ckmelement = conj(ckmelement);
}
Complex wPropergator =
1./Complex(((amplitudeMomentum(0)+amplitudeMomentum(1)).m2()-sqr(MW))/lastSHat(),MW*GW/lastSHat());
Complex wVertices =
2.*SM().alphaEMMZ()*Constants::pi/SM().sin2ThetaW()*ckmelement;
Complex sVertex =
sqrt(4.*Constants::pi*SM().alphaS());
const LorentzVector<Complex>& leptonCurrent = llbarLeftCurrent(0,hel[0],1,hel[1]);
const LorentzVector<Complex>& quarkCurrent = qqbargLeftOneLoopCurrent(2,hel[2],3,hel[3],4,hel[4]);
Complex current = hel[2] == 1 ? Complex(0.,-1)*leptonCurrent.dot(quarkCurrent): 0.;
Complex res = (SM().alphaS()/(2.*Constants::pi))*current*wVertices*wPropergator*sVertex;
return res;
}
void MatchboxAmplitudelnuqqbarg::persistentOutput(PersistentOStream & os) const {
- os << theDiagonal << theCKM << ounit(MW,GeV) << ounit(GW,GeV) << CA << CF;
+ os << theDiagonal << theCKM ;
}
void MatchboxAmplitudelnuqqbarg::persistentInput(PersistentIStream & is, int) {
- is >> theDiagonal >> theCKM >> iunit(MW,GeV) >> iunit(GW,GeV) >> CA >> CF;
+ is >> theDiagonal >> theCKM ;
}
DescribeClass<MatchboxAmplitudelnuqqbarg,MatchboxAmplitude>
describeHerwigMatchboxAmplitudelnuqqbarg("Herwig::MatchboxAmplitudelnuqqbarg", "HwMatchboxBuiltin.so");
void MatchboxAmplitudelnuqqbarg::Init() {
static ClassDocumentation<MatchboxAmplitudelnuqqbarg> documentation
("MatchboxAmplitudelnuqqbarg");
static Switch<MatchboxAmplitudelnuqqbarg,bool> interfaceDiagonal
("Diagonal",
"Use a diagonal CKM matrix (ignoring the CKM object of the StandardModel).",
&MatchboxAmplitudelnuqqbarg::theDiagonal, false, false, false);
static SwitchOption interfaceDiagonalYes
(interfaceDiagonal,
"Yes",
"Use a diagonal CKM matrix.",
true);
static SwitchOption interfaceDiagonalNo
(interfaceDiagonal,
"No",
"Use the CKM object as used by the StandardModel.",
false);
}
diff --git a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbargg.cc b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbargg.cc
--- a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbargg.cc
+++ b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbargg.cc
@@ -1,193 +1,201 @@
// -*- C++ -*-
//
// MatchboxAmplitudelnuqqbargg.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MatchboxAmplitudelnuqqbargg class.
//
#include "Herwig/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbargg.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
using namespace Herwig;
MatchboxAmplitudelnuqqbargg::MatchboxAmplitudelnuqqbargg()
: theDiagonal(false) {}
MatchboxAmplitudelnuqqbargg::~MatchboxAmplitudelnuqqbargg() {}
void MatchboxAmplitudelnuqqbargg::doinit() {
MatchboxAmplitude::doinit();
+ MZ = getParticleData(ParticleID::Z0)->hardProcessMass();
+ GZ = getParticleData(ParticleID::Z0)->hardProcessWidth();
MW = getParticleData(ParticleID::Wplus)->hardProcessMass();
GW = getParticleData(ParticleID::Wplus)->hardProcessWidth();
CA = SM().Nc();
CF = (SM().Nc()*SM().Nc()-1.)/(2.*SM().Nc());
theCKM = standardCKM(SM())->getUnsquaredMatrix(6);
nPoints(6);
}
void MatchboxAmplitudelnuqqbargg::doinitrun() {
MatchboxAmplitude::doinitrun();
+ MZ = getParticleData(ParticleID::Z0)->hardProcessMass();
+ GZ = getParticleData(ParticleID::Z0)->hardProcessWidth();
+ MW = getParticleData(ParticleID::Wplus)->hardProcessMass();
+ GW = getParticleData(ParticleID::Wplus)->hardProcessWidth();
+ CA = SM().Nc();
+ CF = (SM().Nc()*SM().Nc()-1.)/(2.*SM().Nc());
nPoints(6);
}
IBPtr MatchboxAmplitudelnuqqbargg::clone() const {
return new_ptr(*this);
}
IBPtr MatchboxAmplitudelnuqqbargg::fullclone() const {
return new_ptr(*this);
}
bool MatchboxAmplitudelnuqqbargg::canHandle(const PDVector& proc) const {
PDVector xproc = proc;
if ( xproc[0]->CC() )
xproc[0] = xproc[0]->CC();
if ( xproc[1]->CC() )
xproc[1] = xproc[1]->CC();
PDVector::iterator elektron = xproc.begin();
for ( ; elektron != xproc.end(); ++elektron )
if ( abs((*elektron)->id()) >= 11 && abs((*elektron)->id()) <= 16 && abs((*elektron)->id()) % 2 == 1 ) break;
if ( elektron == xproc.end() ) return false;
PDPtr e = *elektron;
xproc.erase(elektron);
PDVector::iterator neutrino = xproc.begin();
for ( ; neutrino != xproc.end(); ++neutrino )
if ( abs((*neutrino)->id()) >= 11 && abs((*neutrino)->id()) <= 16 && abs((*neutrino)->id()) % 2 == 0 ) break;
if ( neutrino == xproc.end() ) return false;
PDPtr n = *neutrino;
xproc.erase(neutrino);
PDVector::iterator quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 && abs((*quark)->id()) % 2 == 1 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr d = *quark;
xproc.erase(quark);
quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 && abs((*quark)->id()) % 2 == 0 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr u = *quark;
xproc.erase(quark);
PDVector::iterator gluon = xproc.begin();
for ( ; gluon != xproc.end(); ++gluon )
if ( (*gluon)->id() == 21 ) break;
if ( gluon == xproc.end() ) return false;
xproc.erase(gluon);
gluon = xproc.begin();
for ( ; gluon != xproc.end(); ++gluon )
if ( (*gluon)->id() == 21 ) break;
if ( gluon == xproc.end() ) return false;
xproc.erase(gluon);
if ( SU2Helper::family(e) != SU2Helper::family(n) ) return false;
if ( u->iCharge() + d->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(u) != SU2Helper::family(d) ) return false;
return xproc.empty();
}
void MatchboxAmplitudelnuqqbargg::prepareAmplitudes(Ptr<MatchboxMEBase>::tcptr me) {
if ( !calculateTreeAmplitudes() ) {
MatchboxAmplitude::prepareAmplitudes(me);
return;
}
amplitudeScale(sqrt(lastSHat()));
setupLeptons(0,amplitudeMomentum(0),1,amplitudeMomentum(1));
momentum(2,amplitudeMomentum(2));
momentum(3,amplitudeMomentum(3));
momentum(4,amplitudeMomentum(4));
momentum(5,amplitudeMomentum(5));
MatchboxAmplitude::prepareAmplitudes(me);
}
Complex MatchboxAmplitudelnuqqbargg::evaluate(size_t a, const vector<int>& hel, Complex& largeN) {
if ( abs(hel[2]+hel[3]) != 2 ) {
largeN = 0.;
return 0.;
}
assert ( amplitudeToColourMap()[2] == 0 && amplitudeToColourMap()[3] == 1 );
int g1,hg1,g2,hg2;
if ( amplitudeToColourMap()[4] == 2 && amplitudeToColourMap()[5] == 3 ) {
if ( a == 0 ) {
g1 = 4; hg1 = hel[4];
g2 = 5; hg2 = hel[5];
} else if ( a == 1 ) {
g1 = 5; hg1 = hel[5];
g2 = 4; hg2 = hel[4];
} else assert ( false );
} else if ( amplitudeToColourMap()[4] == 3 && amplitudeToColourMap()[5] == 2 ) {
if ( a == 0 ) {
g1 = 5; hg1 = hel[5];
g2 = 4; hg2 = hel[4];
} else if ( a == 1 ) {
g1 = 4; hg1 = hel[4];
g2 = 5; hg2 = hel[5];
} else assert ( false );
} else assert ( false );
Complex ckmelement = 1.;
if ( !theDiagonal ) {
bool wPlus = ( abs(amplitudePartonData()[0]->id()) % 2 == 0 ) ?
amplitudePartonData()[1]->id() < 0:
amplitudePartonData()[0]->id() < 0;
pair<int,int> tmp(
SU2Helper::family(amplitudePartonData()[2]),
SU2Helper::family(amplitudePartonData()[3]));
if ( amplitudePartonData()[3]->id() < 0 ) swap(tmp.first,tmp.second);
ckmelement = theCKM[tmp.first][tmp.second];
if ( !wPlus ) ckmelement = conj(ckmelement);
}
Complex wPropergator =
1./Complex(((amplitudeMomentum(0)+amplitudeMomentum(1)).m2()-sqr(MW))/lastSHat(),MW*GW/lastSHat());
Complex wVertices =
2.*SM().alphaEMMZ()*Constants::pi/SM().sin2ThetaW()*ckmelement;
Complex sVertices =
4.*Constants::pi*SM().alphaS();
const LorentzVector<Complex>& leptonCurrent = llbarLeftCurrent(0,hel[0],1,hel[1]);
const LorentzVector<Complex>& quarkCurrent = qqbarggLeftCurrent(2,hel[2],3,hel[3],g1,hg1,g2,hg2);
Complex current = hel[2] == 1 ? Complex(0.,-1)*leptonCurrent.dot(quarkCurrent): 0.;
Complex res = current*wVertices*wPropergator*sVertices;
largeN = res;
return res;
}
void MatchboxAmplitudelnuqqbargg::persistentOutput(PersistentOStream & os) const {
- os << theDiagonal << theCKM << ounit(MW,GeV) << ounit(GW,GeV) << CA << CF;
+ os << theDiagonal << theCKM ;
}
void MatchboxAmplitudelnuqqbargg::persistentInput(PersistentIStream & is, int) {
- is >> theDiagonal >> theCKM >> iunit(MW,GeV) >> iunit(GW,GeV) >> CA >> CF;
+ is >> theDiagonal >> theCKM ;
}
DescribeClass<MatchboxAmplitudelnuqqbargg,MatchboxAmplitude>
describeHerwigMatchboxAmplitudelnuqqbargg("Herwig::MatchboxAmplitudelnuqqbargg", "HwMatchboxBuiltin.so");
void MatchboxAmplitudelnuqqbargg::Init() {
static ClassDocumentation<MatchboxAmplitudelnuqqbargg> documentation
("MatchboxAmplitudelnuqqbargg");
static Switch<MatchboxAmplitudelnuqqbargg,bool> interfaceDiagonal
("Diagonal",
"Use a diagonal CKM matrix (ignoring the CKM object of the StandardModel).",
&MatchboxAmplitudelnuqqbargg::theDiagonal, false, false, false);
static SwitchOption interfaceDiagonalYes
(interfaceDiagonal,
"Yes",
"Use a diagonal CKM matrix.",
true);
static SwitchOption interfaceDiagonalNo
(interfaceDiagonal,
"No",
"Use the CKM object as used by the StandardModel.",
false);
}
diff --git a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarqqbar.cc b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarqqbar.cc
--- a/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarqqbar.cc
+++ b/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarqqbar.cc
@@ -1,267 +1,275 @@
// -*- C++ -*-
//
// MatchboxAmplitudelnuqqbarqqbar.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MatchboxAmplitudelnuqqbarqqbar class.
//
#include "Herwig/MatrixElement/Matchbox/Builtin/Amplitudes/MatchboxAmplitudelnuqqbarqqbar.h"
using namespace Herwig;
MatchboxAmplitudelnuqqbarqqbar::MatchboxAmplitudelnuqqbarqqbar()
: theDiagonal(false) {}
MatchboxAmplitudelnuqqbarqqbar::~MatchboxAmplitudelnuqqbarqqbar() {}
void MatchboxAmplitudelnuqqbarqqbar::doinit() {
MatchboxAmplitude::doinit();
+ MZ = getParticleData(ParticleID::Z0)->hardProcessMass();
+ GZ = getParticleData(ParticleID::Z0)->hardProcessWidth();
MW = getParticleData(ParticleID::Wplus)->hardProcessMass();
GW = getParticleData(ParticleID::Wplus)->hardProcessWidth();
CA = SM().Nc();
CF = (SM().Nc()*SM().Nc()-1.)/(2.*SM().Nc());
theCKM = standardCKM(SM())->getUnsquaredMatrix(6);
nPoints(6);
}
void MatchboxAmplitudelnuqqbarqqbar::doinitrun() {
MatchboxAmplitude::doinitrun();
+ MZ = getParticleData(ParticleID::Z0)->hardProcessMass();
+ GZ = getParticleData(ParticleID::Z0)->hardProcessWidth();
+ MW = getParticleData(ParticleID::Wplus)->hardProcessMass();
+ GW = getParticleData(ParticleID::Wplus)->hardProcessWidth();
+ CA = SM().Nc();
+ CF = (SM().Nc()*SM().Nc()-1.)/(2.*SM().Nc());
nPoints(6);
}
IBPtr MatchboxAmplitudelnuqqbarqqbar::clone() const {
return new_ptr(*this);
}
IBPtr MatchboxAmplitudelnuqqbarqqbar::fullclone() const {
return new_ptr(*this);
}
bool MatchboxAmplitudelnuqqbarqqbar::canHandle(const PDVector& proc) const {
PDVector xproc = proc;
if ( xproc[0]->CC() )
xproc[0] = xproc[0]->CC();
if ( xproc[1]->CC() )
xproc[1] = xproc[1]->CC();
// Charge charge(ZERO);
PDVector::iterator elektron = xproc.begin();
for ( ; elektron != xproc.end(); ++elektron )
if ( abs((*elektron)->id()) >= 11 && abs((*elektron)->id()) <= 16 && abs((*elektron)->id()) % 2 == 1 ) break;
if ( elektron == xproc.end() ) return false;
PDPtr e = *elektron;
xproc.erase(elektron);
PDVector::iterator neutrino = xproc.begin();
for ( ; neutrino != xproc.end(); ++neutrino )
if ( abs((*neutrino)->id()) >= 11 && abs((*neutrino)->id()) <= 16 && abs((*neutrino)->id()) % 2 == 0 ) break;
if ( neutrino == xproc.end() ) return false;
PDPtr n = *neutrino;
xproc.erase(neutrino);
PDVector::iterator quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr q1 = *quark;
xproc.erase(quark);
quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr q2 = *quark;
xproc.erase(quark);
quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr q3 = *quark;
xproc.erase(quark);
quark = xproc.begin();
for ( ; quark != xproc.end(); ++quark )
if ( abs((*quark)->id()) >= 1 && abs((*quark)->id()) <= 6 ) {
assert( (*quark)->hardProcessMass() == ZERO );
break;
}
if ( quark == xproc.end() ) return false;
PDPtr q4 = *quark;
xproc.erase(quark);
if ( q1->id() == -q2->id() ) {
if ( q3->iCharge() + q4->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(q3) != SU2Helper::family(q4) ) return false;
} else if ( q1->id() == -q3->id() ) {
if ( q2->iCharge() + q4->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(q2) != SU2Helper::family(q4) ) return false;
} else if ( q1->id() == -q4->id() ) {
if ( q2->iCharge() + q3->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(q2) != SU2Helper::family(q3) ) return false;
} else if ( q2->id() == -q3->id() ) {
if ( q1->iCharge() + q4->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(q1) != SU2Helper::family(q4) ) return false;
} else if ( q2->id() == -q4->id() ) {
if ( q1->iCharge() + q3->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(q1) != SU2Helper::family(q3) ) return false;
} else if ( q3->id() == -q4->id() ) {
if ( q1->iCharge() + q2->iCharge() + e->iCharge() != PDT::ChargeNeutral ) return false;
if ( theDiagonal && SU2Helper::family(q1) != SU2Helper::family(q2) ) return false;
} else return false;
if ( SU2Helper::family(e) != SU2Helper::family(n) ) return false;
return xproc.empty();
}
void MatchboxAmplitudelnuqqbarqqbar::prepareAmplitudes(Ptr<MatchboxMEBase>::tcptr me) {
if ( !calculateTreeAmplitudes() ) {
MatchboxAmplitude::prepareAmplitudes(me);
return;
}
amplitudeScale(sqrt(lastSHat()));
setupLeptons(0,amplitudeMomentum(0),1,amplitudeMomentum(1));
momentum(2,amplitudeMomentum(2));
momentum(3,amplitudeMomentum(3));
momentum(4,amplitudeMomentum(4));
momentum(5,amplitudeMomentum(5));
MatchboxAmplitude::prepareAmplitudes(me);
}
Complex MatchboxAmplitudelnuqqbarqqbar::evaluate(size_t a, const vector<int>& hel, Complex& largeN) {
const LorentzVector<Complex>& leptonCurrent = llbarLeftCurrent(0,hel[0],1,hel[1]);
Complex Current2345 =
hel[2] == 1 && hel[3] == 1 && abs(hel[4]+hel[5]) == 2 &&
abs(amplitudePartonData()[4]->id()) == abs(amplitudePartonData()[5]->id()) ?
leptonCurrent.dot(qqbarqqbarLeftCurrent(2,hel[2],3,hel[3],4,hel[4],5,hel[5])) : 0.;
Complex Current4523 =
hel[4] == 1 && hel[5] == 1 && abs(hel[2]+hel[3]) == 2 &&
abs(amplitudePartonData()[2]->id()) == abs(amplitudePartonData()[3]->id()) ?
leptonCurrent.dot(qqbarqqbarLeftCurrent(4,hel[4],5,hel[5],2,hel[2],3,hel[3])) : 0.;
Complex Current2543 =
hel[2] == 1 && hel[5] == 1 && abs(hel[4]+hel[3]) == 2 &&
abs(amplitudePartonData()[4]->id()) == abs(amplitudePartonData()[3]->id()) ?
-leptonCurrent.dot(qqbarqqbarLeftCurrent(2,hel[2],5,hel[5],4,hel[4],3,hel[3])) : 0.;
Complex Current4325 =
hel[4] == 1 && hel[3] == 1 && abs(hel[2]+hel[5]) == 2 &&
abs(amplitudePartonData()[2]->id()) == abs(amplitudePartonData()[5]->id()) ?
-leptonCurrent.dot(qqbarqqbarLeftCurrent(4,hel[4],3,hel[3],2,hel[2],5,hel[5])) : 0.;
Complex ckmelement23 = 1.;
Complex ckmelement45 = 1.;
if ( !theDiagonal ) {
bool wPlus = ( abs(amplitudePartonData()[0]->id()) % 2 == 0 ) ?
amplitudePartonData()[1]->id() < 0:
amplitudePartonData()[0]->id() < 0;
pair<int,int> tmp23(
SU2Helper::family(amplitudePartonData()[2])-1,
SU2Helper::family(amplitudePartonData()[3])-1);
pair<int,int> tmp45(
SU2Helper::family(amplitudePartonData()[4])-1,
SU2Helper::family(amplitudePartonData()[5])-1);
if ( amplitudePartonData()[3]->id() < 0 ) swap(tmp23.first,tmp23.second);
if ( amplitudePartonData()[5]->id() < 0 ) swap(tmp45.first,tmp45.second);
ckmelement23 = theCKM[tmp23.first][tmp23.second];
ckmelement45 = theCKM[tmp45.first][tmp45.second];
if ( !wPlus ) {
ckmelement23 = conj(ckmelement23);
ckmelement45 = conj(ckmelement45);
}
}
Complex wPropergator =
1./Complex(((amplitudeMomentum(0)+amplitudeMomentum(1)).m2()-sqr(MW))/lastSHat(),MW*GW/lastSHat());
Complex wVertices23 =
2.*SM().alphaEMMZ()*Constants::pi/SM().sin2ThetaW()*ckmelement23;
Complex wVertices45 =
2.*SM().alphaEMMZ()*Constants::pi/SM().sin2ThetaW()*ckmelement45;
Complex sVertices =
4.*Constants::pi*SM().alphaS();
Complex res2345 =
Complex(0.,-1.)*wPropergator*sVertices*Current2345*wVertices23;
Complex res2543 =
Complex(0.,-1.)*wPropergator*sVertices*Current2543*wVertices23;
Complex res4523 =
Complex(0.,-1.)*wPropergator*sVertices*Current4523*wVertices45;
Complex res4325 =
Complex(0.,-1.)*wPropergator*sVertices*Current4325*wVertices45;
double Nc = SM().Nc();
Complex resLeading = 0.;
Complex resSubLeading = 0.;
if ( amplitudeToColourMap()[2] == 0 && amplitudeToColourMap()[3] == 1 &&
amplitudeToColourMap()[4] == 2 && amplitudeToColourMap()[5] == 3 ) {
if ( a == 0 ) { //(23)(45)
resLeading = res2543 + res4325;
resSubLeading = res2345 + res4523;
} else if ( a == 1 ) { //(25)(43)
resLeading = res2345 + res4523;
resSubLeading = res2543 + res4325;
} else assert(false);
} else if ( amplitudeToColourMap()[2] == 0 && amplitudeToColourMap()[3] == 3 &&
amplitudeToColourMap()[4] == 2 && amplitudeToColourMap()[5] == 1 ) {
if ( a == 0 ) { // (25)(43)
resLeading = res2345 + res4523;
resSubLeading = res2543 + res4325;
} else if ( a == 1 ) { // (23)(45)
resLeading = res2543 + res4325;
resSubLeading = res2345 + res4523;
} else assert(false);
} else if ( amplitudeToColourMap()[2] == 2 && amplitudeToColourMap()[3] == 3 &&
amplitudeToColourMap()[4] == 0 && amplitudeToColourMap()[5] == 1 ) {
if ( a == 0 ) { //(23)(45)
resLeading = res2543 + res4325;
resSubLeading = res2345 + res4523;
} else if ( a == 1 ) { //(25)(43)
resLeading = res2345 + res4523;
resSubLeading = res2543 + res4325;
} else assert(false);
} else if ( amplitudeToColourMap()[2] == 2 && amplitudeToColourMap()[3] == 1 &&
amplitudeToColourMap()[4] == 0 && amplitudeToColourMap()[5] == 3 ) {
if ( a == 0 ) { //(25)(43)
resLeading = res2345 + res4523;
resSubLeading = res2543 + res4325;
} else if ( a == 1 ) { //(23)(45)
resLeading = res2543 + res4325;
resSubLeading = res2345 + res4523;
} else assert(false);
} else assert(false);
resSubLeading *= -1./Nc;
largeN = resLeading/2.;
return (resLeading + resSubLeading)/2.;
}
void MatchboxAmplitudelnuqqbarqqbar::persistentOutput(PersistentOStream & os) const {
- os << theDiagonal << theCKM << ounit(MW,GeV) << ounit(GW,GeV) << CA << CF;
+ os << theDiagonal << theCKM ;
}
void MatchboxAmplitudelnuqqbarqqbar::persistentInput(PersistentIStream & is, int) {
- is >> theDiagonal >> theCKM >> iunit(MW,GeV) >> iunit(GW,GeV) >> CA >> CF;
+ is >> theDiagonal >> theCKM ;
}
DescribeClass<MatchboxAmplitudelnuqqbarqqbar,MatchboxAmplitude>
describeHerwigMatchboxAmplitudelnuqqbarqqbar("Herwig::MatchboxAmplitudelnuqqbarqqbar", "HwMatchboxBuiltin.so");
void MatchboxAmplitudelnuqqbarqqbar::Init() {
static ClassDocumentation<MatchboxAmplitudelnuqqbarqqbar> documentation
("MatchboxAmplitudelnuqqbarqqbar");
static Switch<MatchboxAmplitudelnuqqbarqqbar,bool> interfaceDiagonal
("Diagonal",
"Use a diagonal CKM matrix (ignoring the CKM object of the StandardModel).",
&MatchboxAmplitudelnuqqbarqqbar::theDiagonal, false, false, false);
static SwitchOption interfaceDiagonalYes
(interfaceDiagonal,
"Yes",
"Use a diagonal CKM matrix.",
true);
static SwitchOption interfaceDiagonalNo
(interfaceDiagonal,
"No",
"Use the CKM object as used by the StandardModel.",
false);
}
diff --git a/MatrixElement/Matchbox/External/GoSam/GoSamAmplitude.cc b/MatrixElement/Matchbox/External/GoSam/GoSamAmplitude.cc
--- a/MatrixElement/Matchbox/External/GoSam/GoSamAmplitude.cc
+++ b/MatrixElement/Matchbox/External/GoSam/GoSamAmplitude.cc
@@ -1,1063 +1,1069 @@
// -*- C++ -*-
//
// GoSamAmplitude.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the GoSamAmplitude class.
//
#include "GoSamAmplitude.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/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Command.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Utilities/StringUtils.h"
#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h"
#include "Herwig/API/Filesystem.h"
#include <fstream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <exception>
namespace bfs = Herwig::filesystem;
using namespace Herwig;
#ifndef HERWIG_BINDIR
#error Makefile.am needs to define HERWIG_BINDIR
#endif
#ifndef HERWIG_PKGDATADIR
#error Makefile.am needs to define HERWIG_PKGDATADIR
#endif
#ifndef GOSAM_PREFIX
#error Makefile.am needs to define GOSAM_PREFIX
#endif
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
GoSamAmplitude::GoSamAmplitude() :
theAccuracyTarget(6),theCodeExists(false),theFormOpt(true),theNinja(true),
theHiggsEff(false),theMassiveLeptons(false),theLoopInducedOption(0),
isitDR(false),doneGoSamInit(false),doneGoSamInitRun(false),
bindir_(HERWIG_BINDIR), pkgdatadir_(HERWIG_PKGDATADIR), GoSamPrefix_(GOSAM_PREFIX)
{}
GoSamAmplitude::~GoSamAmplitude() {}
IBPtr GoSamAmplitude::clone() const {
return new_ptr(*this);
}
IBPtr GoSamAmplitude::fullclone() const {
return new_ptr(*this);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void GoSamAmplitude::doinit() {
optionalContractFile() = name() + ".OLPContract.lh";
MatchboxOLPME::doinit();
doneGoSamInit = true;
}
void GoSamAmplitude::doinitrun() {
optionalContractFile() = name() + ".OLPContract.lh";
MatchboxOLPME::doinitrun();
doneGoSamInitRun = true;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
extern "C" void OLP_Start(const char*, int* i);
extern "C" void OLP_Polvec(double*, double*, double*);
extern "C" void OLP_SetParameter(char*, double*, double*, int*);
extern "C" void OLP_PrintParameter(char*);
extern "C" void OLP_EvalSubProcess2(int*, double*, double*, double*, double*);
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool GoSamAmplitude::startOLP(const map<pair<Process, int>, int>& procs) {
char char_cwd[256];
getcwd(char_cwd, sizeof(char_cwd));
string cwd = string(char_cwd);
string folderMatchboxBuild = factory()->buildStorage();
folderMatchboxBuild.erase(folderMatchboxBuild.begin());
// set all necessary path and file names
gosamPath = gosamPathInterface == "" ? cwd + folderMatchboxBuild + "GoSam" : gosamPathInterface;
// When transitioning to C++ 11 this length()-1 workaround can be replaced by string.back()
if (gosamPath.at(gosamPath.length()-1) != '/') gosamPath.append("/");
gosamSourcePath = gosamPath + "source/";
gosamInstallPath = gosamPath + "build/";
// create all the directories
if (!bfs::is_directory(gosamPath)){
try {
bfs::create_directory(gosamPath);
} catch (exception& e) {
throw Exception()
<< "--------------------------------------------------------------------------------\n"
<< "The following exception occured:\n\n"
<< " " << e.what() << "\n\n"
<< " -> Please create the parent directory of\n"
<< " " << gosamPath << "\n"
<< " manually!\n"
<< "--------------------------------------------------------------------------------\n"
<< Exception::runerror;
}
}
if (!bfs::is_directory(gosamSourcePath)) bfs::create_directory(gosamSourcePath);
if (!bfs::is_directory(gosamInstallPath)) bfs::create_directory(gosamInstallPath);
contractFileTitle = name() + ".OLPContract.lh";
contractFileName = gosamPath + "/" + contractFileTitle;
string orderFileName = gosamPath + "/" + name() + ".OLPOrder.lh";
// Set the path variable (plus file name) where to find the GoSam specific input file
gosamSetupInFileName = gosamSetupInFileNameInterface == "" ? gosamPath + "/setup.gosam.in" : gosamSetupInFileNameInterface;
// Use the python script gosam2herwig to make replacements in the GoSam
// specific input file at gosamSetupInFileName. If the GoSam input file
// does not exist yet at gosamSetupInFileName the python script will get
// it from src/defaults/ before making the replacements.
string cmd = "python "+bindir_+"/gosam2herwig ";
cmd+=" --usrinfile="+gosamSetupInFileNameInterface;
cmd+=" --infile="+gosamSetupInFileName+".tbu";
cmd+=" --definfile="+pkgdatadir_+"/defaults/setup.gosam.in";
cmd+=" --formtempdir="+StringUtils::replace(gosamSourcePath, string("/"), string("\\/")); //@FORMTEMPDIR@
cmd+=" --reduction="+(theNinja ? string("ninja,golem95") : string("samurai,golem95")); //@REDUCTIONPROGRAMS@
cmd+=" --formopt="+(theFormOpt ? string("") : string(", noformopt")); //@FORMOPT@
cmd+=" --higgseff="+(theHiggsEff ? string("smehc") : string("smdiag")); //@MODEL@
std::system(cmd.c_str());
if ( factory()->initVerbose() ) {
generator()->log() << "\n\n>>> NOTE: According to the repository settings for the GoSam interface:\n" << flush;
if (theHiggsEff) generator()->log() << "\n -- GoSam will use a model with an effective ggH coupling (model=smehc).\n" << flush;
else if (!theHiggsEff) generator()->log() << "\n -- GoSam will use its default model (model=smdiag).\n" << flush;
if (theNinja) generator()->log() << " -- GoSam will use Ninja as reduction program (reduction_programs=ninja,golem95).\n" << flush;
else if (!theNinja) generator()->log() << " -- GoSam will use Samurai as reduction program (reduction_programs=samurai,golem95).\n" << flush;
if (theFormOpt) generator()->log() << " -- Form optimization switched on (extensions=autotools).\n" << flush;
else if (!theFormOpt) generator()->log() << " -- Form optimization switched off (extensions=autotools, noformopt).\n" << flush;
if (theNinja && !theFormOpt) throw Exception() << "GoSamAmplitude: Ninja reduction needs form optimization!\n" << Exception::runerror;
if (gosamSetupInFileNameInterface == "") {
generator()->log() << "\n Please be aware that you are using a copy of the default GoSam input file!\n"
<< " Please note that if you need special options to be considered for the specific\n"
<< " process you are looking at (diagram filtering, etc.) these are not automatically\n"
<< " set for you. In that case please consider to specify your own GoSam input file\n"
<< " via 'set " << name() << ":SetupInFilename' in the input file.\n\n" << flush;
}
// If one uses a custom GoSam input file at gosamSetupInFileName = gosamSetupInFileNameInterface
// then please note that not all options in there might match the corresponding Herwig repository
// options
if (gosamSetupInFileNameInterface != "") {
generator()->log() << "\n Please be aware that you are using a custom GoSam input file!\n"
<< " Please note that if you have set the options for model, reduction_programs,\n"
<< " extensions and/or form.tempdir manually these will of course not be replaced\n"
<< " by the corresponding repository settings mentioned above.\n\n" << flush;
}
generator()->log() << "\n>>> NOTE: GoSam may return the set of used parameters for this process via the OLP_PrintParameter() function:\n\n"
<< " -- If Debug::level > 1, the OLP parameters are being written to file: at " << factory()->runStorage() + name() + ".OLPParameters.lh.\n\n" << flush;
}
double accuracyTarget = 1.0/pow(10.0,accuracyTargetNegExp());
time_t rawtime;
time (&rawtime);
accuracyFileTitle = name() + ".OLPAccuracy.lh";
accuracyFile = factory()->buildStorage() + accuracyFileTitle;
ofstream accuracyFileStream;
if ( Debug::level > 1 ) {
accuracyFileStream.open(accuracyFile.c_str()); // Opening accuracyFile once here removes all previous content before the read step
accuracyFileStream << "\nFile to contain those PSPs for which GoSam evaluated one-loop interference terms or loop induced ME2s\n"
<< "with acc > target accuracy = " << accuracyTarget << ". Date/Time: " << ctime(&rawtime) << endl;
}
if ( factory()->initVerbose() ) {
generator()->log() << "\n>>> NOTE: GoSam will return the accuracy of one-loop interference terms or loop induced ME2s\n"
<< " at every PSP via the BLHA2 acc parameter:\n\n"
<< " -- In cases where acc > 10^-AccuracyTarget = " << accuracyTarget << " the corresponding PSPs are being dis-\n"
<< " carded.\n"
<< " -- The default value for AccuracyTarget is 6, but you may consider setting it otherwise\n"
<< " via 'set " << name() << ":AccuracyTarget' in the input file.\n"
<< " -- Currently the value for AccuracyTarget is set to " << accuracyTargetNegExp() << ".\n"
<< " -- If Debug::level > 1, the discarded PSPs are being written to file: at " + accuracyFile << ".\n"
<< " -- If the amount of PSPs with acc > " << accuracyTarget << " is significant, please consider to re-evaluate\n"
<< " your process setup (accuracy target, masses, cuts, etc.)!\n\n\n" << flush;
}
// check for old order file and create it if it doesn't already exist
fillOrderFile(procs, orderFileName);
ifstream ifile(contractFileName.c_str());
if(!ifile){
signOLP(orderFileName, contractFileName);
}
if ( !checkOLPContract(contractFileName) ) {
throw Exception() << "GoSamAmplitude: failed to start GoSam" << Exception::runerror;
}
if (!( DynamicLoader::load(gosamInstallPath+"/lib/libgolem_olp.so")
|| DynamicLoader::load(gosamInstallPath+"/lib64/libgolem_olp.so")
|| DynamicLoader::load(gosamInstallPath+"/lib/libgolem_olp.dylib")
|| DynamicLoader::load(gosamInstallPath+"/lib64/libgolem_olp.dylib"))) buildGoSam();
int status = -1;
startOLP(contractFileTitle, status);
if ( status != 1 ) return false;
return true;
}
void GoSamAmplitude::startOLP(const string& contract, int& status) {
string tempcontract = contract;
char char_cwd[256];
getcwd(char_cwd, sizeof(char_cwd));
string cwd = string(char_cwd);
string folderMatchboxBuild = factory()->buildStorage();
folderMatchboxBuild.erase(folderMatchboxBuild.begin());
gosamPath = gosamPathInterface == "" ? cwd + folderMatchboxBuild + "GoSam" : gosamPathInterface;
// When transitioning to C++ 11 this length()-1 workaround can be replaced by string.back()
if (gosamPath.at(gosamPath.length()-1) != '/') gosamPath.append("/");
if (!( DynamicLoader::load(gosamPath+"build/lib/libgolem_olp.so")
|| DynamicLoader::load(gosamPath+"build/lib64/libgolem_olp.so")
|| DynamicLoader::load(gosamPath+"build/lib/libgolem_olp.dylib")
|| DynamicLoader::load(gosamPath+"build/lib64/libgolem_olp.dylib")))
throw Exception() << "GoSamAmplitude: Failed to load GoSam. Please check the log file.\n"
<< Exception::runerror;
tempcontract = gosamPath + tempcontract;
OLP_Start(tempcontract.c_str(), &status);
// hand over input parameters for EW scheme considered
int pStatus = 0;
double zero = 0.0;
if ( SM().ewScheme() == 0 || SM().ewScheme() == 6 ) { // EW/Scheme Default and EW/Scheme Independent
throw Exception() << "GoSamAmplitude: `Best value' schemes are not supported by GoSam"
<< Exception::runerror;
} else if ( SM().ewScheme() == 4 ) { // EW/Scheme mW (uses mW,GF,sin2thetaW) seems not to be supported by GoSam
throw Exception() << "GoSamAmplitude: `mW' scheme is not supported by GoSam"
<< Exception::runerror;
} else if ( SM().ewScheme() == 1 ) { // EW/Scheme GMuScheme (uses mW,mZ,GF)
double in1=getParticleData(ParticleID::Z0)->hardProcessMass()/GeV;
double in2=getParticleData(ParticleID::Wplus)->hardProcessMass()/GeV;
double in3=SM().fermiConstant()*GeV2;
OLP_SetParameter((char *)"mass(23)",&in1,&zero,&pStatus);
OLP_SetParameter((char *)"mass(24)",&in2,&zero,&pStatus);
OLP_SetParameter((char *)"Gf",&in3,&zero,&pStatus);
} else if ( SM().ewScheme() == 2 ) { // EW/Scheme alphaMZScheme (uses mW,mZ,alpha(mZ))
double in1=getParticleData(ParticleID::Z0)->hardProcessMass()/GeV;
double in2=getParticleData(ParticleID::Wplus)->hardProcessMass()/GeV;
double in3=SM().alphaEMMZ();
OLP_SetParameter((char *)"mass(23)",&in1,&zero,&pStatus);
OLP_SetParameter((char *)"mass(24)",&in2,&zero,&pStatus);
OLP_SetParameter((char *)"alpha",&in3,&zero,&pStatus);
} else if ( SM().ewScheme() == 3 ) { // EW/Scheme NoMass (uses alpha(mZ),GF,sin2thetaW)
double in1=SM().fermiConstant()*GeV2;
double in2=SM().alphaEMMZ();
double in3=SM().sin2ThetaW();
OLP_SetParameter((char *)"Gf",&in1,&zero,&pStatus);
OLP_SetParameter((char *)"alpha",&in2,&zero,&pStatus);
OLP_SetParameter((char *)"sw2",&in3,&zero,&pStatus);
} else if ( SM().ewScheme() == 5 ) { // EW/Scheme mZ (uses mZ,alphaEM,sin2thetaW)
double in1=getParticleData(ParticleID::Z0)->hardProcessMass()/GeV;
double in2=SM().alphaEMMZ();
double in3=SM().sin2ThetaW();
OLP_SetParameter((char *)"mass(23)",&in1,&zero,&pStatus);
OLP_SetParameter((char *)"alpha",&in2,&zero,&pStatus);
OLP_SetParameter((char *)"sw2",&in3,&zero,&pStatus);
} else if ( SM().ewScheme() == 7 ) { // EW/Scheme FeynRulesUFO (uses mZ,GF,alpha(mZ))
double in1=getParticleData(ParticleID::Z0)->hardProcessMass()/GeV;
double in2=SM().alphaEMMZ();
double in3=SM().fermiConstant()*GeV2;
OLP_SetParameter((char *)"mass(23)",&in1,&zero,&pStatus);
OLP_SetParameter((char *)"alpha",&in2,&zero,&pStatus);
OLP_SetParameter((char *)"Gf",&in3,&zero,&pStatus);
}
+ // hand over widths of Z and W
+ double wZ = getParticleData(23)->hardProcessWidth()/GeV;
+ double wW = getParticleData(24)->hardProcessWidth()/GeV;
+ OLP_SetParameter((char*)"width(23)",&wZ,&zero,&pStatus);
+ OLP_SetParameter((char*)"width(24)",&wW,&zero,&pStatus);
+
// hand over mass and width of the Higgs
double wH = getParticleData(25)->hardProcessWidth()/GeV;
double mH = getParticleData(25)->hardProcessMass()/GeV;
OLP_SetParameter((char*)"width(25)",&wH,&zero,&pStatus);
OLP_SetParameter((char*)"mass(25)",&mH,&zero,&pStatus);
// hand over initial input parameter for alphaS
double as = SM().alphaS();
OLP_SetParameter((char *)"alphaS", &as, &zero, &pStatus);
// fill massive Particle vector
if (massiveParticles.empty()) {
// with quark masses
for (int i=1; i<=6; ++i)
if (getParticleData(i)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(i);
// with lepton masses
if (theMassiveLeptons && getParticleData(11)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(11);
if (theMassiveLeptons && getParticleData(13)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(13);
if (theMassiveLeptons && getParticleData(15)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(15);
}
// hand over quark (and possibly lepton) masses and widths (iff massive)
if ( massiveParticles.size() != 0 ) {
for ( vector<int>::const_iterator mID = massiveParticles.begin(); mID != massiveParticles.end(); ++mID ) {
string mstr;
string wstr;
int mInt = *mID;
double mass=getParticleData(mInt)->hardProcessMass()/GeV;
double width=getParticleData(mInt)->hardProcessWidth()/GeV;
std::stringstream ss;
ss << mInt;
string str = ss.str();
mstr="mass("+str+")";
wstr="width("+str+")";
char * mchar = new char[mstr.size()+1];
char * wchar = new char[wstr.size()+1];
std::copy(mstr.begin(),mstr.end(),mchar);
std::copy(wstr.begin(),wstr.end(),wchar);
mchar[mstr.size()] = '\0';
wchar[wstr.size()] = '\0';
OLP_SetParameter( mchar, &mass, &zero, &pStatus );
OLP_SetParameter( wchar, &width, &zero, &pStatus );
delete[] mchar;
delete[] wchar;
// Nicer but not working properly:
// double mass=getParticleData(*mID)->hardProcessMass()/GeV;
// double width=getParticleData(*mID)->hardProcessWidth()/GeV;
// string mstr="mass("+static_cast<ostringstream*>(&(ostringstream()<<(*mID)))->str()+")";
// string wstr="width("+static_cast<ostringstream*>(&(ostringstream()<<(*mID)))->str()+")";
// cout<<"\n massiv "<<mstr;
//
// OLP_SetParameter((char *)&mstr,&mass, &zero, &pStatus );
// OLP_SetParameter((char *)&wstr,&width, &zero, &pStatus );
}
}
// Note: In the GoSam input file, the standard is to set the parameter
// 'symmetries' for quark families and lepton generations, which allow
// for flavour changing only between families/generations. If this pa-
// rameter is set, GoSam won't allow to set electron and muon mass and
// width via the interface. Also setting mass and width for the tau is
// not yet considered.
// print OLP parameters
if ( Debug::level > 1 ) {
string ppstr = factory()->runStorage() + name() + ".OLPParameters.lh";
OLP_PrintParameter(const_cast<char*>(ppstr.c_str()));
}
didStartOLP() = true;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void GoSamAmplitude::fillOrderFile(const map<pair<Process, int>, int>& procs, string orderFileName) {
for ( map<pair<Process, int>, int>::const_iterator p = procs.begin() ; p != procs.end() ; ++p ) {
std::stringstream Processstr;
std::stringstream Typestr;
Processstr << (*p).first.first.legs[0]->id() << " " << (*p).first.first.legs[1]->id() << " -> ";
for ( PDVector::const_iterator o = (*p).first.first.legs.begin() + 2 ; o != (*p).first.first.legs.end() ; ++o )
Processstr << (**o).id() << " ";
if ( (*p).first.second == ProcessType::treeME2 ) {
Typestr << "Tree";
} else if ( (*p).first.second == ProcessType::loopInducedME2 ) {
Typestr << "LoopInduced";
} else if ( (*p).first.second == ProcessType::colourCorrelatedME2 ) {
Typestr << "ccTree";
} else if ( (*p).first.second == ProcessType::spinColourCorrelatedME2 ) {
Typestr << "scTree";
} else if ( (*p).first.second == ProcessType::oneLoopInterference ) {
Typestr << "Loop";
}
gosamprocinfo pro = gosamprocinfo((*p).second, -1, Processstr.str(), Typestr.str());
pro.setOAs(p->first.first.orderInAlphaS);
pro.setOAew(p->first.first.orderInAlphaEW);
processmap[(*p).second] = pro;
}
ifstream oldOrderFileStream(orderFileName.c_str());
if (oldOrderFileStream){
oldOrderFileStream.close();
return;
}
ofstream orderFile(orderFileName.c_str());
int asPower = 100;
int minlegs = 100;
int maxlegs = -1;
int maxasPower = -1;
int aewPower = 100;
int maxaewPower = -1;
for ( map<pair<Process, int>, int>::const_iterator t = procs.begin() ; t != procs.end() ; ++t ) {
asPower = min(asPower, static_cast<int>(t->first.first.orderInAlphaS));
minlegs = min(minlegs, static_cast<int>(t->first.first.legs.size()));
maxlegs = max(maxlegs, static_cast<int>(t->first.first.legs.size()));
maxasPower = max(maxasPower, static_cast<int>(t->first.first.orderInAlphaS));
aewPower = min(aewPower, static_cast<int>(t->first.first.orderInAlphaEW));
maxaewPower = max(maxaewPower, static_cast<int>(t->first.first.orderInAlphaEW));
}
orderFile << "# OLP order file created by Herwig/Matchbox for GoSam\n\n";
orderFile << "InterfaceVersion BLHA2\n";
orderFile << "MatrixElementSquareType CHsummed\n";
orderFile << "CorrectionType QCD\n";
orderFile << "IRregularisation " << (isDR() ? "DRED" : "CDR") << "\n";
// loop over quarks to check if they have non-zero masses
for (int i=1; i<=6; ++i) if (getParticleData(i)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(i);
// check if leptons have non-zero masses (iff theMassiveLeptons==true)
if (theMassiveLeptons && getParticleData(11)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(11);
if (theMassiveLeptons && getParticleData(13)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(13);
if (theMassiveLeptons && getParticleData(15)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(15);
if ( massiveParticles.size() != 0 ) {
orderFile << "MassiveParticles ";
for ( vector<int>::const_iterator mID = massiveParticles.begin(); mID != massiveParticles.end(); ++mID ) {
int mInt = *mID;
orderFile << mInt << " ";
}
orderFile << "\n";
}
orderFile << "\n";
vector < string > types;
types.push_back("Tree");
types.push_back("LoopInduced");
types.push_back("ccTree");
types.push_back("scTree");
types.push_back("Loop");
for ( int i = asPower ; i != maxasPower + 1 ; i++ ) {
for ( int j = aewPower ; j != maxaewPower + 1 ; j++ ) {
orderFile << "\nAlphasPower " << i << "\n";
orderFile << "AlphaPower " << j << "\n";
for ( vector<string>::iterator it = types.begin() ; it != types.end() ; it++ ) {
if ( *it == "LoopInduced" ) continue;
for ( map<int, gosamprocinfo>::iterator p = processmap.begin() ; p != processmap.end() ; ++p )
if ( (*p).second.Tstr() == *it && i == (*p).second.orderAs() && j == (*p).second.orderAew() ) {
orderFile << "\nAmplitudeType " << *it << "\n";
break;
}
for ( map<int, gosamprocinfo>::iterator p = processmap.begin() ; p != processmap.end() ; ++p )
if ( (*p).second.Tstr() == *it && i == (*p).second.orderAs() && j == (*p).second.orderAew() ) {
orderFile << (*p).second.Pstr() << "\n";
}
}
}
}
// Write out the loop induced processes separately
int asPowerLI = 100;
int aewPowerLI = 100;
for ( map<int, gosamprocinfo>::iterator p = processmap.begin() ; p != processmap.end() ; ++p ) {
if ( (*p).second.Tstr() != "LoopInduced" ) continue;
if ( (*p).second.orderAs() != asPowerLI || (*p).second.orderAew() != aewPowerLI ) {
asPowerLI = (*p).second.orderAs();
aewPowerLI = (*p).second.orderAew();
// At the moment GoSam requires for qcd loop induced processes the as coupling power
// which would correspond to an associated fictitious Born process
orderFile << "\nAlphasPower " << (asPowerLI-2) << "\n";
orderFile << "AlphaPower " << aewPowerLI << "\n";
orderFile << "\nAmplitudeType " << "LoopInduced" << "\n";
}
orderFile << (*p).second.Pstr() << "\n";
}
orderFile << flush;
}
void GoSamAmplitude::signOLP(const string& order, const string& contract) {
if(!theCodeExists){
char char_cwd[256];
getcwd(char_cwd, sizeof(char_cwd));
string cwd = string(char_cwd);
string folderMatchboxBuild = factory()->buildStorage();
folderMatchboxBuild.erase(folderMatchboxBuild.begin());
generator()->log() << "\n>>> generating GoSam amplitudes. This may take some time, please be patient.\n"
<< ">>> see " + cwd + folderMatchboxBuild + "gosam-amplitudes.log for details.\n" << flush;
string cmd = GoSamPrefix_+"/bin/gosam.py --olp --output-file=" + contract + " --config=" +
gosamSetupInFileName+".tbu" + " --destination=" + gosamSourcePath + " " + order + " > " + cwd + folderMatchboxBuild + "gosam-amplitudes.log 2>&1";
std::system(cmd.c_str());
cmd = "python "+bindir_+"/gosam2herwig ";
cmd += " --makelink ";
// cmd += " --makelinkfrom=contract ";
cmd += " --makelinkfrom="+gosamPath+"/"+name()+".OLPContract.lh";
cmd += " --makelinkto="+factory()->buildStorage() + name() + ".OLPContract.lh";
std::system(cmd.c_str());
}
}
bool GoSamAmplitude::checkOLPContract(string contractFileName) {
ifstream infile(contractFileName.c_str());
string line;
vector < string > contractfile;
while (std::getline(infile, line)) contractfile.push_back(line);
for ( map<int, gosamprocinfo>::iterator p = processmap.begin() ; p != processmap.end() ; p++ ) {
bool righttype = false;
for ( vector<string>::iterator linex = contractfile.begin() ; linex != contractfile.end() ; ++linex ) {
if ( (*linex).find("AmplitudeType ")!= std::string::npos ) {
if ( (*linex).find(" " + (*p).second.Tstr() + " ")!= std::string::npos ) {
righttype = true;
} else {
righttype = false;
}
}
if ( righttype ) {
if ( (*linex).find((*p).second.Pstr()) != std::string::npos && (*p).second.Pstr().length() == (*linex).find("|") ) {
string sub = (*linex).substr((*linex).find("|") + 1, (*linex).find("#") - (*linex).find("|") - 1); // | 1 23 # buggy??
if ( sub.find(" 1 ") != 0 )
throw Exception() << "GoSamAmplitude: Failed to check contractfile. Please check the logfile.\n"
<< Exception::runerror;
string subx = sub.substr(3);
int subint;
istringstream(subx) >> subint;
(*p).second.setGID(subint);
}
}
}
}
string ids = factory()->buildStorage() + "GoSam.ids.dat";
ofstream IDS(ids.c_str());
idpair.clear();
for ( map<int, gosamprocinfo>::iterator p = processmap.begin() ; p != processmap.end() ; p++ )
idpair.push_back(-1);
idpair.push_back(-1);
for ( map<int, gosamprocinfo>::iterator p = processmap.begin() ; p != processmap.end() ; p++ ) {
idpair[(*p).second.HID()]=(*p).second.GID();
IDS << (*p).second.HID() << " " << (*p).second.GID() << " " << (*p).second.Tstr() << "\n";
if ( (*p).second.GID() == -1 ) return 0;
}
IDS << flush;
return 1;
}
bool GoSamAmplitude::buildGoSam() {
if(!theCodeExists){
generator()->log() << "\n>>> compiling GoSam amplitudes. This may take some time, please be patient.\n"
<< ">>> see " + gosamSourcePath + "gosam-build.log for details.\n\n" << flush;
string cmd = "cd " + gosamSourcePath + " && sh autogen.sh FCFLAGS=-g --prefix=" +
gosamInstallPath + " --disable-static > gosam-build.log 2>&1";
std::system(cmd.c_str());
if (!gosamBuildScript.empty()) {
cmd = "cd " + gosamSourcePath + " && " + gosamBuildScript + " >> gosam-build.log 2>&1";
std::system(cmd.c_str());
}
std::system(cmd.c_str());
cmd = "cd " + gosamSourcePath + " && make install >> gosam-build.log 2>&1";
std::system(cmd.c_str());
}
theCodeExists=true;
return 1;
}
void GoSamAmplitude::getids() const {
string line = factory()->buildStorage() + "GoSam.ids.dat";
ifstream infile(line.c_str());
int hid;
int gid;
string type;
while (std::getline(infile, line)) {
idpair.push_back(-1);
idtypepair.push_back(" ");
}
infile.close();
string line2 = factory()->buildStorage() + "GoSam.ids.dat";
ifstream infile2(line2.c_str());
idpair.push_back(-1);
idtypepair.push_back(" ");
while (std::getline(infile2, line2)) {
istringstream(line2) >> hid >> gid >> type;
idpair[hid]=gid;
idtypepair[hid]=type;
}
infile.close();
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void GoSamAmplitude::evalSubProcess() const {
useMe();
double units = pow(lastSHat() / GeV2, int(mePartonData().size()) - 4.);
fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses());
double scale = sqrt(mu2() / GeV2);
if (hasRunningAlphaS()) {
int pStatus = 0;
double zero = 0.0;
double as;
as = lastAlphaS();
OLP_SetParameter((char *)"alphaS", &as, &zero, &pStatus);
}
double out[7] = { };
double acc;
if ( idpair.size() == 0 ){ getids(); }
int id = -99;
if ( olpId()[ProcessType::loopInducedME2] ) id = olpId()[ProcessType::loopInducedME2];
else if ( olpId()[ProcessType::oneLoopInterference] ) id = olpId()[ProcessType::oneLoopInterference];
else id = olpId()[ProcessType::treeME2];
int callid(idpair[id]); // If id denotes the Herwig ID, this returns the GoSam ID
string calltype(idtypepair[id]); // If id denotes the Herwig ID, this returns the amplitude type
OLP_EvalSubProcess2(&(callid), olpMomenta(), &scale, out, &acc);
double accuracyTarget = 1.0/pow(10.0,accuracyTargetNegExp());
accuracyFileTitle = name() + ".OLPAccuracy.lh";
accuracyFile = factory()->buildStorage() + accuracyFileTitle;
ofstream accuracyFileStream;
if ( (olpId()[ProcessType::oneLoopInterference]||olpId()[ProcessType::loopInducedME2]) && acc > accuracyTarget ) {
if ( Debug::level > 1 ) {
accuracyFileStream.open(accuracyFile.c_str(),ios::app);
vector<Lorentz5Momentum> currentpsp = lastXComb().meMomenta();
time_t rawtime;
time (&rawtime);
if (doneGoSamInit) accuracyFileStream << "READ phase: ";
else if (doneGoSamInitRun) accuracyFileStream << "RUN phase: ";
accuracyFileStream << "Sub-process with Herwig ID = " << id << " and GoSam ID = " << callid << ", " << ctime(&rawtime);
accuracyFileStream << "GoSam evaluated one-loop interference or loop induced ME2 with acc = " << acc
<< " > target accuracy = " << accuracyTarget << ", at PSP [in units of GeV]:" << endl;
for (size_t i=0; i!=currentpsp.size(); ++i) {
accuracyFileStream << "(t,x,y,z,mass;m)[" << i << "]=("
<< currentpsp[i].t()/GeV << ","
<< currentpsp[i].x()/GeV << ","
<< currentpsp[i].y()/GeV << ","
<< currentpsp[i].z()/GeV << ","
<< currentpsp[i].mass()/GeV << ";"
<< currentpsp[i].m()/GeV << ")"
<< endl;
}
accuracyFileStream << endl;
}
throw Veto(); // Dispose of PSP
}
if ( olpId()[ProcessType::oneLoopInterference] ) {
if (calculateTreeME2()) lastTreeME2(out[3] * units);
lastOneLoopInterference((out[2])* units);
lastOneLoopPoles(pair<double, double>(out[0] * units, out[1] * units));
} else if ( olpId()[ProcessType::treeME2] ) {
lastTreeME2(out[3] * units);
} else if ( olpId()[ProcessType::loopInducedME2] ) {
lastTreeME2(out[2] * units);
}
}
void GoSamAmplitude::evalColourCorrelator(pair<int, int> ) const {
double units = pow(lastSHat() / GeV2, int(mePartonData().size()) - 4.);
fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses());
double scale = sqrt(mu2() / GeV2);
if (hasRunningAlphaS()) {
int pStatus = 0;
double zero = 0.0;
double as;
as = lastAlphaS();
OLP_SetParameter((char *)"alphaS", &as, &zero, &pStatus);
}
int n = lastXComb().meMomenta().size();
colourCorrelatorResults.resize(n * (n - 1) / 2);
if ( idpair.size() == 0 ) getids();
int callid(idpair[olpId()[ProcessType::colourCorrelatedME2]]);
double acc;
OLP_EvalSubProcess2(&(callid), olpMomenta(), &scale, &colourCorrelatorResults[0], &acc);
cPDVector particles = lastXComb().matrixElement()->mePartonData();
for ( int i = 0 ; i < n ; ++i ) {
for ( int j = i + 1 ; j < n ; ++j ) {
lastColourCorrelator(make_pair(i, j), colourCorrelatorResults[i+j*(j-1)/2] * units);
}
}
}
void GoSamAmplitude::evalSpinColourCorrelator(pair<int , int > ) const {
double units = pow(lastSHat() / GeV2, int(mePartonData().size()) - 4.);
fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses());
double scale = sqrt(mu2() / GeV2);
if (hasRunningAlphaS()) {
int pStatus = 0;
double zero = 0.0;
double as;
as = lastAlphaS();
OLP_SetParameter((char *)"alphaS", &as, &zero, &pStatus);
}
int n = lastXComb().meMomenta().size();
spinColourCorrelatorResults.resize(2*n*n);
if ( idpair.size() == 0 ) getids();
double acc;
int callid(idpair[olpId()[ProcessType::spinColourCorrelatedME2]]);
OLP_EvalSubProcess2(&(callid), olpMomenta(), &scale, &spinColourCorrelatorResults[0], &acc);
for ( int i = 0; i < n; ++i ) {
for ( int j = 0; j < n; ++j ) {
Complex scc(spinColourCorrelatorResults[2*i+2*n*j]*units, spinColourCorrelatorResults[2*i+2*n*j+1]*units);
lastColourSpinCorrelator(make_pair(i,j),scc);
}
}
}
LorentzVector<Complex> GoSamAmplitude::plusPolarization(const Lorentz5Momentum& p, const Lorentz5Momentum& n, int inc) const {
double pvec[4] = {p.t()/GeV,p.x()/GeV,p.y()/GeV,p.z()/GeV};
double nvec[4] = {n.t()/GeV,n.x()/GeV,n.y()/GeV,n.z()/GeV};
double out[8] ={ };
OLP_Polvec(pvec,nvec,out);
LorentzVector<Complex> res;
Complex a(out[0],out[1]);
res.setT(a);
Complex b(out[2],out[3]);
res.setX(b);
Complex c(out[4],out[5]);
res.setY(c);
Complex d(out[6],out[7]);
res.setZ(d);
if (inc<2)
return res.conjugate();
else
return res;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// If needed, insert default implementations of virtual function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void GoSamAmplitude::persistentOutput(PersistentOStream & os) const {
os << idpair << idtypepair << processmap << gosamPathInterface
<< gosamSetupInFileNameInterface << gosamBuildScript << gosamPath
<< gosamSourcePath << gosamInstallPath << gosamSetupInFileName
<< orderFileTitle << contractFileTitle
<< contractFileName << orderFileName
<< theCodeExists << theFormOpt << theNinja << isitDR << massiveParticles << theHiggsEff
<< theAccuracyTarget << theMassiveLeptons << theLoopInducedOption
<< doneGoSamInit << doneGoSamInitRun
<< bindir_ << pkgdatadir_ << GoSamPrefix_;
}
void GoSamAmplitude::persistentInput(PersistentIStream & is, int) {
is >> idpair >> idtypepair >> processmap >> gosamPathInterface
>> gosamSetupInFileNameInterface >> gosamBuildScript >> gosamPath
>> gosamSourcePath >> gosamInstallPath >> gosamSetupInFileName
>> orderFileTitle >> contractFileTitle
>> contractFileName >> orderFileName
>> theCodeExists >> theFormOpt >> theNinja >> isitDR >> massiveParticles >> theHiggsEff
>> theAccuracyTarget >> theMassiveLeptons >> theLoopInducedOption
>> doneGoSamInit >> doneGoSamInitRun
>> bindir_ >> pkgdatadir_ >> GoSamPrefix_;
}
// *** Attention *** The following static variable is needed for the type
// description system in ThePEG. Please check that the template arguments
// are correct (the class and its base class), and that the constructor
// arguments are correct (the class name and the name of the dynamically
// loadable library where the class implementation can be found).
DescribeClass<GoSamAmplitude, MatchboxOLPME> describeHerwigGoSamAmplitude("Herwig::GoSamAmplitude", "HwMatchboxGoSam.so");
void GoSamAmplitude::Init() {
static ClassDocumentation<GoSamAmplitude>
documentation("GoSamAmplitude implements an interface to GoSam.",
"Matrix elements have been calculated using GoSam \\cite{Cullen:2011xs}, \\cite{Cullen:2014yla}",
"%\\cite{Cullen:2011xs}\n"
"\\bibitem{Cullen:2011xs}\n"
"G.~Cullen et al.,\n"
"``GoSam: A Program for Automated One-Loop Calculations,''\n"
"arXiv:1111.6534 [hep-ph].\n"
"%%CITATION = ARXIV:1111.6534;%%\n"
"%\\cite{Cullen:2014yla}\n"
"\\bibitem{Cullen:2014yla}\n"
"G.~Cullen et al.,\n"
"``GoSaam-2.0: a tool for automated one-loop calculations within the Standard Model and beyond,''\n"
"arXiv:1404.7096 [hep-ph].\n"
"%%CITATION = ARXIV:1404.7096;%%");
static Parameter<GoSamAmplitude,string> interfaceProcessPath
("ProcessPath",
"Prefix for the process source code, include files and library produced by GoSam.",
&GoSamAmplitude::gosamPathInterface, "",
false, false);
static Parameter<GoSamAmplitude,string> interfaceSetupInFilename
("SetupInFilename",
"File name of the GoSam infile (typically setup.gosam.in) to be used. If left empty a new setup.gosam.in is created in the location specified in Path",
&GoSamAmplitude::gosamSetupInFileNameInterface, "",
false, false);
static Switch<GoSamAmplitude,bool> interfaceCodeExists
("CodeExists",
"Switch on or off if Code already exists/not exists.",
&GoSamAmplitude::theCodeExists, true, false, false);
static SwitchOption interfaceCodeExistsYes
(interfaceCodeExists,
"Yes",
"Switch True if Code already exists.",
true);
static SwitchOption interfaceCodeExistsNo
(interfaceCodeExists,
"No",
"Switch False if Code has to be build.",
false);
static Switch<GoSamAmplitude,bool> interfaceisitDR
("isDR",
"Switch on or off DR.",
&GoSamAmplitude::isitDR, false, false, false);
static SwitchOption interfaceisitDRYes
(interfaceisitDR,
"Yes",
"Switch True.",
true);
static SwitchOption interfaceisitDRNo
(interfaceisitDR,
"No",
"Switch False.",
false);
static Switch<GoSamAmplitude,bool> interfaceFormOpt
("FormOpt",
"Switch On/Off formopt",
&GoSamAmplitude::theFormOpt, true, false, false);
static SwitchOption interfaceFormOptYes
(interfaceFormOpt,
"Yes",
"Yes",
true);
static SwitchOption interfaceFormOptNo
(interfaceFormOpt,
"No",
"No",
false);
static Switch<GoSamAmplitude,bool> interfaceNinja
("Ninja",
"Switch On/Off for reduction with Ninja. If Off then Samurai is used.",
&GoSamAmplitude::theNinja, true, false, false);
static SwitchOption interfaceNinjaYes
(interfaceNinja,
"Yes",
"Yes",
true);
static SwitchOption interfaceNinjaNo
(interfaceNinja,
"No",
"No",
false);
static Switch<GoSamAmplitude,bool> interfaceHiggsEff
("HiggsEff",
"Switch On/Off for effective higgs model.",
&GoSamAmplitude::theHiggsEff, false, false, false);
static SwitchOption interfaceHiggsEffYes
(interfaceHiggsEff,
"Yes",
"Yes",
true);
static SwitchOption interfaceHiggsEffNo
(interfaceHiggsEff,
"No",
"No",
false);
static Parameter<GoSamAmplitude,string> interfaceBuildScript
("BuildScript",
"File name of a custom build script, which is called between 'autogen.sh'"
"and 'make install'. It can be used for parallelization.",
&GoSamAmplitude::gosamBuildScript, "",
false, false);
static Parameter<GoSamAmplitude,int> interfaceAccuracyTarget
("AccuracyTarget",
"Integer to parametrize the threshold value for the BLHA2 acc parameter, returned by GoSam in the case of "
"sub-processes with one-loop intereference terms or loop induced sub-processes."
"If acc > 10^-AccuracyTarget the corresponding PSP is being discarded. Discarded PSPs are written to file "
"if Debug::level > 1.",
&GoSamAmplitude::theAccuracyTarget, 6, 0, 0,
false, false, Interface::lowerlim);
static Switch<GoSamAmplitude,bool> interfaceMassiveLeptons
("MassiveLeptons",
"If set to Yes, then pass on the light lepton masses - as well as the tau mass - to GoSam."
"Otherwise GoSam will use light leptons of zero mass as default, as well as its own default tau mass.",
&GoSamAmplitude::theMassiveLeptons, false, false, false);
static SwitchOption interfaceMassiveLeptonsNo
(interfaceMassiveLeptons,
"No",
"No",
false);
static SwitchOption interfaceMassiveLeptonsYes
(interfaceMassiveLeptons,
"Yes",
"Yes",
true);
static Switch<GoSamAmplitude,int> interfaceLoopInducedOption
("LoopInducedOption",
"Options for the GoSam interface, in the case that a loop induced process is being considered. The default "
"option is 0, for which only the squared one-loop amplitude in the Standard Model is being considered. All "
"other options consider additional contributions from a model with an effective interaction, which lead to "
"the same final state, such as the squared effective amplitude, or the interference term between the one- "
"loop amplitude in the Standard Model and the effective amplitude, or any additive combinations therefrom. "
"In order to use those options an appropriate model has to be used.",
&GoSamAmplitude::theLoopInducedOption, 0, false, false);
static SwitchOption interfaceLoopInducedOptionLI2
(interfaceLoopInducedOption,
"LI2",
"Only consider the squared one-loop amplitude in the Standard Model.",
0);
static SwitchOption interfaceLoopInducedOptionEff2
(interfaceLoopInducedOption,
"Eff2",
"Only consider the squared effective amplitude.",
1);
static SwitchOption interfaceLoopInducedOptionLIEffInterference
(interfaceLoopInducedOption,
"LIEffInterference",
"Only consider the interference term between the one-loop amplitude "
"in the Standard Model and the effective amplitude.",
2);
static SwitchOption interfaceLoopInducedOptionLI2plusEff2
(interfaceLoopInducedOption,
"LI2plusEff2",
"Consider the sum of the squared one-loop amplitude in the Standard "
"Model plus the squared effective amplitude.",
3);
static SwitchOption interfaceLoopInducedOptionLI2plusLIEffInterference
(interfaceLoopInducedOption,
"LI2plusEffInterference",
"Consider the sum of the squared one-loop amplitude in the Standard "
"Model plus the interference term between the one-loop amplitude in "
"the Standard Model and the effective amplitude.",
4);
static SwitchOption interfaceLoopInducedOptionEff2plusLIEffInterference
(interfaceLoopInducedOption,
"Eff2plusEffInterference",
"Consider the sum of the squared effective amplitude plus the inter- "
"ference term between the one-loop amplitude in the Standard Model "
"and the effective amplitude.",
5);
static SwitchOption interfaceLoopInducedOptionAllAdditions
(interfaceLoopInducedOption,
"AllAdditions",
"Consider the sum of the squared one-loop amplitude in the Standard "
"Model plus all other contributions, which come with the effective "
"Model.",
6);
static Parameter<GoSamAmplitude,string> interfaceBinDir
("BinDir",
"The location for the installed executable",
&GoSamAmplitude::bindir_, string(HERWIG_BINDIR),
false, false);
static Parameter<GoSamAmplitude,string> interfacePKGDATADIR
("DataDir",
"The location for the installed Herwig data files",
&GoSamAmplitude::pkgdatadir_, string(HERWIG_PKGDATADIR),
false, false);
static Parameter<GoSamAmplitude,string> interfaceGoSamPrefix
("GoSamPrefix",
"The prefix for the location of GoSam",
&GoSamAmplitude::GoSamPrefix_, string(GOSAM_PREFIX),
false, false);
}
diff --git a/MatrixElement/Matchbox/External/Makefile.am b/MatrixElement/Matchbox/External/Makefile.am
--- a/MatrixElement/Matchbox/External/Makefile.am
+++ b/MatrixElement/Matchbox/External/Makefile.am
@@ -1,95 +1,95 @@
SUBDIRS = BLHAGeneric VBFNLO NJet GoSam OpenLoops MadGraph
pkglib_LTLIBRARIES =
##############
if HAVE_GOSAM
pkglib_LTLIBRARIES += HwMatchboxGoSam.la
endif
HwMatchboxGoSam_la_LDFLAGS = \
-$(AM_LDFLAGS) -module -version-info 14:0:0
+$(AM_LDFLAGS) -module -version-info 14:1:0
HwMatchboxGoSam_la_CPPFLAGS = $(AM_CPPFLAGS) \
-DHERWIG_BINDIR="\"$(bindir)\"" \
-DHERWIG_PKGDATADIR="\"$(pkgdatadir)\"" \
-DGOSAM_PREFIX="\"$(GOSAMPREFIX)\""
HwMatchboxGoSam_la_SOURCES = \
GoSam/GoSamAmplitude.cc
###############
if HAVE_VBFNLO
pkglib_LTLIBRARIES += HwMatchboxVBFNLO.la
endif
-HwMatchboxVBFNLO_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 3:0:0
+HwMatchboxVBFNLO_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 3:1:0
HwMatchboxVBFNLO_la_CPPFLAGS = $(AM_CPPFLAGS)
HwMatchboxVBFNLO_la_CPPFLAGS += -I$(VBFNLOINCLUDE)
HwMatchboxVBFNLO_la_CPPFLAGS += -DVBFNLOLIB=$(VBFNLOLIB)
HwMatchboxVBFNLO_la_SOURCES = \
VBFNLO/VBFNLOAmplitude.cc \
VBFNLO/VBFNLOPhasespace.cc
###############
if HAVE_OPENLOOPS
pkglib_LTLIBRARIES += HwMatchboxOpenLoops.la
endif
HwMatchboxOpenLoops_la_SOURCES = \
OpenLoops/OpenLoopsAmplitude.cc
HwMatchboxOpenLoops_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 13:1:0
HwMatchboxOpenLoops_la_CPPFLAGS = $(AM_CPPFLAGS) \
-DOPENLOOPSLIBS="\"$(OPENLOOPSLIBS)\"" \
-DOPENLOOPSPREFIX="\"$(OPENLOOPSPREFIX)\""
##############
if HAVE_NJET
pkglib_LTLIBRARIES += HwMatchboxNJet.la
endif
HwMatchboxNJet_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 13:0:0
HwMatchboxNJet_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(NJETINCLUDEPATH) \
-DNJET_PREFIX="\"$(NJETPREFIX)\"" \
-DNJET_LIBS="\"$(NJETLIBPATH)\""
HwMatchboxNJet_la_SOURCES = \
NJet/NJetsAmplitude.cc
##############
if HAVE_MADGRAPH
pkglib_LTLIBRARIES += HwMatchboxMadGraph.la
endif
HwMatchboxMadGraph_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 4:1:0
HwMatchboxMadGraph_la_SOURCES = \
MadGraph/MadGraphAmplitude.cc
HwMatchboxMadGraph_la_CPPFLAGS = $(AM_CPPFLAGS) \
-DHERWIG_BINDIR="\"$(bindir)\"" \
-DHERWIG_INCLUDEDIR="\"$(includedir)\"" \
-DHERWIG_PKGDATADIR="\"$(pkgdatadir)\"" \
-DMADGRAPH_PREFIX="\"$(MADGRAPHPREFIX)\""
diff --git a/MatrixElement/Matchbox/External/VBFNLO/VBFNLOAmplitude.cc b/MatrixElement/Matchbox/External/VBFNLO/VBFNLOAmplitude.cc
--- a/MatrixElement/Matchbox/External/VBFNLO/VBFNLOAmplitude.cc
+++ b/MatrixElement/Matchbox/External/VBFNLO/VBFNLOAmplitude.cc
@@ -1,477 +1,495 @@
// -*- C++ -*-
//
// VBFNLOAmplitude.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the VBFNLOAmplitude class.
//
#include "VBFNLOAmplitude.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/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Utilities/DynamicLoader.h"
#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h"
#include <cstdlib>
#include "VBFNLO/utilities/BLHAinterface.h"
#define DEFSTR(s) CPPSTR(s)
#define CPPSTR(s) #s
using namespace Herwig;
VBFNLOAmplitude::VBFNLOAmplitude()
: theRanHelSum(false), theAnomCoupl(false), VBFNLOlib_(DEFSTR(VBFNLOLIB))
{}
VBFNLOAmplitude::~VBFNLOAmplitude() {}
IBPtr VBFNLOAmplitude::clone() const {
return new_ptr(*this);
}
IBPtr VBFNLOAmplitude::fullclone() const {
return new_ptr(*this);
}
void VBFNLOAmplitude::signOLP(const string& order, const string& contract) {
int status = 0;
OLP_Order(const_cast<char*>(order.c_str()),
const_cast<char*>(contract.c_str()),&status);
if ( status != 1 )
throw Exception() << "VBFNLOAmplitude: Failed to sign contract with VBFNLO.\n"
<< "The BLHA contract file " << contract << "\n"
<< "may contain further details about the error."
<< Exception::runerror;
}
void VBFNLOAmplitude::setOLPParameter(const string& name, double value) const {
int pStatus = 0;
double zero = 0.0;
OLP_SetParameter(const_cast<char*>(name.c_str()),&value,&zero,&pStatus);
if ( !pStatus )
throw Exception() << "VBFNLOAmplitude: VBFNLO failed to set parameter '"
<< name << "' to " << value << "\n"
<< Exception::runerror;
}
void VBFNLOAmplitude::startOLP(const string& contract, int& status) {
OLP_Start(const_cast<char*>(contract.c_str()), &status);
map<long,Energy>::const_iterator it=reshuffleMasses().find(ParticleID::b);
double bmass;
if(it==reshuffleMasses().end())
bmass = getParticleData(ParticleID::b)->hardProcessMass()/GeV;
else
bmass = it->second/GeV;
setOLPParameter("mass(5)",bmass);
setOLPParameter("mass(6)",getParticleData(ParticleID::t)->hardProcessMass()/GeV);
setOLPParameter("mass(23)",getParticleData(ParticleID::Z0)->hardProcessMass()/GeV);
setOLPParameter("mass(24)",getParticleData(ParticleID::Wplus)->hardProcessMass()/GeV);
setOLPParameter("mass(25)",getParticleData(ParticleID::h0)->hardProcessMass()/GeV);
setOLPParameter("width(23)",getParticleData(ParticleID::Z0)->hardProcessWidth()/GeV);
setOLPParameter("width(24)",getParticleData(ParticleID::Wplus)->hardProcessWidth()/GeV);
setOLPParameter("width(25)",getParticleData(ParticleID::h0)->hardProcessWidth()/GeV);
setOLPParameter("alpha",SM().alphaEMMZ());
setOLPParameter("sw2",SM().sin2ThetaW());
setOLPParameter("Gf",SM().fermiConstant()*GeV2);
setOLPParameter("Nf",factory()->nLight());
setOLPParameter("alphas",SM().alphaS());
setOLPParameter("ranhelsum",theRanHelSum);
setOLPParameter("anomcoupl",theAnomCoupl);
didStartOLP() = true;
}
void VBFNLOAmplitude::loadVBFNLO() {
if ( ! DynamicLoader::load(VBFNLOlib_+"/libVBFNLO.so") ) {
string error1 = DynamicLoader::lastErrorMessage;
if ( ! DynamicLoader::load(VBFNLOlib_+"/libVBFNLO.dylib") ) {
string error2 = DynamicLoader::lastErrorMessage;
if ( ! DynamicLoader::load("libVBFNLO.so") ) {
string error3 = DynamicLoader::lastErrorMessage;
if ( ! DynamicLoader::load("libVBFNLO.dylib") ) {
string error4 = DynamicLoader::lastErrorMessage;
throw Exception() << "VBFNLOAmplitude: failed to load libVBFNLO.so/dylib\n"
<< "Error messages are:\n\n"
<< "* " << VBFNLOlib_ << "/libVBFNLO.so:\n"
<< error1 << "\n"
<< "* " << VBFNLOlib_ << "/libVBFNLO.dylib:\n"
<< error2 << "\n"
<< "* libVBFNLO.so:\n"
<< error3 << "\n"
<< "* libVBFNLO.dylib:\n"
<< error4 << "\n"
<< Exception::runerror;
}
}
}
}
}
bool VBFNLOAmplitude::startOLP(const map<pair<Process,int>,int>& procs) {
loadVBFNLO();
string orderFileName = factory()->buildStorage() + name() + ".OLPOrder.lh";
ofstream orderFile(orderFileName.c_str());
olpOrderFileHeader(orderFile);
// add VBFNLO specifics here
olpOrderFileProcesses(orderFile,procs);
orderFile << flush;
orderFile.close();
string contractFileName = factory()->buildStorage() + name() + ".OLPContract.lh";
signOLP(orderFileName, contractFileName);
int status = -1;
startOLP(contractFileName,status);
if ( status != 1 )
return false;
return true;
}
LorentzVector<Complex> VBFNLOAmplitude::plusPolarization(const Lorentz5Momentum& p,
const Lorentz5Momentum& n,
int inc) const {
// shamelessly stolen from the GoSam interface; mind that we can
// always cast eq (5.7) in the manual into a form that it only uses
// <M-||M_+> and then switch bvetween eps_+ for an outgoing and
// eps_- for an incoming gluon.
double pvec[4] = {p.t()/GeV,p.x()/GeV,p.y()/GeV,p.z()/GeV};
double nvec[4] = {n.t()/GeV,n.x()/GeV,n.y()/GeV,n.z()/GeV};
double out[8] ={ };
OLP_Polvec(pvec,nvec,out);
LorentzVector<Complex> res;
Complex a(out[0],out[1]);
res.setT(a);
Complex b(out[2],out[3]);
res.setX(b);
Complex c(out[4],out[5]);
res.setY(c);
Complex d(out[6],out[7]);
res.setZ(d);
if (inc<2)
return res.conjugate();
else
return res;
}
void VBFNLOAmplitude::evalSubProcess() const {
useMe();
double units = pow(lastSHat()/GeV2,mePartonData().size()-4.);
fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses());
double scale = sqrt(mu2()/GeV2);
if (hasRunningAlphaS()) setOLPParameter("alphas",lastAlphaS());
double acc = -1.0;
double out[4]={};
int id =
olpId()[ProcessType::oneLoopInterference] ?
olpId()[ProcessType::oneLoopInterference] :
olpId()[ProcessType::treeME2];
if (theRanHelSum) {
- vector<double> helicityrn = amplitudeRandomNumbers();
+ vector<double> helicityrn;
+ if ( lastHeadMatchboxXComb() ) {
+ helicityrn = lastHeadMatchboxXComb()->amplitudeRandomNumbers();
+ } else {
+ helicityrn = amplitudeRandomNumbers();
+ }
if (helicityrn.size()>0) {
setOLPParameter("HelicityRN",helicityrn[0]);
}
}
OLP_EvalSubProcess2(&id, olpMomenta(), &scale, out, &acc);
if ( olpId()[ProcessType::oneLoopInterference] ) {
lastTreeME2(out[3]*units);
lastOneLoopInterference(out[2]*units);
lastOneLoopPoles(pair<double,double>(out[0]*units,out[1]*units));
} else if ( olpId()[ProcessType::treeME2] ) {
lastTreeME2(out[0]*units);
} else assert(false);
}
void VBFNLOAmplitude::evalColourCorrelator(pair<int,int>) const {
double units = pow(lastSHat()/GeV2,mePartonData().size()-4.);
fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses());
double scale = sqrt(mu2()/GeV2);
if (hasRunningAlphaS()) setOLPParameter("alphas",lastAlphaS());
double acc = -1.0;
int n = lastXComb().meMomenta().size();
colourCorrelatorResults.resize(n*(n-1)/2);
int id = olpId()[ProcessType::colourCorrelatedME2];
- if ( theRanHelSum ) {
+ if (theRanHelSum) {
+ vector<double> helicityrn;
if ( lastHeadMatchboxXComb() ) {
- vector<double> helicityrn = lastHeadMatchboxXComb()->amplitudeRandomNumbers();
- if (helicityrn.size()>0) {
- setOLPParameter("HelicityRN",helicityrn[0]);
- }
- } else if ( amplitudeRandomNumbers().size() > 0 ) {
- vector<double> helicityrn = amplitudeRandomNumbers();
- if (helicityrn.size()>0) {
- setOLPParameter("HelicityRN",helicityrn[0]);
- }
+ helicityrn = lastHeadMatchboxXComb()->amplitudeRandomNumbers();
+ } else {
+ helicityrn = amplitudeRandomNumbers();
+ }
+ if (helicityrn.size()>0) {
+ setOLPParameter("HelicityRN",helicityrn[0]);
}
}
OLP_EvalSubProcess2(&id, olpMomenta(), &scale, &colourCorrelatorResults[0], &acc);
for ( int i = 0; i < n; ++i )
for ( int j = i+1; j < n; ++j ) {
lastColourCorrelator(make_pair(i,j),colourCorrelatorResults[i+j*(j-1)/2]*units);
}
}
void VBFNLOAmplitude::evalSpinColourCorrelator(pair<int,int>) const {
double units = pow(lastSHat()/GeV2,mePartonData().size()-4.);
fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses());
double scale = sqrt(mu2()/GeV2);
if (hasRunningAlphaS()) setOLPParameter("alphas",lastAlphaS());
double acc = -1.0;
int n = lastXComb().meMomenta().size();
spinColourCorrelatorResults.resize(2*n*n);
int id = olpId()[ProcessType::spinColourCorrelatedME2];
- if (theRanHelSum && lastHeadMatchboxXComb()) {
- vector<double> helicityrn = lastHeadMatchboxXComb()->amplitudeRandomNumbers();
+ if (theRanHelSum) {
+ vector<double> helicityrn;
+ if ( lastHeadMatchboxXComb() ) {
+ helicityrn = lastHeadMatchboxXComb()->amplitudeRandomNumbers();
+ } else {
+ helicityrn = amplitudeRandomNumbers();
+ }
if (helicityrn.size()>0) {
setOLPParameter("HelicityRN",helicityrn[0]);
}
}
OLP_EvalSubProcess2(&id, olpMomenta(), &scale, &spinColourCorrelatorResults[0], &acc);
for ( int i = 0; i < n; ++i )
for ( int j = 0; j < n; ++j ) {
if ( i == j || mePartonData()[i]->id() != 21 )
continue;
Complex scc(spinColourCorrelatorResults[2*i+2*n*j]*units,
spinColourCorrelatorResults[2*i+2*n*j+1]*units);
lastColourSpinCorrelator(make_pair(i,j),scc);
}
}
double VBFNLOAmplitude::largeNME2(Ptr<ColourBasis>::tptr cptr) const {
if ( calculateLargeNME2() )
evalLargeNSubProcess(cptr);
return lastLargeNME2();
}
void VBFNLOAmplitude::evalLargeNSubProcess(Ptr<ColourBasis>::tptr) const {
double units = pow(lastSHat()/GeV2,mePartonData().size()-4.);
fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses());
double scale = sqrt(mu2()/GeV2);
if (hasRunningAlphaS()) setOLPParameter("alphas",lastAlphaS());
double acc = -1.0;
double out[4]={};
int id =
olpId()[ProcessType::oneLoopInterference] ?
olpId()[ProcessType::oneLoopInterference] :
olpId()[ProcessType::treeME2];
if (theRanHelSum) {
- vector<double> helicityrn = amplitudeRandomNumbers();
+ vector<double> helicityrn;
+ if ( lastHeadMatchboxXComb() ) {
+ helicityrn = lastHeadMatchboxXComb()->amplitudeRandomNumbers();
+ } else {
+ helicityrn = amplitudeRandomNumbers();
+ }
if (helicityrn.size()>0) {
setOLPParameter("HelicityRN",helicityrn[0]);
}
}
setOLPParameter("Nc",-1); // large-N limit
OLP_EvalSubProcess2(&id, olpMomenta(), &scale, out, &acc);
setOLPParameter("Nc",generator()->standardModel()->Nc());
if ( olpId()[ProcessType::oneLoopInterference] ) {
lastLargeNME2(out[3]*units);
lastOneLoopInterference(out[2]*units);
lastOneLoopPoles(pair<double,double>(out[0]*units,out[1]*units));
} else if ( olpId()[ProcessType::treeME2] ) {
lastLargeNME2(out[0]*units);
} else assert(false);
}
double VBFNLOAmplitude::largeNColourCorrelatedME2(pair<int,int> ij,
Ptr<ColourBasis>::tptr cptr) const {
double cfac = 1.;
double Nc = generator()->standardModel()->Nc();
if ( mePartonData()[ij.first]->iColour() == PDT::Colour8 ) {
cfac = Nc;
} else if ( mePartonData()[ij.first]->iColour() == PDT::Colour3 ||
mePartonData()[ij.first]->iColour() == PDT::Colour3bar ) {
cfac = Nc/2.;
} else assert(false);
if ( calculateLargeNColourCorrelator(ij) )
evalLargeNColourCorrelator(ij,cptr);
return lastLargeNColourCorrelator(ij)/cfac;
}
void VBFNLOAmplitude::evalLargeNColourCorrelator(pair<int,int>,
Ptr<ColourBasis>::tptr) const {
double units = pow(lastSHat()/GeV2,mePartonData().size()-4.);
fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses());
double scale = sqrt(mu2()/GeV2);
if (hasRunningAlphaS()) setOLPParameter("alphas",lastAlphaS());
double acc = -1.0;
int n = lastXComb().meMomenta().size();
colourCorrelatorResults.resize(n*(n-1)/2);
int id = olpId()[ProcessType::colourCorrelatedME2];
- if (theRanHelSum && lastHeadMatchboxXComb()) {
- vector<double> helicityrn = lastHeadMatchboxXComb()->amplitudeRandomNumbers();
+ if (theRanHelSum) {
+ vector<double> helicityrn;
+ if ( lastHeadMatchboxXComb() ) {
+ helicityrn = lastHeadMatchboxXComb()->amplitudeRandomNumbers();
+ } else {
+ helicityrn = amplitudeRandomNumbers();
+ }
if (helicityrn.size()>0) {
setOLPParameter("HelicityRN",helicityrn[0]);
}
}
setOLPParameter("Nc",-1); // large-N limit
OLP_EvalSubProcess2(&id, olpMomenta(), &scale, &colourCorrelatorResults[0], &acc);
setOLPParameter("Nc",generator()->standardModel()->Nc());
for ( int i = 0; i < n; ++i )
for ( int j = i+1; j < n; ++j ) {
lastLargeNColourCorrelator(make_pair(i,j),colourCorrelatorResults[i+j*(j-1)/2]*units);
}
}
void VBFNLOAmplitude::doinit() {
loadVBFNLO();
MatchboxOLPME::doinit();
}
void VBFNLOAmplitude::doinitrun() {
loadVBFNLO();
MatchboxOLPME::doinitrun();
}
void VBFNLOAmplitude::persistentOutput(PersistentOStream & os) const {
os << colourCorrelatorResults << spinColourCorrelatorResults << theRanHelSum << theAnomCoupl << VBFNLOlib_;
}
void VBFNLOAmplitude::persistentInput(PersistentIStream & is, int) {
is >> colourCorrelatorResults >> spinColourCorrelatorResults >> theRanHelSum >> theAnomCoupl >> VBFNLOlib_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<VBFNLOAmplitude,MatchboxOLPME>
describeHerwigVBFNLOAmplitude("Herwig::VBFNLOAmplitude", "HwMatchboxVBFNLO.so");
void VBFNLOAmplitude::Init() {
static ClassDocumentation<VBFNLOAmplitude> documentation
("VBFNLOAmplitude implements an interface to VBFNLO.",
"Matrix elements have been calculated using VBFNLO "
"(Ref.~\\cite{VBFNLO} and process-specific references)\n",
"%\\cite{VBFNLO}\n"
"\\bibitem{Arnold:2008rz}\n"
"K.~Arnold, M.~Bahr, G.~Bozzi, F.~Campanario, C.~Englert, T.~Figy, "
"N.~Greiner and C.~Hackstein {\\it et al.},\n"
"``VBFNLO: A Parton level Monte Carlo for processes with electroweak bosons,''\n"
"Comput.\\ Phys.\\ Commun.\\ {\\bf 180} (2009) 1661\n"
"[arXiv:0811.4559 [hep-ph]];\n"
"%%CITATION = ARXIV:0811.4559;%%\n"
"J.~Baglio, J.~Bellm, F.~Campanario, B.~Feigl, J.~Frank, T.~Figy, "
"M.~Kerner and L.~D.~Ninh {\\it et al.},\n"
"``Release Note - VBFNLO 2.7.0,''\n"
"arXiv:1404.3940 [hep-ph].\n"
"%%CITATION = ARXIV:1404.3940;%%\n");
static Switch<VBFNLOAmplitude,bool> interfaceRandomHelicitySummation
("RandomHelicitySummation", "Switch for random helicity summation of leptons and photons",
&VBFNLOAmplitude::theRanHelSum, false, false, false);
static SwitchOption interfaceRandomHelicitySummationYes
(interfaceRandomHelicitySummation,
"Yes",
"Perform random helicity summation",
true);
static SwitchOption interfaceRandomHelicitySummationNo
(interfaceRandomHelicitySummation,
"No",
"Sum over all helicity combinations",
false);
static Switch<VBFNLOAmplitude,bool> interfaceAnomalousCouplings
("AnomalousCouplings", "Switch for anomalous couplings",
&VBFNLOAmplitude::theAnomCoupl, false, false, false);
static SwitchOption interfaceAnomalousCouplingsYes
(interfaceAnomalousCouplings,
"Yes",
"Switch anomalous couplings on",
true);
static SwitchOption interfaceAnomalousCouplingsNo
(interfaceAnomalousCouplings,
"No",
"Switch anomalous couplings off",
false);
}
diff --git a/MatrixElement/Matchbox/Matching/DipoleMatching.cc b/MatrixElement/Matchbox/Matching/DipoleMatching.cc
--- a/MatrixElement/Matchbox/Matching/DipoleMatching.cc
+++ b/MatrixElement/Matchbox/Matching/DipoleMatching.cc
@@ -1,139 +1,147 @@
// -*- C++ -*-
//
// DipoleMatching.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DipoleMatching class.
//
#include "DipoleMatching.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.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/MatrixElement/Matchbox/Dipoles/SubtractionDipole.h"
using namespace Herwig;
DipoleMatching::DipoleMatching() {}
DipoleMatching::~DipoleMatching() {}
IBPtr DipoleMatching::clone() const {
return new_ptr(*this);
}
IBPtr DipoleMatching::fullclone() const {
return new_ptr(*this);
}
CrossSection DipoleMatching::dSigHatDR() const {
double xme2 = 0.;
pair<int,int> ij(dipole()->bornEmitter(),
dipole()->bornSpectator());
double ccme2 =
dipole()->underlyingBornME()->largeNColourCorrelatedME2(ij,theLargeNBasis);
if(ccme2==0.)return 0.*nanobarn;
double lnme2=dipole()->underlyingBornME()->largeNME2(theLargeNBasis);
if(lnme2==0){
generator()->log() <<"\nDipoleMatching: ";
generator()->log() <<"\n LargeNME2 is ZERO, while largeNColourCorrelatedME2 is not ZERO." ;
generator()->log() <<"\n This is too seriuos.\n" ;
generator()->log() << Exception::runerror;
}
ccme2 *=
dipole()->underlyingBornME()->me2() /lnme2;
xme2 = dipole()->me2Avg(ccme2);
xme2 /= dipole()->underlyingBornME()->lastXComb().lastAlphaS();
double bornPDF = bornPDFWeight(dipole()->underlyingBornME()->lastScale());
if ( bornPDF == 0.0 )
return ZERO;
xme2 *= bornPDF;
if ( profileScales() )
xme2 *= profileScales()->hardScaleProfile(dipole()->showerHardScale(),dipole()->lastPt());
CrossSection res =
sqr(hbarc) *
realXComb()->jacobian() *
subtractionScaleWeight() *
xme2 /
(2. * realXComb()->lastSHat());
return res;
}
double DipoleMatching::me2() const {
throw Exception() << "DipoleMatching::me2(): Not intented to use. Disable the ShowerApproximationGenerator."
<< Exception::runerror;
return 0.;
}
// If needed, insert default implementations of virtual function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void DipoleMatching::persistentOutput(PersistentOStream & os) const {
os << theShowerHandler;
}
void DipoleMatching::persistentInput(PersistentIStream & is, int) {
is >> theShowerHandler;
}
void DipoleMatching::doinit() {
if ( theShowerHandler ) {
+ theShowerHandler->init();
hardScaleFactor(theShowerHandler->hardScaleFactor());
factorizationScaleFactor(theShowerHandler->factorizationScaleFactor());
renormalizationScaleFactor(theShowerHandler->renormalizationScaleFactor());
profileScales(theShowerHandler->profileScales());
restrictPhasespace(theShowerHandler->restrictPhasespace());
hardScaleIsMuF(theShowerHandler->hardScaleIsMuF());
+ if ( theShowerHandler->showerPhaseSpaceOption() == 0 ) {
+ useOpenZ(false);
+ } else if ( theShowerHandler->showerPhaseSpaceOption() == 1 ) {
+ useOpenZ(true);
+ } else {
+ throw InitException() << "DipoleMatching::doinit(): Choice of shower phase space cannot be handled by the matching";
+ }
}
// need to fo this after for consistency checks
ShowerApproximation::doinit();
}
// *** Attention *** The following static variable is needed for the type
// description system in ThePEG. Please check that the template arguments
// are correct (the class and its base class), and that the constructor
// arguments are correct (the class name and the name of the dynamically
// loadable library where the class implementation can be found).
DescribeClass<DipoleMatching,Herwig::ShowerApproximation>
describeHerwigDipoleMatching("Herwig::DipoleMatching", "HwDipoleMatching.so HwShower.so");
void DipoleMatching::Init() {
static ClassDocumentation<DipoleMatching> documentation
("DipoleMatching implements NLO matching with the dipole shower.");
static Reference<DipoleMatching,ShowerHandler> interfaceShowerHandler
("ShowerHandler",
"The dipole shower handler object to use.",
&DipoleMatching::theShowerHandler, false, false, true, true, false);
interfaceShowerHandler.rank(-1);
}
diff --git a/MatrixElement/Matchbox/Matching/Makefile.am b/MatrixElement/Matchbox/Matching/Makefile.am
--- a/MatrixElement/Matchbox/Matching/Makefile.am
+++ b/MatrixElement/Matchbox/Matching/Makefile.am
@@ -1,24 +1,24 @@
noinst_LTLIBRARIES = libHwMatchboxMatching.la
pkglib_LTLIBRARIES = HwQTildeMatching.la HwDipoleMatching.la
libHwMatchboxMatching_la_SOURCES = \
HardScaleProfile.h \
HardScaleProfile.cc \
ShowerApproximation.h \
ShowerApproximation.cc \
ShowerApproximationKernel.h \
ShowerApproximationKernel.cc \
ShowerApproximationGenerator.h \
ShowerApproximationGenerator.cc \
MEMatching.h \
MEMatching.cc
HwQTildeMatching_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 3:0:0
HwQTildeMatching_la_SOURCES = \
QTildeMatching.h \
QTildeMatching.cc
-HwDipoleMatching_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 3:0:0
+HwDipoleMatching_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 3:1:0
HwDipoleMatching_la_SOURCES = \
DipoleMatching.h \
DipoleMatching.cc
diff --git a/MatrixElement/Matchbox/Matching/ShowerApproximation.cc b/MatrixElement/Matchbox/Matching/ShowerApproximation.cc
--- a/MatrixElement/Matchbox/Matching/ShowerApproximation.cc
+++ b/MatrixElement/Matchbox/Matching/ShowerApproximation.cc
@@ -1,716 +1,716 @@
// -*- C++ -*-
//
// ShowerApproximation.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ShowerApproximation class.
//
#include "ShowerApproximation.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/MatrixElement/Matchbox/Dipoles/SubtractionDipole.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/TildeKinematics.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.h"
using namespace Herwig;
ShowerApproximation::ShowerApproximation()
: HandlerBase(),
theExtrapolationX(1.0), theBelowCutoff(false),
theFFPtCut(1.0*GeV), theFFScreeningScale(ZERO),
theFIPtCut(1.0*GeV), theFIScreeningScale(ZERO),
theIIPtCut(1.0*GeV), theIIScreeningScale(ZERO),
theSafeCut(0.0*GeV),
theRestrictPhasespace(true), theHardScaleFactor(1.0),
theRenormalizationScaleFactor(1.0), theFactorizationScaleFactor(1.0),
theRealEmissionScaleInSubtraction(showerScale),
theBornScaleInSubtraction(showerScale),
theEmissionScaleInSubtraction(showerScale),
theRealEmissionScaleInSplitting(showerScale),
theBornScaleInSplitting(showerScale),
theEmissionScaleInSplitting(showerScale),
theRenormalizationScaleFreeze(1.*GeV),
theFactorizationScaleFreeze(1.*GeV),
- maxPtIsMuF(false) {}
+ maxPtIsMuF(false), theOpenZ(true) {}
ShowerApproximation::~ShowerApproximation() {}
void ShowerApproximation::setLargeNBasis() {
assert(dipole()->realEmissionME()->matchboxAmplitude());
if ( !dipole()->realEmissionME()->matchboxAmplitude()->treeAmplitudes() )
return;
if ( !theLargeNBasis ) {
if ( !dipole()->realEmissionME()->matchboxAmplitude()->colourBasis() )
throw Exception() << "ShowerApproximation::setLargeNBasis(): Expecting a colour basis object."
<< Exception::runerror;
theLargeNBasis =
dipole()->realEmissionME()->matchboxAmplitude()->colourBasis()->cloneMe();
theLargeNBasis->clear();
theLargeNBasis->doLargeN();
}
}
void ShowerApproximation::setDipole(Ptr<SubtractionDipole>::tptr dip) {
theDipole = dip;
setLargeNBasis();
}
Ptr<SubtractionDipole>::tptr ShowerApproximation::dipole() const { return theDipole; }
Ptr<TildeKinematics>::tptr
ShowerApproximation::showerTildeKinematics() const {
return Ptr<TildeKinematics>::tptr();
}
Ptr<InvertedTildeKinematics>::tptr
ShowerApproximation::showerInvertedTildeKinematics() const {
return Ptr<InvertedTildeKinematics>::tptr();
}
void ShowerApproximation::checkCutoff() {
assert(!showerTildeKinematics());
}
void ShowerApproximation::getShowerVariables() {
// check for the cutoff
dipole()->isAboveCutoff(isAboveCutoff());
// get the hard scale
dipole()->showerHardScale(hardScale());
// set the shower scale and variables for completeness
dipole()->showerScale(dipole()->lastPt());
dipole()->showerParameters().resize(1);
dipole()->showerParameters()[0] = dipole()->lastZ();
// check for phase space
dipole()->isInShowerPhasespace(isInShowerPhasespace());
}
bool ShowerApproximation::isAboveCutoff() const {
if ( dipole()->bornEmitter() > 1 &&
dipole()->bornSpectator() > 1 ) {
return dipole()->lastPt() >= max(ffPtCut(),safeCut());
} else if ( ( dipole()->bornEmitter() > 1 &&
dipole()->bornSpectator() < 2 ) ||
( dipole()->bornEmitter() < 2 &&
dipole()->bornSpectator() > 1 ) ) {
return dipole()->lastPt() >= max(fiPtCut(),safeCut());
} else {
assert(dipole()->bornEmitter() < 2 &&
dipole()->bornSpectator() < 2);
return dipole()->lastPt() >= max(iiPtCut(),safeCut());
}
return true;
}
Energy ShowerApproximation::hardScale() const {
if ( !maxPtIsMuF ) {
if ( !bornCXComb()->mePartonData()[0]->coloured() &&
!bornCXComb()->mePartonData()[1]->coloured() ) {
Energy maxPt = (bornCXComb()->meMomenta()[0] + bornCXComb()->meMomenta()[1]).m();
maxPt *= hardScaleFactor();
return maxPt;
}
Energy maxPt = generator()->maximumCMEnergy();
vector<Lorentz5Momentum>::const_iterator p =
bornCXComb()->meMomenta().begin() + 2;
cPDVector::const_iterator pp =
bornCXComb()->mePartonData().begin() + 2;
for ( ; p != bornCXComb()->meMomenta().end(); ++p, ++pp )
if ( (**pp).coloured() )
maxPt = min(maxPt,p->mt());
if ( maxPt == generator()->maximumCMEnergy() )
maxPt = (bornCXComb()->meMomenta()[0] + bornCXComb()->meMomenta()[1]).m();
maxPt *= hardScaleFactor();
return maxPt;
} else {
return hardScaleFactor()*sqrt(bornCXComb()->lastShowerScale());
}
}
bool ShowerApproximation::isInShowerPhasespace() const {
if ( !dipole()->isAboveCutoff() )
return false;
if ( !restrictPhasespace() )
return true;
InvertedTildeKinematics& kinematics =
const_cast<InvertedTildeKinematics&>(*dipole()->invertedTildeKinematics());
tcStdXCombPtr tmpreal = kinematics.realXComb();
tcStdXCombPtr tmpborn = kinematics.bornXComb();
Ptr<SubtractionDipole>::tptr tmpdip = kinematics.dipole();
Energy hard = dipole()->showerHardScale();
Energy pt = dipole()->lastPt();
double z = dipole()->lastZ();
pair<double,double> zbounds(0.,1.);
kinematics.dipole(const_ptr_cast<Ptr<SubtractionDipole>::tptr>(theDipole));
kinematics.prepare(realCXComb(),bornCXComb());
if ( pt > hard ) {
kinematics.dipole(tmpdip);
kinematics.prepare(tmpreal,tmpborn);
return false;
}
try {
- zbounds = kinematics.zBounds(pt,hard);
+ zbounds = kinematics.zBounds(pt,openZ() ? kinematics.ptMax() : hard);
} catch(...) {
kinematics.dipole(tmpdip);
kinematics.prepare(tmpreal,tmpborn);
throw;
}
kinematics.dipole(tmpdip);
kinematics.prepare(tmpreal,tmpborn);
return z > zbounds.first && z < zbounds.second;
}
Energy2 ShowerApproximation::showerEmissionScale() const {
Energy2 mur = sqr(dipole()->lastPt());
if ( dipole()->bornEmitter() > 1 &&
dipole()->bornSpectator() > 1 ) {
return mur + sqr(ffScreeningScale());
} else if ( ( dipole()->bornEmitter() > 1 &&
dipole()->bornSpectator() < 2 ) ||
( dipole()->bornEmitter() < 2 &&
dipole()->bornSpectator() > 1 ) ) {
return mur + sqr(fiScreeningScale());
} else {
assert(dipole()->bornEmitter() < 2 &&
dipole()->bornSpectator() < 2);
return mur + sqr(iiScreeningScale());
}
return mur;
}
Energy2 ShowerApproximation::bornRenormalizationScale() const {
return
sqr(dipole()->underlyingBornME()->renormalizationScaleFactor()) *
dipole()->underlyingBornME()->renormalizationScale();
}
Energy2 ShowerApproximation::bornFactorizationScale() const {
return
sqr(dipole()->underlyingBornME()->factorizationScaleFactor()) *
dipole()->underlyingBornME()->factorizationScale();
}
Energy2 ShowerApproximation::realRenormalizationScale() const {
return
sqr(dipole()->realEmissionME()->renormalizationScaleFactor()) *
dipole()->realEmissionME()->renormalizationScale();
}
Energy2 ShowerApproximation::realFactorizationScale() const {
return
sqr(dipole()->realEmissionME()->factorizationScaleFactor()) *
dipole()->realEmissionME()->factorizationScale();
}
double ShowerApproximation::bornPDFWeight(Energy2 muf) const {
if ( !bornCXComb()->mePartonData()[0]->coloured() &&
!bornCXComb()->mePartonData()[1]->coloured() )
return 1.;
if ( muf < sqr(theFactorizationScaleFreeze) )
muf = sqr(theFactorizationScaleFreeze);
double pdfweight = 1.;
if ( bornCXComb()->mePartonData()[0]->coloured() &&
dipole()->underlyingBornME()->havePDFWeight1() )
pdfweight *= dipole()->underlyingBornME()->pdf1(muf,theExtrapolationX);
if ( bornCXComb()->mePartonData()[1]->coloured() &&
dipole()->underlyingBornME()->havePDFWeight2() )
pdfweight *= dipole()->underlyingBornME()->pdf2(muf,theExtrapolationX);
return pdfweight;
}
double ShowerApproximation::realPDFWeight(Energy2 muf) const {
if ( !realCXComb()->mePartonData()[0]->coloured() &&
!realCXComb()->mePartonData()[1]->coloured() )
return 1.;
if ( muf < sqr(theFactorizationScaleFreeze) )
muf = sqr(theFactorizationScaleFreeze);
double pdfweight = 1.;
if ( realCXComb()->mePartonData()[0]->coloured() &&
dipole()->realEmissionME()->havePDFWeight1() )
pdfweight *= dipole()->realEmissionME()->pdf1(muf,theExtrapolationX);
if ( realCXComb()->mePartonData()[1]->coloured() &&
dipole()->realEmissionME()->havePDFWeight2() )
pdfweight *= dipole()->realEmissionME()->pdf2(muf,theExtrapolationX);
return pdfweight;
}
double ShowerApproximation::scaleWeight(int rScale, int bScale, int eScale) const {
double emissionAlpha = 1.;
Energy2 emissionScale = ZERO;
Energy2 showerscale = ZERO;
if ( eScale == showerScale || bScale == showerScale || eScale == showerScale ) {
showerscale = showerRenormalizationScale();
if ( showerscale < sqr(theRenormalizationScaleFreeze) )
showerscale = sqr(theFactorizationScaleFreeze);
}
if ( eScale == showerScale ) {
emissionAlpha = SM().alphaS(showerscale);
emissionScale = showerFactorizationScale();
} else if ( eScale == realScale ) {
emissionAlpha = dipole()->realEmissionME()->lastXComb().lastAlphaS();
emissionScale = dipole()->realEmissionME()->lastScale();
} else if ( eScale == bornScale ) {
emissionAlpha = dipole()->underlyingBornME()->lastXComb().lastAlphaS();
emissionScale = dipole()->underlyingBornME()->lastScale();
}
double emissionPDF = realPDFWeight(emissionScale);
double couplingFactor = 1.;
if ( bScale != rScale ) {
double bornAlpha = 1.;
if ( bScale == showerScale ) {
bornAlpha = SM().alphaS(showerscale);
} else if ( bScale == realScale ) {
bornAlpha = dipole()->realEmissionME()->lastXComb().lastAlphaS();
} else if ( bScale == bornScale ) {
bornAlpha = dipole()->underlyingBornME()->lastXComb().lastAlphaS();
}
double realAlpha = 1.;
if ( rScale == showerScale ) {
realAlpha = SM().alphaS(showerscale);
} else if ( rScale == realScale ) {
realAlpha = dipole()->realEmissionME()->lastXComb().lastAlphaS();
} else if ( rScale == bornScale ) {
realAlpha = dipole()->underlyingBornME()->lastXComb().lastAlphaS();
}
couplingFactor *=
pow(realAlpha/bornAlpha,(double)(dipole()->underlyingBornME()->orderInAlphaS()));
}
Energy2 hardScale = ZERO;
if ( bScale == showerScale ) {
hardScale = showerFactorizationScale();
} else if ( bScale == realScale ) {
hardScale = dipole()->realEmissionME()->lastScale();
} else if ( bScale == bornScale ) {
hardScale = dipole()->underlyingBornME()->lastScale();
}
double bornPDF = bornPDFWeight(hardScale);
if ( bornPDF < 1e-8 )
bornPDF = 0.0;
if ( emissionPDF < 1e-8 )
emissionPDF = 0.0;
if ( emissionPDF == 0.0 || bornPDF == 0.0 )
return 0.0;
return
emissionAlpha * emissionPDF *
couplingFactor / bornPDF;
}
double ShowerApproximation::channelWeight(int emitter, int emission,
int spectator, int) const {
double cfac = 1.;
double Nc = generator()->standardModel()->Nc();
if (realCXComb()->mePartonData()[emitter]->iColour() == PDT::Colour8){
if (realCXComb()->mePartonData()[emission]->iColour() == PDT::Colour8)
cfac = Nc;
else if ( realCXComb()->mePartonData()[emission]->iColour() == PDT::Colour3 ||
realCXComb()->mePartonData()[emission]->iColour() == PDT::Colour3bar)
cfac = 0.5;
else assert(false);
}
else if ((realCXComb()->mePartonData()[emitter] ->iColour() == PDT::Colour3 ||
realCXComb()->mePartonData()[emitter] ->iColour() == PDT::Colour3bar))
cfac = (sqr(Nc)-1.)/(2.*Nc);
else assert(false);
// do the most simple thing for the time being; needs fixing later
if ( realCXComb()->mePartonData()[emission]->id() == ParticleID::g ) {
Energy2 pipk =
realCXComb()->meMomenta()[emitter] * realCXComb()->meMomenta()[spectator];
Energy2 pipj =
realCXComb()->meMomenta()[emitter] * realCXComb()->meMomenta()[emission];
Energy2 pjpk =
realCXComb()->meMomenta()[emission] * realCXComb()->meMomenta()[spectator];
return cfac *GeV2 * pipk / ( pipj * ( pipj + pjpk ) );
}
return
cfac * GeV2 / (realCXComb()->meMomenta()[emitter] * realCXComb()->meMomenta()[emission]);
}
double ShowerApproximation::channelWeight() const {
double currentChannel = channelWeight(dipole()->realEmitter(),
dipole()->realEmission(),
dipole()->realSpectator(),
dipole()->bornEmitter());
if ( currentChannel == 0. )
return 0.;
double sum = 0.;
for ( vector<Ptr<SubtractionDipole>::tptr>::const_iterator dip =
dipole()->partnerDipoles().begin();
dip != dipole()->partnerDipoles().end(); ++dip )
sum += channelWeight((**dip).realEmitter(),
(**dip).realEmission(),
(**dip).realSpectator(),
(**dip).bornEmitter());
assert(sum > 0.0);
return currentChannel / sum;
}
// If needed, insert default implementations of virtual function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void ShowerApproximation::doinit() {
if ( profileScales() ) {
if ( profileScales()->unrestrictedPhasespace() &&
restrictPhasespace() ) {
generator()->log()
<< "ShowerApproximation warning: The scale profile chosen requires an unrestricted phase space,\n"
<< "however, the phase space was set to be restricted. Will switch to unrestricted phase space.\n"
<< flush;
restrictPhasespace(false);
}
}
HandlerBase::doinit();
}
void ShowerApproximation::persistentOutput(PersistentOStream & os) const {
os << theLargeNBasis
<< theBornXComb << theRealXComb << theTildeXCombs << theDipole << theBelowCutoff
<< ounit(theFFPtCut,GeV) << ounit(theFFScreeningScale,GeV)
<< ounit(theFIPtCut,GeV) << ounit(theFIScreeningScale,GeV)
<< ounit(theIIPtCut,GeV) << ounit(theIIScreeningScale,GeV)
<< ounit(theSafeCut,GeV)
<< theRestrictPhasespace << theHardScaleFactor
<< theRenormalizationScaleFactor << theFactorizationScaleFactor
<< theExtrapolationX
<< theRealEmissionScaleInSubtraction << theBornScaleInSubtraction
<< theEmissionScaleInSubtraction << theRealEmissionScaleInSplitting
<< theBornScaleInSplitting << theEmissionScaleInSplitting
<< ounit(theRenormalizationScaleFreeze,GeV)
<< ounit(theFactorizationScaleFreeze,GeV) << maxPtIsMuF
- << theHardScaleProfile;
+ << theHardScaleProfile << theOpenZ;
}
void ShowerApproximation::persistentInput(PersistentIStream & is, int) {
is >> theLargeNBasis
>> theBornXComb >> theRealXComb >> theTildeXCombs >> theDipole >> theBelowCutoff
>> iunit(theFFPtCut,GeV) >> iunit(theFFScreeningScale,GeV)
>> iunit(theFIPtCut,GeV) >> iunit(theFIScreeningScale,GeV)
>> iunit(theIIPtCut,GeV) >> iunit(theIIScreeningScale,GeV)
>> iunit(theSafeCut,GeV)
>> theRestrictPhasespace >> theHardScaleFactor
>> theRenormalizationScaleFactor >> theFactorizationScaleFactor
>> theExtrapolationX
>> theRealEmissionScaleInSubtraction >> theBornScaleInSubtraction
>> theEmissionScaleInSubtraction >> theRealEmissionScaleInSplitting
>> theBornScaleInSplitting >> theEmissionScaleInSplitting
>> iunit(theRenormalizationScaleFreeze,GeV)
>> iunit(theFactorizationScaleFreeze,GeV) >> maxPtIsMuF
- >> theHardScaleProfile;
+ >> theHardScaleProfile >> theOpenZ;
}
// *** Attention *** The following static variable is needed for the type
// description system in ThePEG. Please check that the template arguments
// are correct (the class and its base class), and that the constructor
// arguments are correct (the class name and the name of the dynamically
// loadable library where the class implementation can be found).
DescribeAbstractClass<ShowerApproximation,HandlerBase>
describeHerwigShowerApproximation("Herwig::ShowerApproximation", "Herwig.so");
void ShowerApproximation::Init() {
static ClassDocumentation<ShowerApproximation> documentation
("ShowerApproximation describes the shower emission to be used "
"in NLO matching.");
static Parameter<ShowerApproximation,Energy> interfaceFFPtCut
("FFPtCut",
"Set the pt infrared cutoff",
&ShowerApproximation::theFFPtCut, GeV, 1.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,Energy> interfaceFIPtCut
("FIPtCut",
"Set the pt infrared cutoff",
&ShowerApproximation::theFIPtCut, GeV, 1.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,Energy> interfaceIIPtCut
("IIPtCut",
"Set the pt infrared cutoff",
&ShowerApproximation::theIIPtCut, GeV, 1.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,Energy> interfaceSafeCut
("SafeCut",
"Set the enhanced infrared cutoff for the Matching.",
&ShowerApproximation::theSafeCut, GeV, 0.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,Energy> interfaceFFScreeningScale
("FFScreeningScale",
"Set the screening scale",
&ShowerApproximation::theFFScreeningScale, GeV, 0.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,Energy> interfaceFIScreeningScale
("FIScreeningScale",
"Set the screening scale",
&ShowerApproximation::theFIScreeningScale, GeV, 0.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,Energy> interfaceIIScreeningScale
("IIScreeningScale",
"Set the screening scale",
&ShowerApproximation::theIIScreeningScale, GeV, 0.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Switch<ShowerApproximation,bool> interfaceRestrictPhasespace
("RestrictPhasespace",
"Switch on or off phasespace restrictions",
&ShowerApproximation::theRestrictPhasespace, true, false, false);
static SwitchOption interfaceRestrictPhasespaceYes
(interfaceRestrictPhasespace,
"Yes",
"Perform phasespace restrictions",
true);
static SwitchOption interfaceRestrictPhasespaceNo
(interfaceRestrictPhasespace,
"No",
"Do not perform phasespace restrictions",
false);
static Parameter<ShowerApproximation,double> interfaceHardScaleFactor
("HardScaleFactor",
"The hard scale factor.",
&ShowerApproximation::theHardScaleFactor, 1.0, 0.0, 0,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,double> interfaceRenormalizationScaleFactor
("RenormalizationScaleFactor",
"The hard scale factor.",
&ShowerApproximation::theRenormalizationScaleFactor, 1.0, 0.0, 0,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,double> interfaceFactorizationScaleFactor
("FactorizationScaleFactor",
"The hard scale factor.",
&ShowerApproximation::theFactorizationScaleFactor, 1.0, 0.0, 0,
false, false, Interface::lowerlim);
static Parameter<ShowerApproximation,double> interfaceExtrapolationX
("ExtrapolationX",
"The x from which on extrapolation should be performed.",
&ShowerApproximation::theExtrapolationX, 1.0, 0.0, 1.0,
false, false, Interface::limited);
static Switch<ShowerApproximation,int> interfaceRealEmissionScaleInSubtraction
("RealEmissionScaleInSubtraction",
"Set the scale choice for the real emission cross section in the matching subtraction.",
&ShowerApproximation::theRealEmissionScaleInSubtraction, showerScale, false, false);
static SwitchOption interfaceRealEmissionScaleInSubtractionRealScale
(interfaceRealEmissionScaleInSubtraction,
"RealScale",
"Use the real emission scale.",
realScale);
static SwitchOption interfaceRealEmissionScaleInSubtractionBornScale
(interfaceRealEmissionScaleInSubtraction,
"BornScale",
"Use the Born scale.",
bornScale);
static SwitchOption interfaceRealEmissionScaleInSubtractionShowerScale
(interfaceRealEmissionScaleInSubtraction,
"ShowerScale",
"Use the shower scale",
showerScale);
interfaceRealEmissionScaleInSubtraction.rank(-1);
static Switch<ShowerApproximation,int> interfaceBornScaleInSubtraction
("BornScaleInSubtraction",
"Set the scale choice for the Born cross section in the matching subtraction.",
&ShowerApproximation::theBornScaleInSubtraction, showerScale, false, false);
static SwitchOption interfaceBornScaleInSubtractionRealScale
(interfaceBornScaleInSubtraction,
"RealScale",
"Use the real emission scale.",
realScale);
static SwitchOption interfaceBornScaleInSubtractionBornScale
(interfaceBornScaleInSubtraction,
"BornScale",
"Use the Born scale.",
bornScale);
static SwitchOption interfaceBornScaleInSubtractionShowerScale
(interfaceBornScaleInSubtraction,
"ShowerScale",
"Use the shower scale",
showerScale);
interfaceBornScaleInSubtraction.rank(-1);
static Switch<ShowerApproximation,int> interfaceEmissionScaleInSubtraction
("EmissionScaleInSubtraction",
"Set the scale choice for the emission in the matching subtraction.",
&ShowerApproximation::theEmissionScaleInSubtraction, showerScale, false, false);
static SwitchOption interfaceEmissionScaleInSubtractionRealScale
(interfaceEmissionScaleInSubtraction,
"RealScale",
"Use the real emission scale.",
realScale);
static SwitchOption interfaceEmissionScaleInSubtractionEmissionScale
(interfaceEmissionScaleInSubtraction,
"BornScale",
"Use the Born scale.",
bornScale);
static SwitchOption interfaceEmissionScaleInSubtractionShowerScale
(interfaceEmissionScaleInSubtraction,
"ShowerScale",
"Use the shower scale",
showerScale);
interfaceEmissionScaleInSubtraction.rank(-1);
static Switch<ShowerApproximation,int> interfaceRealEmissionScaleInSplitting
("RealEmissionScaleInSplitting",
"Set the scale choice for the real emission cross section in the splitting.",
&ShowerApproximation::theRealEmissionScaleInSplitting, showerScale, false, false);
static SwitchOption interfaceRealEmissionScaleInSplittingRealScale
(interfaceRealEmissionScaleInSplitting,
"RealScale",
"Use the real emission scale.",
realScale);
static SwitchOption interfaceRealEmissionScaleInSplittingBornScale
(interfaceRealEmissionScaleInSplitting,
"BornScale",
"Use the Born scale.",
bornScale);
static SwitchOption interfaceRealEmissionScaleInSplittingShowerScale
(interfaceRealEmissionScaleInSplitting,
"ShowerScale",
"Use the shower scale",
showerScale);
interfaceRealEmissionScaleInSplitting.rank(-1);
static Switch<ShowerApproximation,int> interfaceBornScaleInSplitting
("BornScaleInSplitting",
"Set the scale choice for the Born cross section in the splitting.",
&ShowerApproximation::theBornScaleInSplitting, showerScale, false, false);
static SwitchOption interfaceBornScaleInSplittingRealScale
(interfaceBornScaleInSplitting,
"RealScale",
"Use the real emission scale.",
realScale);
static SwitchOption interfaceBornScaleInSplittingBornScale
(interfaceBornScaleInSplitting,
"BornScale",
"Use the Born scale.",
bornScale);
static SwitchOption interfaceBornScaleInSplittingShowerScale
(interfaceBornScaleInSplitting,
"ShowerScale",
"Use the shower scale",
showerScale);
interfaceBornScaleInSplitting.rank(-1);
static Switch<ShowerApproximation,int> interfaceEmissionScaleInSplitting
("EmissionScaleInSplitting",
"Set the scale choice for the emission in the splitting.",
&ShowerApproximation::theEmissionScaleInSplitting, showerScale, false, false);
static SwitchOption interfaceEmissionScaleInSplittingRealScale
(interfaceEmissionScaleInSplitting,
"RealScale",
"Use the real emission scale.",
realScale);
static SwitchOption interfaceEmissionScaleInSplittingEmissionScale
(interfaceEmissionScaleInSplitting,
"BornScale",
"Use the Born scale.",
bornScale);
static SwitchOption interfaceEmissionScaleInSplittingShowerScale
(interfaceEmissionScaleInSplitting,
"ShowerScale",
"Use the shower scale",
showerScale);
interfaceEmissionScaleInSplitting.rank(-1);
static Parameter<ShowerApproximation,Energy> interfaceRenormalizationScaleFreeze
("RenormalizationScaleFreeze",
"The freezing scale for the renormalization scale.",
&ShowerApproximation::theRenormalizationScaleFreeze, GeV, 1.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
interfaceRenormalizationScaleFreeze.rank(-1);
static Parameter<ShowerApproximation,Energy> interfaceFactorizationScaleFreeze
("FactorizationScaleFreeze",
"The freezing scale for the factorization scale.",
&ShowerApproximation::theFactorizationScaleFreeze, GeV, 1.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
interfaceFactorizationScaleFreeze.rank(-1);
static Reference<ShowerApproximation,HardScaleProfile> interfaceHardScaleProfile
("HardScaleProfile",
"The hard scale profile to use.",
&ShowerApproximation::theHardScaleProfile, false, false, true, true, false);
static Reference<ShowerApproximation,ColourBasis> interfaceLargeNBasis
("LargeNBasis",
"Set the large-N colour basis implementation.",
&ShowerApproximation::theLargeNBasis, false, false, true, true, false);
interfaceLargeNBasis.rank(-1);
static Switch<ShowerApproximation,bool> interfaceMaxPtIsMuF
("MaxPtIsMuF",
"",
&ShowerApproximation::maxPtIsMuF, false, false, false);
static SwitchOption interfaceMaxPtIsMuFYes
(interfaceMaxPtIsMuF,
"Yes",
"",
true);
static SwitchOption interfaceMaxPtIsMuFNo
(interfaceMaxPtIsMuF,
"No",
"",
false);
}
diff --git a/MatrixElement/Matchbox/Matching/ShowerApproximation.h b/MatrixElement/Matchbox/Matching/ShowerApproximation.h
--- a/MatrixElement/Matchbox/Matching/ShowerApproximation.h
+++ b/MatrixElement/Matchbox/Matching/ShowerApproximation.h
@@ -1,675 +1,691 @@
// -*- C++ -*-
//
// ShowerApproximation.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_ShowerApproximation_H
#define Herwig_ShowerApproximation_H
//
// This is the declaration of the ShowerApproximation class.
//
#include "ThePEG/Handlers/HandlerBase.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "Herwig/MatrixElement/Matchbox/Dipoles/SubtractionDipole.fh"
#include "Herwig/MatrixElement/Matchbox/Utility/ColourBasis.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/TildeKinematics.fh"
#include "Herwig/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.fh"
#include "HardScaleProfile.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup Matchbox
* \author Simon Platzer
*
* \brief ShowerApproximation describes the shower emission to be used
* in NLO matching.
*
*/
class ShowerApproximation: public HandlerBase {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
ShowerApproximation();
/**
* The destructor.
*/
virtual ~ShowerApproximation();
//@}
public:
/**
* Return true, if this shower approximation will require a
* splitting generator
*/
virtual bool needsSplittingGenerator() const { return false; }
/**
* Return true, if this shower approximation will require
* H events
*/
virtual bool hasHEvents() const { return true; }
/**
* Return true, if this shower approximation will require tilde
* XCombs for the real phase space point generated
*/
virtual bool needsTildeXCombs() const { return false; }
/**
* Return true, if this shower approximation will require
* a truncated parton shower
*/
virtual bool needsTruncatedShower() const { return false; }
/**
* Return the tilde kinematics object returning the shower
* kinematics parametrization if different from the nominal dipole
* mappings.
*/
virtual Ptr<TildeKinematics>::tptr showerTildeKinematics() const;
/**
* Return the tilde kinematics object returning the shower
* kinematics parametrization if different from the nominal dipole
* mappings.
*/
virtual Ptr<InvertedTildeKinematics>::tptr showerInvertedTildeKinematics() const;
public:
/**
* Set the XComb object describing the Born process
*/
void setBornXComb(tStdXCombPtr xc) { theBornXComb = xc; }
/**
* Return the XComb object describing the Born process
*/
tStdXCombPtr bornXComb() const { return theBornXComb; }
/**
* Return the XComb object describing the Born process
*/
tcStdXCombPtr bornCXComb() const { return theBornXComb; }
/**
* Set the XComb object describing the real emission process
*/
void setRealXComb(tStdXCombPtr xc) { theRealXComb = xc; }
/**
* Return the XComb object describing the real emission process
*/
tStdXCombPtr realXComb() const { return theRealXComb; }
/**
* Return the XComb object describing the real emission process
*/
tcStdXCombPtr realCXComb() const { return theRealXComb; }
/**
* Set the tilde xcomb objects associated to the real xcomb
*/
void setTildeXCombs(const vector<StdXCombPtr>& xc) { theTildeXCombs = xc; }
/**
* Return the tilde xcomb objects associated to the real xcomb
*/
const vector<StdXCombPtr>& tildeXCombs() const { return theTildeXCombs; }
/**
* Set the dipole in charge for the emission
*/
void setDipole(Ptr<SubtractionDipole>::tptr);
/**
* Return the dipole in charge for the emission
*/
Ptr<SubtractionDipole>::tptr dipole() const;
/**
* Return true, if this matching is capable of spin correlations.
*/
virtual bool hasSpinCorrelations() const { return false; }
public:
/**
* Return true if one of the recently encountered configutations was
* below the infrared cutoff.
*/
bool belowCutoff() const { return theBelowCutoff; }
/**
* Indicate that one of the recently encountered configutations was
* below the infrared cutoff.
*/
void wasBelowCutoff() { theBelowCutoff = true; }
/**
* Reset the below cutoff flag.
*/
void resetBelowCutoff() { theBelowCutoff = false; }
/**
* Return the pt cut to be applied for final-final dipoles.
*/
Energy ffPtCut() const { return theFFPtCut; }
/**
* Return the pt cut to be applied for final-initial dipoles.
*/
Energy fiPtCut() const { return theFIPtCut; }
/**
* Return the pt cut to be applied for initial-initial dipoles.
*/
Energy iiPtCut() const { return theIIPtCut; }
/**
* Return the pt cut to be applied for initial-initial dipoles.
*/
Energy safeCut() const { return theSafeCut;}
/**
* Return the screening scale to be applied for final-final dipoles.
*/
Energy ffScreeningScale() const { return theFFScreeningScale; }
/**
* Return the screening scale to be applied for final-initial dipoles.
*/
Energy fiScreeningScale() const { return theFIScreeningScale; }
/**
* Return the screening scale to be applied for initial-initial dipoles.
*/
Energy iiScreeningScale() const { return theIIScreeningScale; }
/**
* Return the shower renormalization scale
*/
virtual Energy2 showerEmissionScale() const;
/**
* Return the shower renormalization scale
*/
Energy2 showerRenormalizationScale() const {
return sqr(renormalizationScaleFactor())*showerEmissionScale();
}
/**
* Return the shower factorization scale
*/
Energy2 showerFactorizationScale() const {
return sqr(factorizationScaleFactor())*showerEmissionScale();
}
/**
* Return the Born renormalization scale
*/
Energy2 bornRenormalizationScale() const;
/**
* Return the Born factorization scale
*/
Energy2 bornFactorizationScale() const;
/**
* Return the real emission renormalization scale
*/
Energy2 realRenormalizationScale() const;
/**
* Return the real emission factorization scale
*/
Energy2 realFactorizationScale() const;
/**
* Enumerate possible scale choices
*/
enum ScaleChoices {
bornScale = 0,
/** Use the born scales */
realScale = 1,
/** Use the real scales */
showerScale = 2
/** Use the shower scales */
};
/**
* Return the scale choice in the real emission cross section to be
* used in the matching subtraction.
*/
int realEmissionScaleInSubtraction() const { return theRealEmissionScaleInSubtraction; }
/**
* Return the scale choice in the born cross section to be
* used in the matching subtraction.
*/
int bornScaleInSubtraction() const { return theBornScaleInSubtraction; }
/**
* Return the scale choice in the emission contribution to be
* used in the matching subtraction.
*/
int emissionScaleInSubtraction() const { return theEmissionScaleInSubtraction; }
/**
* Return the scale choice in the real emission cross section to be
* used in the splitting.
*/
int realEmissionScaleInSplitting() const { return theRealEmissionScaleInSplitting; }
/**
* Return the scale choice in the born cross section to be
* used in the splitting.
*/
int bornScaleInSplitting() const { return theBornScaleInSplitting; }
/**
* Return the scale choice in the emission contribution to be
* used in the splitting.
*/
int emissionScaleInSplitting() const { return theEmissionScaleInSplitting; }
/**
* Return the scale weight
*/
double scaleWeight(int rScale, int bScale, int eScale) const;
/**
* Return the scale weight for the matching subtraction
*/
double subtractionScaleWeight() const {
return scaleWeight(realEmissionScaleInSubtraction(),
bornScaleInSubtraction(),
emissionScaleInSubtraction());
}
/**
* Return the scale weight for the splitting
*/
double splittingScaleWeight() const {
return scaleWeight(realEmissionScaleInSplitting(),
bornScaleInSplitting(),
emissionScaleInSplitting());
}
public:
/**
* Return true, if the phase space restrictions of the dipole shower should
* be applied.
*/
bool restrictPhasespace() const { return theRestrictPhasespace; }
/**
* Indicate that the phase space restrictions of the dipole shower should
* be applied.
*/
void restrictPhasespace(bool yes) { theRestrictPhasespace = yes; }
/**
* Return profile scales
*/
Ptr<HardScaleProfile>::tptr profileScales() const { return theHardScaleProfile; }
/**
* Set profile scales
*/
void profileScales(Ptr<HardScaleProfile>::ptr prof) { theHardScaleProfile = prof; }
/**
* Return true if maximum pt should be deduced from the factorization scale
*/
bool hardScaleIsMuF() const { return maxPtIsMuF; }
/**
* Indicate that maximum pt should be deduced from the factorization scale
*/
void hardScaleIsMuF(bool yes) { maxPtIsMuF = yes; }
/**
* Return the scale factor for the hard scale
*/
double hardScaleFactor() const { return theHardScaleFactor; }
/**
* Set the scale factor for the hard scale
*/
void hardScaleFactor(double f) { theHardScaleFactor = f; }
/**
* Get the factorization scale factor
*/
double factorizationScaleFactor() const { return theFactorizationScaleFactor; }
/**
* Get the renormalization scale factor
*/
double renormalizationScaleFactor() const { return theRenormalizationScaleFactor; }
/**
* Set the factorization scale factor
*/
void factorizationScaleFactor(double f) { theFactorizationScaleFactor = f; }
/**
* Set the renormalization scale factor
*/
void renormalizationScaleFactor(double f) { theRenormalizationScaleFactor = f; }
/**
* Determine if the configuration is below or above the cutoff.
*/
virtual void checkCutoff();
/**
* Determine all kinematic variables which are not provided by the
* dipole kinematics; store all shower variables in the respective
* dipole object for later use.
*/
virtual void getShowerVariables();
/**
* Return the shower approximation to the real emission cross
* section for the given pair of Born and real emission
* configurations.
*/
virtual CrossSection dSigHatDR() const = 0;
/**
* Return the shower approximation splitting kernel for the given
* pair of Born and real emission configurations in units of the
* Born center of mass energy squared, and including a weight to
* project onto the splitting given by the dipole used.
*/
virtual double me2() const = 0;
/**
* Return the Born PDF weight
*/
double bornPDFWeight(Energy2 muF) const;
/**
* Return the real emission PDF weight
*/
double realPDFWeight(Energy2 muF) const;
protected:
/**
* Return true, if the shower was able to generate an emission
* leading from the given Born to the given real emission process.
*/
virtual bool isInShowerPhasespace() const;
/**
* Return true, if the shower emission leading from the given Born
* to the given real emission process would have been generated
* above the shower's infrared cutoff.
*/
virtual bool isAboveCutoff() const;
/**
* Return the relevant hard scale
*/
virtual Energy hardScale() const;
+ /**
+ * Use the maximum available phase space for the momentum fraction
+ */
+ void useOpenZ(bool yes) { theOpenZ = yes; }
+
+ /**
+ * Return true if the maximum available phase space should be used
+ * for the momentum fraction
+ */
+ bool openZ() const { return theOpenZ; }
+
public:
/**
* Generate a weight for the given dipole channel
*/
virtual double channelWeight(int emitter, int emission,
int spectator, int bemitter) const;
/**
* Generate a normalized weight taking into account all channels
*/
virtual double channelWeight() 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 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();
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
public:
/**
* A large-N colour basis to be used when reproducing the shower
* kernels.
*/
Ptr<ColourBasis>::tptr largeNBasis() const { return theLargeNBasis; }
protected:
/**
* A large-N colour basis to be used when reproducing the shower
* kernels.
*/
Ptr<ColourBasis>::ptr theLargeNBasis;
/**
* Set the large-N basis
*/
void setLargeNBasis();
/**
* The x value from which on we extrapolate PDFs for numerically stable ratios.
*/
double theExtrapolationX;
private:
/**
* The XComb object describing the Born process
*/
tStdXCombPtr theBornXComb;
/**
* The XComb object describing the real emission process
*/
tStdXCombPtr theRealXComb;
/**
* The tilde xcomb objects associated to the real xcomb
*/
vector<StdXCombPtr> theTildeXCombs;
/**
* The dipole in charge for the emission
*/
Ptr<SubtractionDipole>::tptr theDipole;
/**
* True if one of the recently encountered configutations was below
* the infrared cutoff.
*/
bool theBelowCutoff;
/**
* The pt cut to be applied for final-final dipoles.
*/
Energy theFFPtCut;
/**
* An optional screening scale for final-final dipoles; see
* DipoleSplittingKernel
*/
Energy theFFScreeningScale;
/**
* The pt cut to be applied for final-initial dipoles.
*/
Energy theFIPtCut;
/**
* An optional screening scale for final-initial dipoles; see
* DipoleSplittingKernel
*/
Energy theFIScreeningScale;
/**
* The pt cut to be applied for initial-initial dipoles.
*/
Energy theIIPtCut;
/**
* An optional screening scale for initial-initial dipoles; see
* DipoleSplittingKernel
*/
Energy theIIScreeningScale;
/**
* The cut to be applied as an enhanced shower cutoff.
*/
Energy theSafeCut;
/**
* True, if the phase space restrictions of the dipole shower should
* be applied.
*/
bool theRestrictPhasespace;
/**
* The scale factor for the hard scale
*/
double theHardScaleFactor;
/**
* The scale factor for the renormalization scale
*/
double theRenormalizationScaleFactor;
/**
* The scale factor for the factorization scale
*/
double theFactorizationScaleFactor;
/**
* The scale choice in the real emission cross section to be
* used in the matching subtraction.
*/
int theRealEmissionScaleInSubtraction;
/**
* The scale choice in the born cross section to be
* used in the matching subtraction.
*/
int theBornScaleInSubtraction;
/**
* The scale choice in the emission contribution to be
* used in the matching subtraction.
*/
int theEmissionScaleInSubtraction;
/**
* The scale choice in the real emission cross section to be
* used in the splitting.
*/
int theRealEmissionScaleInSplitting;
/**
* The scale choice in the born cross section to be
* used in the splitting.
*/
int theBornScaleInSplitting;
/**
* The scale choice in the emission contribution to be
* used in the splitting.
*/
int theEmissionScaleInSplitting;
/**
* A freezing value for the renormalization scale
*/
Energy theRenormalizationScaleFreeze;
/**
* A freezing value for the factorization scale
*/
Energy theFactorizationScaleFreeze;
/**
* True if maximum pt should be deduced from the factorization scale
*/
bool maxPtIsMuF;
/**
* The profile scales
*/
Ptr<HardScaleProfile>::ptr theHardScaleProfile;
+ /**
+ * Use the maximum available phase space for the momentum fraction
+ */
+ bool theOpenZ;
+
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
ShowerApproximation & operator=(const ShowerApproximation &);
};
}
#endif /* Herwig_ShowerApproximation_H */
diff --git a/MatrixElement/Matchbox/Scales/Makefile.am b/MatrixElement/Matchbox/Scales/Makefile.am
--- a/MatrixElement/Matchbox/Scales/Makefile.am
+++ b/MatrixElement/Matchbox/Scales/Makefile.am
@@ -1,32 +1,32 @@
pkglib_LTLIBRARIES = HwMatchboxScales.la
-HwMatchboxScales_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 4:0:0
+HwMatchboxScales_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 4:1:0
HwMatchboxScales_la_SOURCES = \
MatchboxHtScale.h \
MatchboxLeptonMassScale.h \
MatchboxLeptonPtScale.h \
MatchboxParticlePtScale.h \
MatchboxPtScale.h \
MatchboxHtScale.cc \
MatchboxLeptonMassScale.cc \
MatchboxLeptonPtScale.cc \
MatchboxParticlePtScale.cc \
MatchboxPtScale.cc \
MatchboxSHatScale.h \
MatchboxSHatScale.cc \
MatchboxTopMassScale.h \
MatchboxTopMassScale.cc \
MatchboxTopMTScale.h \
MatchboxTopMTScale.cc \
MatchboxTopSumMTScale.h \
MatchboxTopSumMTScale.cc \
MatchboxTopMinMTScale.h \
MatchboxTopMinMTScale.cc \
MatchboxTriVecScales.h \
MatchboxTriVecScales.cc \
MatchboxTopLinearSumMTScale.h \
MatchboxTopLinearSumMTScale.cc \
MatchboxTopIndividualMTScale.h \
MatchboxTopIndividualMTScale.cc
diff --git a/MatrixElement/Matchbox/Scales/MatchboxHtScale.cc b/MatrixElement/Matchbox/Scales/MatchboxHtScale.cc
--- a/MatrixElement/Matchbox/Scales/MatchboxHtScale.cc
+++ b/MatrixElement/Matchbox/Scales/MatchboxHtScale.cc
@@ -1,164 +1,164 @@
// -*- C++ -*-
//
// MatchboxHtScale.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MatchboxHtScale class.
//
#include "MatchboxHtScale.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.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"
using namespace Herwig;
MatchboxHtScale::MatchboxHtScale()
: theIncludeMT(false), theHTFactor(1.0),
theMTFactor(1.0),theScalePtCut(15.*GeV) {}
MatchboxHtScale::~MatchboxHtScale() {}
IBPtr MatchboxHtScale::clone() const {
return new_ptr(*this);
}
IBPtr MatchboxHtScale::fullclone() const {
return new_ptr(*this);
}
Energy2 MatchboxHtScale::renormalizationScale() const {
tcPDVector pd (mePartonData().begin() + 2, mePartonData().end());
vector<LorentzMomentum> p (meMomenta().begin() + 2, meMomenta().end());
tcPDPtr t1 = mePartonData()[0];
tcPDPtr t2 = mePartonData()[1];
tcCutsPtr cuts = lastCutsPtr();
theJetFinder->cluster(pd, p, cuts, t1, t2);
initWeightFactors(pd,p,theJetFinder);
// momentum of the non-jet system
LorentzMomentum nonJetMomentum(ZERO,ZERO,ZERO,ZERO);
// (weighted) pt of the jet systems
Energy ptJetSum = ZERO;
bool gotone = false;
tcPDVector::const_iterator pdata = pd.begin();
vector<LorentzMomentum>::const_iterator mom = p.begin();
for ( ; mom != p.end(); ++pdata, ++mom ) {
- if ( theJetFinder->unresolvedMatcher()->check(**pdata)&&
- mom->perp()>theScalePtCut){
- //abs(mom->rapidity()+(!lastXCombPtr()->head()?lastXCombPtr()->lastY():lastXCombPtr()->head()->lastY()))<5.01
- gotone = true;
- ptJetSum += jetPtWeight(*mom)*mom->perp();
+ if ( theJetFinder->unresolvedMatcher()->check(**pdata) ){
+ if( mom->perp() > theScalePtCut ){
+ gotone = true;
+ ptJetSum += jetPtWeight(*mom)*mom->perp();
+ }
} else if ( theIncludeMT ) {
nonJetMomentum += *mom;
}
}
if ( !gotone && lastXCombPtr()->willPassCuts() )
throw Exception() << "MatchboxHtScale::renormalizationScale(): "
<< "No jets could be found. Check your setup."
<< "\nHint: The HT scale is defined with a PtMin cut on jets. (default:) "
<< "\n set /Herwig/MatrixElements/Matchbox/ScalesHTScale:JetPtCut 15.*GeV "
<< Exception::runerror;
Energy mtNonJetSum =
sqrt(nonJetMomentum.perp2() + nonJetMomentum.m2());
mtNonJetSum *= theMTFactor;
ptJetSum *= theHTFactor;
return sqr(ptJetSum + mtNonJetSum);
}
Energy2 MatchboxHtScale::factorizationScale() const {
return renormalizationScale();
}
// If needed, insert default implementations of virtual function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void MatchboxHtScale::persistentOutput(PersistentOStream & os) const {
os << theJetFinder << theIncludeMT << theHTFactor << theMTFactor << ounit(theScalePtCut,GeV);
}
void MatchboxHtScale::persistentInput(PersistentIStream & is, int) {
is >> theJetFinder >> theIncludeMT >> theHTFactor >> theMTFactor >> iunit(theScalePtCut,GeV);
}
// *** Attention *** The following static variable is needed for the type
// description system in ThePEG. Please check that the template arguments
// are correct (the class and its base class), and that the constructor
// arguments are correct (the class name and the name of the dynamically
// loadable library where the class implementation can be found).
DescribeClass<MatchboxHtScale,MatchboxScaleChoice>
describeHerwigMatchboxHtScale("Herwig::MatchboxHtScale", "HwMatchboxScales.so");
void MatchboxHtScale::Init() {
static ClassDocumentation<MatchboxHtScale> documentation
("MatchboxHtScale implements scale choices related to transverse momenta.");
static Reference<MatchboxHtScale,JetFinder> interfaceJetFinder
("JetFinder",
"A reference to the jet finder.",
&MatchboxHtScale::theJetFinder, false, false, true, false, false);
static Switch<MatchboxHtScale,bool> interfaceIncludeMT
("IncludeMT",
"Include the transverse masses of the non-jet objects.",
&MatchboxHtScale::theIncludeMT, false, false, false);
static SwitchOption interfaceIncludeMTYes
(interfaceIncludeMT,
"Yes",
"",
true);
static SwitchOption interfaceIncludeMTNo
(interfaceIncludeMT,
"No",
"",
false);
static Parameter<MatchboxHtScale,double> interfaceHTFactor
("HTFactor",
"A factor to scale the HT contribution.",
&MatchboxHtScale::theHTFactor, 1.0, 0.0, 0,
false, false, Interface::lowerlim);
static Parameter<MatchboxHtScale,double> interfaceMTFactor
("MTFactor",
"A factor to scale the MT contribution.",
&MatchboxHtScale::theMTFactor, 1.0, 0.0, 0,
false, false, Interface::lowerlim);
static Parameter<MatchboxHtScale,Energy> interfaceScalePtCut
("JetPtCut",
"The Pt cut to define jets in the sum.",
&MatchboxHtScale::theScalePtCut, GeV, 15.*GeV, 0.*GeV, 0.*GeV,
false, false, Interface::lowerlim);
}
diff --git a/Models/ADD/ADDModelFFGGRVertex.cc b/Models/ADD/ADDModelFFGGRVertex.cc
--- a/Models/ADD/ADDModelFFGGRVertex.cc
+++ b/Models/ADD/ADDModelFFGGRVertex.cc
@@ -1,91 +1,92 @@
// -*- C++ -*-
//
// ADDModelFFGGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ADDModelFFGGRVertex class.
//
#include "ADDModelFFGGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
ADDModelFFGGRVertex::ADDModelFFGGRVertex()
: couplast_(0.), q2last_(ZERO), kappa_(ZERO), r_(ZERO) {
orderInGem(1);
orderInGs (1);
+ colourStructure(ColourStructure::SU3TFUND);
}
void ADDModelFFGGRVertex::doinit() {
for(int ix=1;ix<7;++ix) {
addToList(-ix,ix,21,39);
}
FFVTVertex::doinit();
tcHwADDPtr hwADD=dynamic_ptr_cast<tcHwADDPtr>(generator()->standardModel());
if(!hwADD) throw Exception()
<< "Must have ADDModel in ADDModelFFGGRVertex::doinit()"
<< Exception::runerror;
kappa_ = 2./hwADD->MPlanckBar();
r_ = sqr(hwADD->LambdaT())/hwADD->MPlanckBar();
}
void ADDModelFFGGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV) << ounit(r_,GeV);
}
void ADDModelFFGGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV) >> iunit(r_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ADDModelFFGGRVertex,FFVTVertex>
describeHerwigADDModelFFGGRVertex("Herwig::ADDModelFFGGRVertex", "HwADDModel.so");
void ADDModelFFGGRVertex::Init() {
static ClassDocumentation<ADDModelFFGGRVertex> documentation
("The ADDModelFFGGRVertexxs class is the implementation"
" of the two fermion vector coupling for the ADD model.");
}
#ifndef NDEBUG
void ADDModelFFGGRVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr,
tcPDPtr cc, tcPDPtr) {
#else
void ADDModelFFGGRVertex::setCoupling(Energy2 q2,tcPDPtr,tcPDPtr,
tcPDPtr, tcPDPtr) {
#endif
// work out the particles
assert(cc->id()==ParticleID::g && abs(aa->id()) <= 6);
Complex coup;
// overall factor
if(q2last_!=q2||couplast_==0.) {
couplast_ = strongCoupling(q2);
q2last_=q2;
}
left (1.);
right(1.);
// set the coupling
norm(UnitRemoval::E * kappa_ * couplast_);
}
Complex ADDModelFFGGRVertex::propagator(int iopt, Energy2 q2,tcPDPtr part,
Energy mass, Energy width) {
if(part->id()!=ParticleID::Graviton)
return VertexBase::propagator(iopt,q2,part,mass,width);
else
return Complex(4.*Constants::pi*UnitRemoval::E2/sqr(r_));
}
diff --git a/Models/ADD/ADDModelFFGRVertex.cc b/Models/ADD/ADDModelFFGRVertex.cc
--- a/Models/ADD/ADDModelFFGRVertex.cc
+++ b/Models/ADD/ADDModelFFGRVertex.cc
@@ -1,73 +1,74 @@
// -*- C++ -*-
//
// ADDModelFFGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ADDModelFFGRVertex class.
//
#include "ADDModelFFGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
void ADDModelFFGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV) << ounit(r_,GeV);
}
void ADDModelFFGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV) >> iunit(r_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ADDModelFFGRVertex,FFTVertex>
describeHerwigADDModelFFGRVertex("Herwig::ADDModelFFGRVertex", "HwADDModel.so");
void ADDModelFFGRVertex::Init() {
static ClassDocumentation<ADDModelFFGRVertex> documentation
("The ADDModelFFGRVertex class is the ADDModel calculation"
" of the fermion-antifermion-graviton vertex");
}
void ADDModelFFGRVertex::setCoupling(Energy2,tcPDPtr,tcPDPtr, tcPDPtr) {
norm(Complex(kappa_ * UnitRemoval::E));
}
ADDModelFFGRVertex::ADDModelFFGRVertex() : kappa_(ZERO), r_(ZERO) {
orderInGem(1);
orderInGs (0);
+ colourStructure(ColourStructure::DELTA);
}
void ADDModelFFGRVertex::doinit() {
// PDG codes for the particles
// the quarks
for (int ix=1;ix<7;++ix) addToList(-ix,ix,39);
// the leptons
for (int ix=11;ix<17;++ix) addToList(-ix,ix,39);
FFTVertex::doinit();
tcHwADDPtr hwADD=dynamic_ptr_cast<tcHwADDPtr>(generator()->standardModel());
if(!hwADD)
throw Exception() << "Must have ADDModel in ADDModelFFGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwADD->MPlanckBar();
r_ = sqr(hwADD->LambdaT())/hwADD->MPlanckBar();
}
Complex ADDModelFFGRVertex::propagator(int iopt, Energy2 q2,tcPDPtr part,
Energy mass, Energy width) {
if(part->id()!=ParticleID::Graviton)
return VertexBase::propagator(iopt,q2,part,mass,width);
else
return Complex(4.*Constants::pi*UnitRemoval::E2/sqr(r_));
}
diff --git a/Models/ADD/ADDModelFFWGRVertex.cc b/Models/ADD/ADDModelFFWGRVertex.cc
--- a/Models/ADD/ADDModelFFWGRVertex.cc
+++ b/Models/ADD/ADDModelFFWGRVertex.cc
@@ -1,198 +1,199 @@
// -*- C++ -*-
//
// ADDModelFFWGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ADDModelFFWGRVertex class.
//
#include "ADDModelFFWGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
using namespace Herwig;
using namespace ThePEG;
ADDModelFFWGRVertex::ADDModelFFWGRVertex()
: charge_(17,0.), gl_(17,0.), gr_(17,0.),
ckm_(3,vector<Complex>(3,0.0)), couplast_(0.),
q2last_(ZERO), kappa_(ZERO), r_(ZERO) {
orderInGem(2);
orderInGs (0);
+ colourStructure(ColourStructure::DELTA);
}
void ADDModelFFWGRVertex::doinit() {
for(int ix=1;ix<7;++ix) {
addToList(-ix,ix,22,39);
addToList(-ix,ix,23,39);
}
for(int ix=11;ix<17;++ix) {
addToList(-ix,ix,22,39);
addToList(-ix,ix,23,39);
}
// particles for outgoing W-
// quarks
for(int ix=1;ix<6;ix+=2) {
for(int iy=2;iy<7;iy+=2) {
addToList(-ix, iy, -24,39);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix, ix+1, -24,39);
}
// particles for outgoing W+
// quarks
for(int ix=2;ix<7;ix+=2) {
for(int iy=1;iy<6;iy+=2) {
addToList(-ix, iy, 24,39);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix-1, ix, 24,39);
}
FFVTVertex::doinit();
tcHwADDPtr hwADD=dynamic_ptr_cast<tcHwADDPtr>(generator()->standardModel());
if(!hwADD) throw Exception()
<< "Must have ADDModel in ADDModelFFWGRVertex::doinit()"
<< Exception::runerror;
double sw2 = sin2ThetaW();
double fact = 0.25/sqrt(sw2*(1.-sw2));
for(int ix=1;ix<4;++ix) {
charge_[2*ix-1] = hwADD->ed();
charge_[2*ix ] = hwADD->eu();
charge_[2*ix+9 ] = hwADD->ee();
charge_[2*ix+10] = hwADD->enu();
gl_[2*ix-1] = fact*(hwADD->vd() + hwADD->ad() );
gl_[2*ix ] = fact*(hwADD->vu() + hwADD->au() );
gl_[2*ix+9 ] = fact*(hwADD->ve() + hwADD->ae() );
gl_[2*ix+10] = fact*(hwADD->vnu() + hwADD->anu());
gr_[2*ix-1] = fact*(hwADD->vd() - hwADD->ad() );
gr_[2*ix ] = fact*(hwADD->vu() - hwADD->au() );
gr_[2*ix+9 ] = fact*(hwADD->ve() - hwADD->ae() );
gr_[2*ix+10] = fact*(hwADD->vnu() - hwADD->anu());
}
kappa_=2./hwADD->MPlanckBar();
r_ = sqr(hwADD->LambdaT())/hwADD->MPlanckBar();
Ptr<CKMBase>::transient_pointer CKM = generator()->standardModel()->CKM();
// cast the CKM object to the HERWIG one
ThePEG::Ptr<Herwig::StandardCKM>::transient_const_pointer
hwCKM = ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardCKM>::
transient_const_pointer>(CKM);
if(hwCKM) {
vector< vector<Complex > > CKM;
CKM = hwCKM->getUnsquaredMatrix(generator()->standardModel()->families());
for(unsigned int ix=0;ix<3;++ix) {
for(unsigned int iy=0;iy<3;++iy) {
ckm_[ix][iy]=CKM[ix][iy];
}
}
}
else {
throw Exception() << "Must have access to the Herwig::StandardCKM object"
<< "for the CKM matrix in SMFFWVertex::doinit()"
<< Exception::runerror;
}
}
void ADDModelFFWGRVertex::persistentOutput(PersistentOStream & os) const {
os << charge_ << gl_ << gr_ << ounit(kappa_,InvGeV) << ckm_ << ounit(r_,GeV);
}
void ADDModelFFWGRVertex::persistentInput(PersistentIStream & is, int) {
is >> charge_ >> gl_ >> gr_ >> iunit(kappa_,InvGeV) >> ckm_ >> iunit(r_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ADDModelFFWGRVertex,FFVTVertex>
describeHerwigADDModelFFWGRVertex("Herwig::ADDModelFFWGRVertex", "HwADDModel.so");
void ADDModelFFWGRVertex::Init() {
static ClassDocumentation<ADDModelFFWGRVertex> documentation
("The ADDModelFFWGRVertexxs class is the implementation"
" of the two fermion vector coupling for the ADD model.");
}
void ADDModelFFWGRVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr bb,
tcPDPtr cc, tcPDPtr) {
// work out the particles
int iferm= abs(aa->id());
int ibos = abs(cc->id());
Complex coup;
// overall factor
assert( ibos >= 22 && ibos <= 24 );
if( q2last_ != q2 || couplast_ == 0. ) {
couplast_ = electroMagneticCoupling(q2);
q2last_ = q2;
}
// photon
if(ibos==22) {
// alpha
coup = UnitRemoval::E * kappa_ * couplast_;
// _charge of particle
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16));
coup *= charge_[iferm];
left (1.);
right(1.);
}
// Z boson
else if(ibos==23) {
coup = UnitRemoval::E * kappa_ * couplast_;
// _charge of particle
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16));
left (gl_[iferm]);
right(gr_[iferm]);
}
else if(ibos==24) {
coup = UnitRemoval::E * kappa_ * couplast_ *
sqrt(0.5) / sqrt(sin2ThetaW());
// the left and right couplings
int iferm=abs(aa->id());
int ianti=abs(bb->id());
// quarks
if(iferm>=1 && iferm <=6) {
int iu,id;
// up type first
if(iferm%2==0) {
iu = iferm/2;
id = (ianti+1)/2;
}
// down type first
else {
iu = ianti/2;
id = (iferm+1)/2;
}
assert( iu>=1 && iu<=3 && id>=1 && id<=3);
left(ckm_[iu-1][id-1]);
right(0.);
}
// leptons
else if(iferm>=11 && iferm <=16) {
left(1.);
right(0.);
}
else
assert(false);
}
// set the coupling
norm(coup);
}
Complex ADDModelFFWGRVertex::propagator(int iopt, Energy2 q2,tcPDPtr part,
Energy mass, Energy width) {
if(part->id()!=ParticleID::Graviton)
return VertexBase::propagator(iopt,q2,part,mass,width);
else
return Complex(4.*Constants::pi*UnitRemoval::E2/sqr(r_));
}
diff --git a/Models/ADD/ADDModelGGGGRVertex.cc b/Models/ADD/ADDModelGGGGRVertex.cc
--- a/Models/ADD/ADDModelGGGGRVertex.cc
+++ b/Models/ADD/ADDModelGGGGRVertex.cc
@@ -1,84 +1,85 @@
// -*- C++ -*-
//
// ADDModelGGGGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ADDModelGGGGRVertex class.
//
#include "ADDModelGGGGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
ADDModelGGGGRVertex::ADDModelGGGGRVertex()
: kappa_(ZERO), r_(ZERO), couplast_(0.), q2last_(ZERO) {
orderInGem(1);
orderInGs (1);
+ colourStructure(ColourStructure::SU3F);
}
void ADDModelGGGGRVertex::doinit() {
addToList(21, 21, 21, 39);
VVVTVertex::doinit();
// set the graviton coupling
tcHwADDPtr hwADD=dynamic_ptr_cast<tcHwADDPtr>(generator()->standardModel());
if(!hwADD)
throw Exception()
<< "Must have ADDModel in ADDModelGGGGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwADD->MPlanckBar();
r_ = sqr(hwADD->LambdaT())/hwADD->MPlanckBar();
}
void ADDModelGGGGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV) << ounit(r_,GeV);
}
void ADDModelGGGGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV) >> iunit(r_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ADDModelGGGGRVertex,VVVTVertex>
describeHerwigADDModelGGGGRVertex("Herwig::ADDModelGGGGRVertex", "HwADDModel.so");
void ADDModelGGGGRVertex::Init() {
static ClassDocumentation<ADDModelGGGGRVertex> documentation
("The ADDModelGGGGRVertex class is the four point coupling"
" of three vector bosons and a graviton in the Randell-Sundrum model.");
}
#ifndef NDEBUG
void ADDModelGGGGRVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,
tcPDPtr c, tcPDPtr) {
#else
void ADDModelGGGGRVertex::setCoupling(Energy2 q2,tcPDPtr,tcPDPtr,
tcPDPtr, tcPDPtr) {
#endif
assert(a->id() == ParticleID::g && b->id() == ParticleID::g &&
c->id() == ParticleID::g);
if(q2!=q2last_||couplast_==0.) {
couplast_ = strongCoupling(q2);
q2last_=q2;
}
norm(Complex(couplast_*kappa_*UnitRemoval::E));
}
Complex ADDModelGGGGRVertex::propagator(int iopt, Energy2 q2,tcPDPtr part,
Energy mass, Energy width) {
if(part->id()!=ParticleID::Graviton)
return VertexBase::propagator(iopt,q2,part,mass,width);
else
return Complex(4.*Constants::pi*UnitRemoval::E2/sqr(r_));
}
diff --git a/Models/ADD/ADDModelSSGRVertex.cc b/Models/ADD/ADDModelSSGRVertex.cc
--- a/Models/ADD/ADDModelSSGRVertex.cc
+++ b/Models/ADD/ADDModelSSGRVertex.cc
@@ -1,69 +1,70 @@
// -*- C++ -*-
//
// ADDModelSSGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ADDModelSSGRVertex class.
//
#include "ADDModelSSGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
ADDModelSSGRVertex::ADDModelSSGRVertex() : kappa_(ZERO), r_(ZERO) {
orderInGem(1);
orderInGs (0);
+ colourStructure(ColourStructure::SINGLET);
}
void ADDModelSSGRVertex::doinit() {
addToList(25,25,39);
SSTVertex::doinit();
tcHwADDPtr hwADD=dynamic_ptr_cast<tcHwADDPtr>(generator()->standardModel());
if(!hwADD)
throw Exception() << "Must have ADDModel in ADDModelSSGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwADD->MPlanckBar();
r_ = sqr(hwADD->LambdaT())/hwADD->MPlanckBar();
}
void ADDModelSSGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV) << ounit(r_,GeV);
}
void ADDModelSSGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV) >> iunit(r_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ADDModelSSGRVertex,SSTVertex>
describeHerwigADDModelSSGRVertex("Herwig::ADDModelSSGRVertex", "HwADDModel.so");
void ADDModelSSGRVertex::Init() {
static ClassDocumentation<ADDModelSSGRVertex> documentation
("The ADDModelSSGRVertex class is the implementation of"
" the ADDModel scalar-scalar-graviton vertex");
}
void ADDModelSSGRVertex::setCoupling(Energy2,tcPDPtr,tcPDPtr, tcPDPtr) {
norm(Complex(kappa_ * UnitRemoval::E));
}
Complex ADDModelSSGRVertex::propagator(int iopt, Energy2 q2,tcPDPtr part,
Energy mass, Energy width) {
if(part->id()!=ParticleID::Graviton)
return VertexBase::propagator(iopt,q2,part,mass,width);
else
return Complex(4.*Constants::pi*UnitRemoval::E2/sqr(r_));
}
diff --git a/Models/ADD/ADDModelVVGRVertex.cc b/Models/ADD/ADDModelVVGRVertex.cc
--- a/Models/ADD/ADDModelVVGRVertex.cc
+++ b/Models/ADD/ADDModelVVGRVertex.cc
@@ -1,72 +1,73 @@
// -*- C++ -*-
//
// ADDModelVVGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ADDModelVVGRVertex class.
//
#include "ADDModelVVGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
void ADDModelVVGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV) << ounit(r_,GeV);
}
void ADDModelVVGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV) >> iunit(r_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ADDModelVVGRVertex,VVTVertex>
describeHerwigADDModelVVGRVertex("Herwig::ADDModelVVGRVertex", "HwADDModel.so");
void ADDModelVVGRVertex::Init() {
static ClassDocumentation<ADDModelVVGRVertex> documentation
("The ADDModelVVGRVertex class is the implementation"
" of the ADDModel vector-vector-graviton vertex");
}
void ADDModelVVGRVertex::setCoupling(Energy2,tcPDPtr,tcPDPtr, tcPDPtr) {
norm(Complex(UnitRemoval::E * kappa_));
}
ADDModelVVGRVertex::ADDModelVVGRVertex() : kappa_(ZERO), r_(ZERO) {
orderInGem(1);
orderInGs (0);
+ colourStructure(ColourStructure::DELTA);
}
void ADDModelVVGRVertex::doinit() {
addToList(23,23,39);
addToList(22,22,39);
addToList(24,-24,39);
addToList(21,21,39);
VVTVertex::doinit();
tcHwADDPtr hwADD=dynamic_ptr_cast<tcHwADDPtr>(generator()->standardModel());
if(!hwADD)
throw Exception() << "Must be ADDModel in ADDModelVVGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwADD->MPlanckBar();
r_ = sqr(hwADD->LambdaT())/hwADD->MPlanckBar();
}
Complex ADDModelVVGRVertex::propagator(int iopt, Energy2 q2,tcPDPtr part,
Energy mass, Energy width) {
if(part->id()!=ParticleID::Graviton)
return VertexBase::propagator(iopt,q2,part,mass,width);
else
return Complex(4.*Constants::pi*UnitRemoval::E2/sqr(r_));
}
diff --git a/Models/ADD/ADDModelWWWGRVertex.cc b/Models/ADD/ADDModelWWWGRVertex.cc
--- a/Models/ADD/ADDModelWWWGRVertex.cc
+++ b/Models/ADD/ADDModelWWWGRVertex.cc
@@ -1,106 +1,107 @@
// -*- C++ -*-
//
// ADDModelWWWGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ADDModelWWWGRVertex class.
//
#include "ADDModelWWWGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
ADDModelWWWGRVertex::ADDModelWWWGRVertex()
: kappa_(ZERO), r_(ZERO), couplast_(0.),
q2last_(ZERO), zfact_(0.) {
// order in the couplings
orderInGem(2);
orderInGs (0);
+ colourStructure(ColourStructure::SINGLET);
}
void ADDModelWWWGRVertex::doinit() {
addToList(24,-24, 22, 39);
addToList(24,-24, 23, 39);
VVVTVertex::doinit();
zfact_ = sqrt((1.-sin2ThetaW())/sin2ThetaW());
// set the graviton coupling
tcHwADDPtr hwADD=dynamic_ptr_cast<tcHwADDPtr>(generator()->standardModel());
if(!hwADD)
throw Exception()
<< "Must have ADDModel in ADDModelWWWGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwADD->MPlanckBar();
r_ = sqr(hwADD->LambdaT())/hwADD->MPlanckBar();
}
void ADDModelWWWGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV) << zfact_ << ounit(r_,GeV);
}
void ADDModelWWWGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV) >> zfact_ >> iunit(r_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ADDModelWWWGRVertex,VVVTVertex>
describeHerwigADDModelWWWGRVertex("Herwig::ADDModelWWWGRVertex", "HwADDModel.so");
void ADDModelWWWGRVertex::Init() {
static ClassDocumentation<ADDModelWWWGRVertex> documentation
("The ADDModelWWWGRVertex class is the four point coupling"
" of three vector bosons and a graviton in the Randell-Sundrum model.");
}
// couplings for the WWWGR vertex
void ADDModelWWWGRVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,
tcPDPtr c, tcPDPtr) {
int ida=a->id();
int idb=b->id();
int idc=c->id();
// first the overall normalisation
if(q2!=q2last_||couplast_==0.) {
couplast_ = electroMagneticCoupling(q2);
q2last_=q2;
}
// W- W+ photon and cylic perms
if((ida==-24 && idb== 24 && idc== 22) ||
(ida== 22 && idb==-24 && idc== 24) ||
(ida== 24 && idb== 22 && idc==-24) )
norm(Complex(couplast_*kappa_*UnitRemoval::E));
// W+ W- photon (anticylic perms of above)
else if((ida== 24 && idb==-24 && idc== 22) ||
(ida== 22 && idb== 24 && idc==-24) ||
(ida==-24 && idb== 22 && idc== 24) )
norm(-Complex(couplast_*kappa_*UnitRemoval::E));
// W- W+ Z and cylic perms
else if((ida==-24 && idb== 24 && idc== 23) ||
(ida== 23 && idb==-24 && idc== 24) ||
(ida== 24 && idb== 23 && idc==-24) )
norm(Complex(couplast_*zfact_*kappa_*UnitRemoval::E));
// W+ W- Z (anticylic perms of above)
else if((ida== 24 && idb==-24 && idc== 23) ||
(ida== 23 && idb== 24 && idc==-24) ||
(ida==-24 && idb== 23 && idc== 24) )
norm(-Complex(couplast_*zfact_*kappa_*UnitRemoval::E));
else assert(false);
}
Complex ADDModelWWWGRVertex::propagator(int iopt, Energy2 q2,tcPDPtr part,
Energy mass, Energy width) {
if(part->id()!=ParticleID::Graviton)
return VertexBase::propagator(iopt,q2,part,mass,width);
else
return Complex(4.*Constants::pi*UnitRemoval::E2/sqr(r_));
}
diff --git a/Models/Feynrules/python/ufo2herwig b/Models/Feynrules/python/ufo2herwig
--- a/Models/Feynrules/python/ufo2herwig
+++ b/Models/Feynrules/python/ufo2herwig
@@ -1,387 +1,437 @@
#! /usr/bin/env python
from __future__ import division
import os, sys, pprint, argparse, re,copy
from string import strip, Template
# add path to the ufo conversion modules
modulepath = os.path.join("@PKGLIBDIR@",'python')
sys.path.append(modulepath)
from ufo2peg import *
# set up the option parser for command line input
parser = argparse.ArgumentParser(
description='Create Herwig model files from Feynrules UFO input.'
)
parser.add_argument(
'ufodir',
metavar='UFO_directory',
help='the UFO model directory'
)
parser.add_argument(
'-v', '--verbose',
action="store_true",
help="print verbose output"
)
parser.add_argument(
'-n','--name',
default="FRModel",
help="set custom nametag for the model"
)
parser.add_argument(
'--ignore-skipped',
action="store_true",
help="ignore skipped vertices and produce output anyway"
)
parser.add_argument(
'--split-model',
action="store_true",
help="Split the model file into pieces to improve compilation for models with many parameters"
)
parser.add_argument(
'--no-generic-loop-vertices',
action="store_true",
help="Don't include the automatically generated generic loop vertices for h->gg and h->gamma gamma"
)
parser.add_argument(
+ '--include-generic',
+ action="store_true",
+ help="Include support for generic spin structures (still experimental)"
+)
+parser.add_argument(
+ '--use-generic-for-tensors',
+ action="store_true",
+ help="Use the generic machinery for all tensor vertices (debugging only)"
+)
+parser.add_argument(
'--forbidden-particle-name',
action="append",
default=["eta","phi"],
help="Add particle names not allowed as names in UFO models to avoid conflicts with"+\
"Herwig internal particles, names will have _UFO appended"
)
# get the arguments
args = parser.parse_args()
# import the model
import imp
path,mod = os.path.split(os.path.abspath(args.ufodir))
FR = imp.load_module(mod,*imp.find_module(mod,[path]))
##################################################
##################################################
# get the Model name from the arguments
modelname = args.name
libname = modelname + '.so'
# define arrays and variables
#allplist = ""
parmdecls = []
parmgetters = []
parmconstr = []
doinit = []
paramstoreplace_ = []
paramstoreplace_expressions_ = []
# get external parameters for printing
parmsubs = dict( [ (p.name, p.value)
for p in FR.all_parameters
if p.nature == 'external' ] )
# evaluate python cmath
def evaluate(x):
import cmath
return eval(x,
{'cmath':cmath,
'complexconjugate':FR.function_library.complexconjugate},
parmsubs)
## get internal params into arrays
internal = ( p for p in FR.all_parameters
if p.nature == 'internal' )
#paramstoreplaceEW_ = []
#paramstoreplaceEW_expressions_ = []
# calculate internal parameters
for p in internal:
parmsubs.update( { p.name : evaluate(p.value) } )
# if 'aS' in p.value and p.name != 'aS':
# paramstoreplace_.append(p.name)
# paramstoreplace_expressions_.append(p.value)
# if 'aEWM1' in p.value and p.name != 'aEWM1':
# paramstoreplaceEW_.append(p.name)
# paramstoreplaceEW_expressions_.append(p.value)
parmvalues=copy.copy(parmsubs)
# more arrays used for substitution in templates
paramsforstream = []
parmmodelconstr = []
# loop over parameters and fill in template stuff according to internal/external and complex/real
# WARNING: Complex external parameter input not tested!
if args.verbose:
print 'verbose mode on: printing all parameters'
print '-'*60
paramsstuff = ('name', 'expression', 'default value', 'nature')
pprint.pprint(paramsstuff)
interfacedecl_T = """\
static Parameter<{modelname}, {type}> interface{pname}
("{pname}",
"The interface for parameter {pname}",
&{modelname}::{pname}_, {value}, 0, 0,
false, false, Interface::nolimits);
"""
+# sort out the couplings
+couplingDefns = { "QED" : 99, "QCD" : 99 }
+try :
+ for coupling in FR.all_orders:
+ name = coupling.name.upper()
+ couplingDefns[name]= coupling.expansion_order
+except:
+ for coupling in FR.all_couplings:
+ for name,value in coupling.order.iteritems():
+ if(name not in couplingDefns) :
+ couplingDefns[name]=99
+
+# sort out the particles
+
massnames = {}
widthnames = {}
for particle in FR.all_particles:
# skip ghosts and goldstones
if(isGhost(particle) or isGoldstone(particle)) :
continue
if particle.mass != 'ZERO':
massnames[particle.mass] = abs(particle.pdg_code)
if particle.width != 'ZERO':
widthnames[particle.width] = abs(particle.pdg_code)
interfaceDecls = []
modelparameters = {}
for p in FR.all_parameters:
value = parmsubs[p.name]
if p.type == 'real':
assert( value.imag < 1.0e-16 )
value = value.real
if p.nature == 'external':
if p not in massnames and p not in widthnames:
interfaceDecls.append(
interfacedecl_T.format(modelname=modelname,
pname=p.name,
value=value,
type=typemap(p.type))
)
else:
interfaceDecls.append('\n// no interface for %s. Use particle definition instead.\n' % p.name)
if hasattr(p,'lhablock'):
lhalabel = '{lhablock}_{lhacode}'.format( lhablock=p.lhablock.upper(), lhacode='_'.join(map(str,p.lhacode)) )
if p not in massnames and p not in widthnames:
parmmodelconstr.append('set %s:%s ${%s}' % (modelname, p.name, lhalabel))
else:
parmmodelconstr.append('# %s is taken from the particle setup' % p.name)
modelparameters[lhalabel] = value
parmsubs[p.name] = lhalabel
else:
if p not in massnames and p not in widthnames:
parmmodelconstr.append('set %s:%s %s' % (modelname, p.name, value))
else:
parmmodelconstr.append('# %s is taken from the particle setup' % p.name)
parmsubs[p.name] = value
if p not in massnames and p not in widthnames:
parmconstr.append('%s_(%s)' % (p.name, value))
else:
parmconstr.append('%s_()' % p.name)
else :
parmconstr.append('%s_()' % p.name)
parmsubs[p.name] = value
elif p.type == 'complex':
value = complex(value)
if p.nature == 'external':
#
# TODO: WE DO NOT HAVE COMPLEX INTERFACES IN THEPEG (yet?)
#
# interfaceDecls.append(
# interfacedecl_T.format(modelname=modelname,
# pname=p.name,
# value='Complex(%s,%s)'%(value.real,value.imag),
# type=typemap(p.type))
# )
#
# parmmodelconstr.append('set %s:%s (%s,%s)' % (modelname, p.name, value.real, value.imag))
parmconstr.append('%s_(%s,%s)' % (p.name, value.real, value.imag))
else :
parmconstr.append('%s_(%s,%s)' % (p.name, 0.,0.))
parmsubs[p.name] = value
else:
raise Exception('Unknown data type "%s".' % p.type)
parmdecls.append(' %s %s_;' % (typemap(p.type), p.name))
parmgetters.append(' %s %s() const { return %s_; }' % (typemap(p.type),p.name, p.name))
paramsforstream.append('%s_' % p.name)
expression, symbols = 'return %s_' % p.name, None
if p.nature != 'external':
expression, symbols = py2cpp(p.value)
text = add_brackets(expression, symbols)
text=text.replace('()()','()')
doinit.append(' %s_ = %s;' % (p.name, text) )
if p in massnames:
doinit.append(' resetMass(%s,%s_ * GeV);' % (massnames[p], p.name) )
elif p in widthnames:
doinit.append(' getParticleData(%s)->width(%s_ * GeV);' % (widthnames[p], p.name) )
- doinit.append(' getParticleData(%s)->cTau (%s_ == 0.0 ? ZERO : hbarc/(%s_*GeV));' % (widthnames[p], p.name, p.name) )
- doinit.append(' getParticleData(%s)->widthCut(10. * %s_ * GeV);' % (widthnames[px], p.name) )
+ doinit.append(' getParticleData(%s)->cTau (%s_ == 0.0 ? Length() : hbarc/(%s_*GeV));' % (widthnames[p], p.name, p.name) )
+ doinit.append(' getParticleData(%s)->widthCut(10. * %s_ * GeV);' % (widthnames[p], p.name) )
elif p.nature == 'external':
if p in massnames:
doinit.append(' %s_ = getParticleData(%s)->mass() / GeV;' % (p.name, massnames[p]) )
elif p in widthnames:
doinit.append(' %s_ = getParticleData(%s)->width() / GeV;' % (p.name, widthnames[p]) )
if args.verbose:
pprint.pprint((p.name,p.value, value, p.nature))
pcwriter = ParamCardWriter(FR.all_parameters)
paramcard_output = '\n'.join(pcwriter.output)
### special treatment
# if p.name == 'aS':
# expression = '0.25 * sqr(strongCoupling(q2)) / Constants::pi'
# elif p.name == 'aEWM1':
# expression = '4.0 * Constants::pi / sqr(electroMagneticCoupling(q2))'
# elif p.name == 'Gf':
# expression = 'generator()->standardModel()->fermiConstant() * GeV2'
paramconstructor=': '
for ncount in range(0,len(parmconstr)) :
paramconstructor += parmconstr[ncount]
if(ncount != len(parmconstr) -1) :
paramconstructor += ','
if(ncount%5 == 0 ) :
paramconstructor += "\n"
paramout=""
paramin =""
for ncount in range(0,len(paramsforstream)) :
if(ncount !=0 ) :
paramout += "<< " + paramsforstream[ncount]
paramin += ">> " + paramsforstream[ncount]
else :
paramout += paramsforstream[ncount]
paramin += paramsforstream[ncount]
if(ncount%5 == 0 ) :
paramout += "\n"
paramin += "\n"
parmtextsubs = { 'parmgetters' : '\n'.join(parmgetters),
'parmdecls' : '\n'.join(parmdecls),
'parmconstr' : paramconstructor,
'getters' : '',
'decls' : '',
'addVertex' : '',
'doinit' : '\n'.join(doinit),
'ostream' : paramout,
'istream' : paramin ,
'refs' : '',
'parmextinter': ''.join(interfaceDecls),
'ModelName': modelname,
'calcfunctions': '',
'param_card_data': paramcard_output
}
##################################################
##################################################
##################################################
# set up the conversion of the vertices
-vertexConverter = VertexConverter(FR,parmvalues)
+vertexConverter = VertexConverter(FR,parmvalues,couplingDefns)
vertexConverter.readArgs(args)
# convert the vertices
vertexConverter.convert()
+cdefs=""
+couplingOrders=""
+ncount=2
+for name,value in couplingDefns.iteritems() :
+ if(name=="QED") :
+ couplingOrders+=" setCouplings(\"%s\",make_pair(%s,%s));\n" %(name,1,value)
+ elif (name=="QCD") :
+ couplingOrders+=" setCouplings(\"%s\",make_pair(%s,%s));\n" %(name,2,value)
+ else :
+ ncount+=1
+ cdefs +=" const T %s = %s;\n" % (name,ncount)
+ couplingOrders+=" setCouplings(\"%s\",make_pair(%s,%s));\n" % (name,ncount,value)
+# coupling definitions
+couplingTemplate= """\
+namespace ThePEG {{
+namespace Helicity {{
+namespace CouplingType {{
+ typedef unsigned T;
+ /**
+ * Enums for couplings
+ */
+{coup}
+}}
+}}
+}}
+"""
+if(cdefs!="") :
+ cdefs = couplingTemplate.format(coup=cdefs)
+parmtextsubs['couplings'] = cdefs
+parmtextsubs['couplingOrders'] = couplingOrders
-##################################################
-##################################################
-##################################################
-
-
+# particles
plist, names = thepeg_particles(FR,parmsubs,modelname,modelparameters,args.forbidden_particle_name)
particlelist = [
"# insert HPConstructor:Outgoing 0 /Herwig/{n}/Particles/{p}".format(n=modelname,p=p)
for p in names
]
# make the first one active to have something runnable in the example .in file
particlelist[0] = particlelist[0][2:]
particlelist = '\n'.join(particlelist)
modelfilesubs = { 'plist' : plist,
'vlist' : vertexConverter.get_vertices(libname),
'setcouplings': '\n'.join(parmmodelconstr),
'ModelName': modelname
}
# write the files from templates according to the above subs
if vertexConverter.should_print():
MODEL_HWIN = getTemplate('LHC-FR.in')
if(not args.split_model) :
MODEL_CC = [getTemplate('Model.cc')]
else :
MODEL_EXTRA_CC=getTemplate('Model6.cc')
extra_names=[]
extra_calcs=[]
parmtextsubs['doinit']=""
for i in range(0,len(doinit)) :
if( i%20 == 0 ) :
function_name = "initCalc" +str(int(i/20))
parmtextsubs['doinit'] += function_name +"();\n"
parmtextsubs['calcfunctions'] += "void " + function_name + "();\n"
extra_names.append(function_name)
extra_calcs.append("")
extra_calcs[-1] += doinit[i] + "\n"
for i in range(0,len(extra_names)) :
ccname = '%s_extra_%s.cc' % (modelname,i)
writeFile( ccname, MODEL_EXTRA_CC.substitute({'ModelName' : modelname,
'functionName' : extra_names[i],
'functionCalcs' : extra_calcs[i] }) )
MODEL_CC = [getTemplate('Model1.cc'),getTemplate('Model2.cc'),getTemplate('Model3.cc'),
getTemplate('Model4.cc'),getTemplate('Model5.cc')]
MODEL_H = getTemplate('Model.h')
print 'LENGTH',len(MODEL_CC)
MODELINFILE = getTemplate('FR.model')
writeFile( 'LHC-%s.in' % modelname,
MODEL_HWIN.substitute({ 'ModelName' : modelname,
'Particles' : particlelist })
)
modeltemplate = Template( MODELINFILE.substitute(modelfilesubs) )
writeFile( '%s.h' % modelname, MODEL_H.substitute(parmtextsubs) )
for i in range(0,len(MODEL_CC)) :
if(len(MODEL_CC)==1) :
ccname = '%s.cc' % modelname
else :
ccname = '%s.cc' % (modelname + str(i))
writeFile( ccname, MODEL_CC[i].substitute(parmtextsubs) )
writeFile( modelname +'.template', modeltemplate.template )
writeFile( modelname +'.model', modeltemplate.substitute( modelparameters ) )
# copy the Makefile-FR to current directory,
# replace with the modelname for compilation
with open(os.path.join(modulepath,'Makefile-FR'),'r') as orig:
with open('Makefile','w') as dest:
dest.write(orig.read().replace("FeynrulesModel.so", libname))
print 'finished generating model:\t', modelname
print 'model directory:\t\t', args.ufodir
print 'generated:\t\t\t', len(FR.all_vertices), 'vertices'
print '='*60
print 'library:\t\t\t', libname
print 'input file:\t\t\t', 'LHC-' + modelname +'.in'
print 'model file:\t\t\t', modelname +'.model'
print '='*60
print """\
To complete the installation, compile by typing "make".
An example input file is provided as LHC-FRModel.in,
you'll need to change the required particles in there.
"""
print 'DONE!'
print '='*60
diff --git a/Models/Feynrules/python/ufo2peg/GeneralVertex_class.template b/Models/Feynrules/python/ufo2peg/GeneralVertex_class.template
new file mode 100644
--- /dev/null
+++ b/Models/Feynrules/python/ufo2peg/GeneralVertex_class.template
@@ -0,0 +1,41 @@
+class ${ModelName}${classname}: public Abstract${lorentztag}Vertex {
+ public:
+ ${ModelName}${classname}() {
+ colourStructure(ColourStructure::${colourStructure});
+ ${addToPlist}
+ }
+
+ ${evaldefs}
+
+ void persistentOutput(PersistentOStream & os) const { os << model_; }
+ void persistentInput(PersistentIStream & is, int) { is >> model_; }
+
+ virtual void setCoupling(Energy2, tcPDPtr,
+ tcPDPtr, tcPDPtr) {assert(false);}
+
+ virtual void setCoupling(Energy2,tcPDPtr,tcPDPtr,tcPDPtr,
+ tcPDPtr) {assert(false);}
+
+ protected:
+
+ IBPtr clone() const { return new_ptr(*this); }
+ IBPtr fullclone() const { return new_ptr(*this); }
+ void doinit() {
+ model_ = dynamic_ptr_cast<tcHw${ModelName}Ptr>
+ (generator()->standardModel());
+ assert(model_);
+ ${couplingOrders}
+ Abstract${lorentztag}Vertex::doinit();
+ }
+
+ private:
+
+ ${ModelName}${classname} & operator=(const ${ModelName}${classname} &);
+
+ tcHw${ModelName}Ptr model_;
+};
+DescribeClass<${ModelName}${classname},Helicity::Abstract${lorentztag}Vertex>
+describeHerwig${ModelName}${classname}("Herwig::${ModelName}${classname}",
+ "${ModelName}.so");
+
+${evalimpls}
diff --git a/Models/Feynrules/python/ufo2peg/Model.cc.template b/Models/Feynrules/python/ufo2peg/Model.cc.template
--- a/Models/Feynrules/python/ufo2peg/Model.cc.template
+++ b/Models/Feynrules/python/ufo2peg/Model.cc.template
@@ -1,93 +1,94 @@
// -*- C++ -*-
//
// ${ModelName}.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2007 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ${ModelName} class.
//
#include "${ModelName}.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Helicity/Vertex/VertexBase.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include <fstream>
//#include "Herwig/Models/General/ModelGenerator.h"
using namespace ThePEG;
using namespace Herwig;
${ModelName}::${ModelName}()
${parmconstr}
{}
IBPtr ${ModelName}::clone() const {
return new_ptr(*this);
}
IBPtr ${ModelName}::fullclone() const {
return new_ptr(*this);
}
void ${ModelName}::doinit() {
${doinit}
BSMModel::doinit();
${addVertex}
writeParamCard();
+${couplingOrders}
}
void ${ModelName}::doinitrun() {
BSMModel::doinitrun();
writeParamCard();
}
void ${ModelName}::persistentOutput(PersistentOStream & os) const {
os << ${ostream} ;
}
void ${ModelName}::persistentInput(PersistentIStream & is, int) {
is >> ${istream} ;
}
void ${ModelName}::writeParamCard() const {
ofstream card("param_card.dat");
card
<< "#####################################################\n"
<< "## DO NOT EDIT - GENERATED BY HERWIG UFO CONVERTER ##\n"
<< "#####################################################\n\n";
card
${param_card_data}
<< '\n';
card.close();
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<${ModelName},BSMModel>
describeThePEG${ModelName}("Herwig::${ModelName}", "${ModelName}.so");
void ${ModelName}::Init() {
${refs}
static ClassDocumentation<${ModelName}> documentation
("The ${ModelName} class inherits from BSMModel"
"and supplies additional couplings and access to the ${ModelName}"
"vertices for helicity amplitude calculations" );
${parmextinter}
}
diff --git a/Models/Feynrules/python/ufo2peg/Model.h.template b/Models/Feynrules/python/ufo2peg/Model.h.template
--- a/Models/Feynrules/python/ufo2peg/Model.h.template
+++ b/Models/Feynrules/python/ufo2peg/Model.h.template
@@ -1,148 +1,150 @@
// -*- C++ -*-
//
// ${ModelName}.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2013 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_${ModelName}_H
#define HERWIG_${ModelName}_H
// This is the declaration of the ${ModelName} class.
#include "Herwig/Models/General/BSMModel.h"
+${couplings}
+
namespace Herwig {
using namespace ThePEG;
using ThePEG::Constants::pi;
const Complex ii = Complex(0,1);
/** \ingroup Models
*
* This is the Herwig ${ModelName} class which inherits from ThePEG
* FeynRules Model class and implements additional FeynRules Model couplings,
* access to vertices for helicity amplitude calculations etc.
*
* @see BSMModel
*/
class ${ModelName}: public BSMModel {
public:
/// Default constructor
${ModelName}();
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);
//@}
/**
* Write out a UFO param_card.dat that matches the configured values
*/
void writeParamCard() const;
/**
* Standard Init function used to initialize the interfaces.
*/
static void Init();
protected:
virtual bool registerDefaultVertices() const { return false; }
public:
/**
* Pointers to the objects handling the vertices.
*/
//@{
${getters}
${parmgetters}
//@}
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:
/**
* Initialize this object after the setup phase before saving and
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
//@}
private:
/**
* Private and non-existent assignment operator.
*/
${ModelName} & operator=(const ${ModelName} &);
private:
/**
* Helper functions for doinit
*/
//@{
${calcfunctions}
//@}
private:
/**
* Pointers to the vertices for ${ModelName} Model helicity amplitude
* calculations.
*/
//@{
${decls}
${parmdecls}
//@}
};
}
namespace ThePEG {
ThePEG_DECLARE_POINTERS(Herwig::${ModelName},Hw${ModelName}Ptr);
}
#endif /* HERWIG_${ModelName}_H */
diff --git a/Models/Feynrules/python/ufo2peg/Vertex_class.template b/Models/Feynrules/python/ufo2peg/Vertex_class.template
--- a/Models/Feynrules/python/ufo2peg/Vertex_class.template
+++ b/Models/Feynrules/python/ufo2peg/Vertex_class.template
@@ -1,43 +1,42 @@
class ${ModelName}${classname}: public ${lorentztag}Vertex {
public:
${ModelName}${classname}() {
${header}
+ colourStructure(ColourStructure::${colourStructure});
${addToPlist}
}
void setCoupling(Energy2 ${couplingptrs}) {
${symbolrefs}
${prepend}
// getParams(q2);
${norm}
${left}
${right}
${append}
}
void persistentOutput(PersistentOStream & os) const { os << model_; }
void persistentInput(PersistentIStream & is, int) { is >> model_; }
// static void Init();
protected:
IBPtr clone() const { return new_ptr(*this); }
IBPtr fullclone() const { return new_ptr(*this); }
void doinit() {
model_ = dynamic_ptr_cast<tcHw${ModelName}Ptr>
(generator()->standardModel());
assert(model_);
// getParams(q2);
${parameters}
- ${setCouplings}
- orderInGem(${qedorder});
- orderInGs(${qcdorder});
+ ${couplingOrders}
${lorentztag}Vertex::doinit();
}
// void getParams(Energy2);
private:
${ModelName}${classname} & operator=(const ${ModelName}${classname} &);
// Complex leftval, rightval, normval;
tcHw${ModelName}Ptr model_;
};
DescribeClass<${ModelName}${classname},Helicity::${lorentztag}Vertex>
describeHerwig${ModelName}${classname}("Herwig::${ModelName}${classname}",
"${ModelName}.so");
// void ${ModelName}${classname}::getParams(Energy2 ) {
// }
diff --git a/Models/Feynrules/python/ufo2peg/check_lorentz.py b/Models/Feynrules/python/ufo2peg/check_lorentz.py
--- a/Models/Feynrules/python/ufo2peg/check_lorentz.py
+++ b/Models/Feynrules/python/ufo2peg/check_lorentz.py
@@ -1,854 +1,864 @@
-import itertools,cmath,re,sys
+import itertools,cmath,re
from .helpers import SkipThisVertex,extractAntiSymmetricIndices
from .converter import py2cpp
from .lorentzparser import parse_lorentz
+import string,re
def compare(a,b) :
num=abs(a-b)
den=abs(a+b)
if(den == 0. and 1e-10) :
return True
return num/den<1e-10
def evaluate(x,model,parmsubs):
import cmath
return eval(x,
{'cmath':cmath,
'complexconjugate':model.function_library.complexconjugate},
parmsubs)
-# ordering for EW VVV vertices
+# ordering for EW VVV vertices (ordering not an issue as all same spin)
def VVVordering(vertex) :
pattern = "if((p1->id()==%s&&p2->id()==%s&&p3->id()==%s)"+\
"||(p1->id()==%s&&p2->id()==%s&&p3->id()==%s)||"+\
"(p1->id()==%s&&p2->id()==%s&&p3->id()==%s)) {norm(-norm());}"
ordering = pattern%(vertex.particles[1].pdg_code,
vertex.particles[0].pdg_code,
vertex.particles[2].pdg_code,
vertex.particles[0].pdg_code,
vertex.particles[2].pdg_code,
vertex.particles[1].pdg_code,
vertex.particles[2].pdg_code,
vertex.particles[1].pdg_code,
vertex.particles[0].pdg_code)
return ordering
def tensorCouplings(vertex,value,prefactors,L,lorentztag,pos,all_couplings,order) :
# split the structure into its different terms for analysis
ordering=""
structures = extractStructures(L)
if(lorentztag == 'SST') :
terms=[['P(1003,2)','P(2003,1)'],
['P(1003,1)','P(2003,2)'],
['P(-1,1)','P(-1,2)','Metric(1003,2003)'],
['Metric(1003,2003)']]
signs=[1.,1.,-1.,-1.]
new_couplings=[False]*len(terms)
elif(lorentztag == 'FFT' ) :
terms=[['P(2003,1)','Gamma(1003,2,1)'],
['P(2003,2)','Gamma(1003,2,1)'],
['P(1003,1)','Gamma(2003,2,1)'],
['P(1003,2)','Gamma(2003,2,1)'],
['P(-1,1)','Gamma(-1,2,1)','Metric(1003,2003)'],
['P(-1,2)','Gamma(-1,2,1)','Metric(1003,2003)'],
['Metric(1003,2003)']]
signs=[1.,-1.,1.,-1.,-0.5,0.5,1.]
new_couplings=[False]*3*len(terms)
elif(lorentztag == 'VVT' ) :
terms=[['P(-1,1)','P(-1,2)','Metric(1,2003)','Metric(2,1003)'], # from C term
['P(-1,1)','P(-1,2)','Metric(1,1003)','Metric(2,2003)'], # from C term
['P(-1,1)','P(-1,2)','Metric(1,2)','Metric(1003,2003)'], # from C term
['P(1,2)','P(2,1)','Metric(1003,2003)'], # from D term (sym)
['P(1,2)','P(2003,1)','Metric(2,1003)'], # 1st term
['P(1,2)','P(1003,1)','Metric(2,2003)'], # 1st swap
['P(2,1)','P(2003,2)','Metric(1,1003)'], # 2nd term
['P(2,1)','P(1003,2)','Metric(1,2003)'], # 2nd swap
['P(1003,2)','P(2003,1)','Metric(1,2)'], # 3rd term
['P(1003,1)','P(2003,2)','Metric(1,2)'], # 3rd swap
['Metric(1,2003)','Metric(2,1003)'], # from mass term
['Metric(1,1003)','Metric(2,2003)'], # from mass term
['Metric(1,2)','Metric(1003,2003)'], # from mass term
['P(1,1)','P(2,1)','Metric(1003,2003)'], # gauge terms
['P(1,2)','P(2,2)','Metric(1003,2003)'], # gauge terms
['P(1,1)','P(2,2)','Metric(1003,2003)'], # gauge terms
['P(1003,1)','P(1,1)','Metric(2,2003)'], # gauge terms
['P(1003,2)','P(2,2)','Metric(1,2003)'], # gauge terms
['P(2003,1)','P(1,1)','Metric(2,1003)'], # gauge terms
['P(2003,2)','P(2,2)','Metric(1,1003)'], # gauge terms
]
signs=[1.,1.,-1.,1.,-1.,-1.,-1.,-1.,1.,1.,1.,1.,-1.,1.,1.,0.25,-1.,-1.,-1.,-1.]
new_couplings=[False]*len(terms)
elif(lorentztag == 'FFVT' ) :
terms = [['Gamma(2004,2,1)','Metric(3,1004)'],
['Gamma(1004,2,1)','Metric(3,2004)'],
['Gamma(3,2,1)','Metric(1004,2004)'],
['Gamma(2004,2,-1)','Metric(3,1004)'],
['Gamma(1004,2,-1)','Metric(3,2004)'],
['Gamma(3,2,-1)','Metric(1004,2004)']]
signs=[1.,1.,-0.5,1.,1.,-0.5]
new_couplings=[False]*3*len(terms)
elif(lorentztag == 'VVVT' ) :
# the F(mu nu,rho sigma lambda) terms first
terms = [['P(2004,2)','Metric(1,1004)','Metric(2,3)'],['P(2004,3)','Metric(1,1004)','Metric(2,3)'],
['P(1004,2)','Metric(1,2004)','Metric(2,3)'],['P(1004,3)','Metric(1,2004)','Metric(2,3)'],
['P(2004,3)','Metric(1,3)','Metric(2,1004)'],['P(2004,1)','Metric(1,3)','Metric(2,1004)'],
['P(1004,3)','Metric(1,3)','Metric(2,2004)'],['P(1004,1)','Metric(1,3)','Metric(2,2004)'],
['P(2004,1)','Metric(1,2)','Metric(3,1004)'],['P(2004,2)','Metric(1,2)','Metric(3,1004)'],
['P(1004,1)','Metric(1,2)','Metric(3,2004)'],['P(1004,2)','Metric(1,2)','Metric(3,2004)'],
['P(3,1)','Metric(1,2004)','Metric(2,1004)'],['P(3,2)','Metric(1,2004)','Metric(2,1004)'],
['P(3,1)','Metric(1,1004)','Metric(2,2004)'],['P(3,2)','Metric(1,1004)','Metric(2,2004)'],
['P(3,1)','Metric(1,2)','Metric(1004,2004)'],['P(3,2)','Metric(1,2)','Metric(1004,2004)'],
['P(2,3)','Metric(1,2004)','Metric(3,1004)'],['P(2,1)','Metric(1,2004)','Metric(3,1004)'],
['P(2,3)','Metric(1,1004)','Metric(3,2004)'],['P(2,1)','Metric(1,1004)','Metric(3,2004)'],
['P(2,3)','Metric(1,3)','Metric(1004,2004)'],['P(2,1)','Metric(1,3)','Metric(1004,2004)'],
['P(1,2)','Metric(2,2004)','Metric(3,1004)'],['P(1,3)','Metric(2,2004)','Metric(3,1004)'],
['P(1,2)','Metric(2,1004)','Metric(3,2004)'],['P(1,3)','Metric(2,1004)','Metric(3,2004)'],
['P(1,2)','Metric(2,3)','Metric(1004,2004)'],['P(1,3)','Metric(2,3)','Metric(1004,2004)']]
signs = [1.,-1.,1.,-1.,1.,-1.,1.,-1.,1.,-1.,1.,-1.,
1.,-1.,1.,-1.,-1.,1.,1.,-1.,1.,-1.,-1.,1.,1.,-1.,1.,-1.,-1.,1.]
new_couplings=[False]*len(terms)
l = lambda c: len(pos[c])
if l(8)!=3 :
ordering = VVVordering(vertex)
# unknown
else :
raise Exception('Unknown data type "%s".' % lorentztag)
iterm=0
try :
for term in terms:
for perm in itertools.permutations(term):
label = '*'.join(perm)
for istruct in range(0,len(structures)) :
if label in structures[istruct] :
reminder = structures[istruct].replace(label,'1.',1)
loc=iterm
if(reminder.find("ProjM")>=0) :
reminder=re.sub("\*ProjM\(.*,.\)","",reminder)
loc+=len(terms)
elif(reminder.find("ProjP")>=0) :
reminder=re.sub("\*ProjP\(.*,.\)","",reminder)
loc+=2*len(terms)
structures[istruct] = "Done"
val = eval(reminder, {'cmath':cmath} )*signs[iterm]
if(new_couplings[loc]) :
new_couplings[loc] += val
else :
new_couplings[loc] = val
iterm+=1
except :
SkipThisVertex()
# check we've handled all the terms
for val in structures:
if(val!="Done") :
raise SkipThisVertex()
# special for FFVT
if(lorentztag=="FFVT") :
t_couplings=new_couplings
new_couplings=[False]*9
for i in range(0,9) :
j = i+3*(i/3)
k = i+3+3*(i/3)
if( not t_couplings[j]) :
new_couplings[i] = t_couplings[k]
else :
new_couplings[i] = t_couplings[j]
# set the couplings
for icoup in range(0,len(new_couplings)) :
if(new_couplings[icoup]) :
new_couplings[icoup] = '(%s) * (%s) *(%s)' % (new_couplings[icoup],prefactors,value)
if(len(all_couplings)==0) :
all_couplings=new_couplings
else :
for icoup in range(0,len(new_couplings)) :
if(new_couplings[icoup] and all_couplings[icoup]) :
all_couplings[icoup] = '(%s) + (%s) ' % (new_couplings[icoup],all_couplings[icoup])
elif(new_couplings[icoup]) :
all_couplings[icoup] = new_couplings[icoup]
# return the results
return (ordering,all_couplings)
-def processTensorCouplings(lorentztag,vertex,model,parmsubs,all_couplings) :
+def processTensorCouplings(lorentztag,vertex,model,parmsubs,all_couplings,order) :
# check for fermion vertices (i.e. has L/R couplings)
fermions = "FF" in lorentztag
# test and process the values of the couplings
tval = [False]*3
value = [False]*3
# loop over the colours
for icolor in range(0,len(all_couplings)) :
lmax = len(all_couplings[icolor])
if(fermions) : lmax /=3
# loop over the different terms
for ix in range(0,lmax) :
test = [False]*3
# normal case
if( not fermions ) :
test[0] = all_couplings[icolor][ix]
else :
# first case vector but no L/R couplings
if( not all_couplings[icolor][lmax+ix] and
not all_couplings[icolor][2*lmax+ix] ) :
test[0] = all_couplings[icolor][ix]
# special for mass terms and massless particles
if(not all_couplings[icolor][ix]) :
- code = abs(vertex.particles[0].pdg_code)
+ code = abs(vertex.particles[order[0]-1].pdg_code)
if(ix==6 and code ==12 or code ==14 or code==16) :
continue
else :
raise SkipThisVertex()
# second case L/R couplings
elif( not all_couplings[icolor][ix] ) :
# L=R, replace with vector
if(all_couplings[icolor][lmax+ix] ==
all_couplings[icolor][2*lmax+ix]) :
test[0] = all_couplings[icolor][lmax+ix]
else :
test[1] = all_couplings[icolor][lmax+ix]
test[2] = all_couplings[icolor][2*lmax+ix]
else :
raise SkipThisVertex()
# special handling of mass terms
# scalar divide by m**2
if((ix==3 and lorentztag=="SST") or
( ix>=10 and ix<=12 and lorentztag=="VVT" )) :
for i in range(0,len(test)) :
if(test[i]) :
- test[i] = '(%s)/%s**2' % (test[i],vertex.particles[0].mass.value)
+ test[i] = '(%s)/%s**2' % (test[i],vertex.particles[order[0]-1].mass.value)
# fermions divide by 4*m
elif(ix==6 and lorentztag=="FFT" and
- float(vertex.particles[0].mass.value) != 0. ) :
+ float(vertex.particles[order[0]-1].mass.value) != 0. ) :
for i in range(0,len(test)) :
if(test[i]) :
- test[i] = '-(%s)/%s/4' % (test[i],vertex.particles[0].mass.value)
+ test[i] = '-(%s)/%s/4' % (test[i],vertex.particles[order[0]-1].mass.value)
# set values on first pass
if(not tval[0] and not tval[1] and not tval[2]) :
value = test
for i in range(0,len(test)) :
if(test[i]) : tval[i] = evaluate(test[i],model,parmsubs)
else :
for i in range(0,len(test)) :
if(not test[i] and not tval[i]) :
continue
if(not test[i] or not tval[i]) :
# special for mass terms and vectors
if(lorentztag=="VVT" and ix >=10 and ix <=12 and
- float(vertex.particles[0].mass.value) == 0. ) :
+ float(vertex.particles[order[0]-1].mass.value) == 0. ) :
continue
# special for vector gauge terms
if(lorentztag=="VVT" and ix>=13) :
continue
raise SkipThisVertex()
tval2 = evaluate(test[i],model,parmsubs)
if(abs(tval[i]-tval2)>1e-6) :
# special for fermion mass term if fermions massless
if(lorentztag=="FFT" and ix ==6 and tval2 == 0. and
- float(vertex.particles[0].mass.value) == 0. ) :
+ float(vertex.particles[order[0]-1].mass.value) == 0. ) :
continue
raise SkipThisVertex()
# simple clean up
for i in range(0,len(value)):
if(value[i]) :
value[i] = value[i].replace("(1.0) * ","").replace(" * (1)","")
# put everything together
coup_left = 0.
coup_right = 0.
coup_norm = 0.
if(lorentztag == "SST" or lorentztag == "VVT" or
lorentztag == "VVVT" or lorentztag == "FFT" ) :
coup_norm = value[0]
if(value[1] or value[2]) :
raise SkipThisVertex()
elif(lorentztag=="FFVT") :
if(not value[1] and not value[2]) :
coup_norm = value[0]
coup_left = "1."
coup_right = "1."
elif(not value[0]) :
coup_norm = "1."
if(value[1] and value[2]) :
coup_left = value[1]
coup_right = value[2]
elif(value[1]) :
coup_left = value[1]
coup_right = "0."
elif(value[2]) :
coup_left = "0."
coup_right = value[2]
else :
raise SkipThisVertex()
else :
raise SkipThisVertex()
else :
raise SkipThisVertex()
# return the answer
return (coup_left,coup_right,coup_norm)
def extractStructures(L) :
structure1 = L.structure.split()
structures =[]
sign=''
for struct in structure1 :
if(struct=='+') :
continue
elif(struct=='-') :
sign='-'
else :
structures.append(sign+struct.strip())
sign=''
return structures
def changeSign(sign1,sign2) :
if((sign1=="+" and sign2=="+") or\
(sign1=="-" and sign2=="-")) :
return "+"
else :
return "-"
def epsilonOrder(eps) :
terms,sign = extractAntiSymmetricIndices(eps,"Epsilon(")
return (sign,"Epsilon(%s,%s,%s,%s)" % (terms[0],terms[1],terms[2],terms[3]))
def VVSEpsilon(couplings,struct) :
if(struct.find("Epsilon")<0) :
return
fact=""
sign="+"
if(struct[-1]==")") :
fact=struct.split("(")[0]
if(fact.find("Epsilon")>=0) :
fact=""
else :
struct=struct.split("(",1)[1][:-1]
if(fact[0]=="-") :
sign="-"
fact=fact[1:]
split = struct.split("*")
# find the epsilon
eps=""
for piece in split :
if(piece.find("Epsilon")>=0) :
eps=piece
split.remove(piece)
break
# and any prefactors
for piece in split :
if(piece.find("P(")<0) :
split.remove(piece)
if(piece[0]=="+" or piece[0]=="-") :
sign=changeSign(sign,piece[0])
piece=piece[1:]
if(fact=="") :
fact=piece
else :
fact = "( %s ) * ( %s )" % (fact , piece)
# now sort out the momenta
for piece in split :
terms=piece.split(",")
terms[0]=terms[0].strip("P(")
terms[1]=terms[1].strip(")")
eps=eps.replace(terms[0],"P%s"%terms[1])
(nsign,eps)=epsilonOrder(eps)
if(nsign>0) : sign=changeSign(sign,"-")
if(fact=="") : fact="1."
if(eps!="Epsilon(1,2,P1,P2)") :
return
if(couplings[6]==0.) :
couplings[6] = "( %s%s )" % (sign,fact)
else :
couplings[6] = "( %s ) + ( %s%s )" % (couplings[6],sign,fact)
def scalarVectorCouplings(value,prefactors,L,lorentztag,all_couplings,order) :
# set up the types of term we are looking for
if(lorentztag=="VVS") :
couplings=[0.,0.,0.,0.,0.,0.,0.]
terms=[['P(-1,%s)' % order[0],
'P(-1,%s)' % order[1],
'Metric(%s,%s)' %(order[0],order[1])],
['P(1,%s)' % order[0],
'P(2,%s)' % order[0]],
['P(1,%s)' % order[0],
'P(2,%s)' % order[1]],
['P(1,%s)' % order[1],
'P(2,%s)' % order[0]],
['P(1,%s)' % order[1],
'P(2,%s)' % order[1]],
['Metric(%s,%s)'%(order[0],order[1])]]
elif(lorentztag=="VVSS") :
couplings=[0.]
terms=[['Metric(%s,%s)' % (order[0],order[1])]]
elif(lorentztag=="VSS"):
couplings=[0.,0.]
terms=[['P(%s,%s)' % (order[0],order[2])],
['P(%s,%s)' % (order[0],order[1])]]
# extract the lorentz structures
structures = extractStructures(L)
# handle the scalar couplings
itype=-1
try :
for term in terms:
itype+=1
for perm in itertools.permutations(term):
label = '*'.join(perm)
for istruct in range(0,len(structures)) :
if label in structures[istruct] :
reminder = structures[istruct].replace(label,'1.',1)
couplings[itype]+=eval(reminder, {'cmath':cmath} )
structures[istruct]='Done'
except :
raise SkipThisVertex()
# special for VVS and epsilon
# handle the pseudoscalar couplings
for struct in structures :
if(struct != "Done" ) :
if(lorentztag=="VVS") :
VVSEpsilon(couplings,struct)
else :
raise SkipThisVertex()
# put it all together
if(len(all_couplings)==0) :
for ic in range(0,len(couplings)) :
if(couplings[ic]!=0.) :
all_couplings.append('(%s) * (%s) * (%s)' % (prefactors,value,couplings[ic]))
else :
all_couplings.append(False)
else :
for ic in range(0,len(couplings)) :
if(couplings[ic]!=0. and all_couplings[ic]) :
all_couplings[ic] = '(%s) * (%s) * (%s) + (%s) ' % (prefactors,value,
couplings[ic],all_couplings[ic])
elif(couplings[ic]!=0) :
all_couplings[ic] = '(%s) * (%s) * (%s) ' % (prefactors,value,couplings[ic])
return all_couplings
def processScalarVectorCouplings(lorentztag,vertex,model,parmsubs,all_couplings,header,order) :
# check the values
tval = [False]*len(all_couplings[0])
value =[False]*len(all_couplings[0])
for icolor in range(0,len(all_couplings)) :
for ix in range(0,len(all_couplings[icolor])) :
if(not value[ix]) :
value[ix] = all_couplings[icolor][ix]
if(value[ix] and not tval[ix]) :
tval[ix] = evaluate(value[ix],model,parmsubs)
elif(value[ix]) :
tval2 = evaluate(all_couplings[icolor][0],model,parmsubs)
if(abs(tval[ix]-tval2)>1e-6) :
raise SkipThisVertex()
append = ""
symbols = set()
coup_norm=0.
if(lorentztag=="VVS") :
if(not value[0] and not value[1] and not value[2] and \
not value[3] and not value[4] and not value[6] and value[5]) :
coup_norm=value[5]
else :
for ix in range(0,len(value)) :
if(value[ix]) :
value[ix], sym = py2cpp(value[ix])
symbols |= sym
else :
value[ix]=0.
lorentztag = 'GeneralVVS'
header="kinematics(true);"
# g_mu,nv piece of coupling
if(value[5]!=0.) :
append +='a00( %s + Complex(( %s )* GeV2/invariant(1,2)));\n' % ( value[0],value[5])
else :
append +='a00( %s );\n' % value[0]
# other couplings
append += 'a11( %s );\n a12( %s );\n a21( %s );\n a22( %s );\n aEp( %s );\n' % \
( value[1],value[2],value[3],value[4],value[6] )
coup_norm="1."
elif(lorentztag=="VVSS") :
coup_norm = value[0]
elif(lorentztag=="VSS") :
if(abs(tval[0]+tval[1])>1e-6) :
- raise SkipThisVertex()
- coup_norm = value[1]
- append = 'if(p2->id()!=%s){norm(-norm());}' \
- % vertex.particles[order[1]-1].pdg_code
+ for ix in range(0,len(value)) :
+ if(value[ix]) :
+ value[ix], sym = py2cpp(value[ix])
+ symbols |= sym
+ else :
+ value[ix]=0.
+ coup_norm = "1."
+ append = 'if(p2->id()==%s) { a( %s ); b( %s);}\n else { a( %s ); b( %s);}' \
+ % (vertex.particles[order[1]-1].pdg_code,
+ value[0],value[1],value[1],value[0])
+ else :
+ coup_norm = value[1]
+ append = 'if(p2->id()!=%s){norm(-norm());}' \
+ % vertex.particles[order[1]-1].pdg_code
# return the answer
return (coup_norm,append,lorentztag,header,symbols)
def getIndices(term) :
if(term[0:2]=="P(") :
indices = term.strip(")").strip("P(").split(",")
mom = int(indices[1])
index = int(indices[0])
return (True,mom,index)
else :
return (False,0,0)
def lorentzScalar(vertex,L) :
dotProduct = """(invariant( i[{i1}], i[{i2}] )/GeV2)"""
structures=L.structure.split()
output="("
for struct in structures:
if(struct=="+" or struct=="-") :
output+=struct
continue
structure = struct.split("*")
worked = False
mom=-1
newTerm=""
while True :
term = structure[-1]
structure.pop()
(momentum,mom,index) = getIndices(term)
if( not momentum) : break
# look for the matching momenta
for term in structure :
(momentum,mom2,index2) = getIndices(term)
if(index2==index) :
structure.remove(term)
dot = dotProduct.format(i1=mom-1,i2=mom2-1)
if(newTerm=="") :
newTerm = dot
else :
newTerm = " ( %s) * ( %s ) " % (newTerm,dot)
if(len(structure)==0) :
worked = True
break
if(not worked) :
return False
else :
output+=newTerm
output+=")"
return output
kinematicsline = """\
long id [3]={{{id1},{id2},{id3}}};
long id2[3]={{p1->id(),p2->id(),p3->id()}};
unsigned int i[3];
for(unsigned int ix=0;ix<3;++ix) {{
for(unsigned int iy=0;iy<3;++iy) {{
if(id[ix]==id2[iy]) {{
i[ix] = iy;
id2[iy]=0;
break;
}}
}}
}}
double hw_kine1 = {kine};
"""
kinematicsline2 = """\
long id [4]={{{id1},{id2},{id3},{id4}}};
long id2[4]={{p1->id(),p2->id(),p3->id(),p4->id()}};
unsigned int i[4];
for(unsigned int ix=0;ix<4;++ix) {{
for(unsigned int iy=0;iy<4;++iy) {{
if(id[ix]==id2[iy]) {{
i[ix] = iy;
id2[iy]=0;
break;
}}
}}
}}
double hw_kine1 = {kine};
"""
kinematicsline3 ="""\
double hw_kine{i} = {kine};
"""
def scalarCouplings(vertex,value,prefactors,L,lorentztag,
all_couplings,prepend,header) :
try :
val = int(L.structure)
except :
output = lorentzScalar(vertex,L)
if( not output ) :
raise SkipThisVertex()
else :
if(prepend=="") :
if(lorentztag=="SSS") :
+ # order doesn't matter here, all same spin
prepend = kinematicsline.format(id1=vertex.particles[0].pdg_code,
+ id2=vertex.particles[1].pdg_code,
+ id3=vertex.particles[2].pdg_code,
+ kine=output)
+ else :
+ # order doesn't matter here, all same spin
+ prepend = kinematicsline2.format(id1=vertex.particles[0].pdg_code,
id2=vertex.particles[1].pdg_code,
id3=vertex.particles[2].pdg_code,
+ id4=vertex.particles[3].pdg_code,
kine=output)
- else :
- prepend = kinematicsline2.format(id1=vertex.particles[0].pdg_code,
- id2=vertex.particles[1].pdg_code,
- id3=vertex.particles[2].pdg_code,
- id4=vertex.particles[2].pdg_code,
- kine=output)
value = "(%s) *(hw_kine1)" % value
else :
osplit=prepend.split("\n")
i=-1
while osplit[i]=="":
i=i-1
ikin=int(osplit[i].split("=")[0].replace("double hw_kine",""))+1
prepend +=kinematicsline3.format(kine=output,i=ikin)
value = "(%s) *(hw_kine%s)" % (value,ikin)
header="kinematics(true);"
if(len(all_couplings)==0) :
all_couplings.append('(%s) * (%s)' % (prefactors,value))
else :
all_couplings[0] = '(%s) * (%s) + (%s)' % (prefactors,value,all_couplings[0])
return (prepend, header,all_couplings)
def processScalarCouplings(model,parmsubs,all_couplings) :
tval = False
value = False
for icolor in range(0,len(all_couplings)) :
if(len(all_couplings[icolor])!=1) :
raise SkipThisVertex()
if(not value) :
value = all_couplings[icolor][0]
m = re.findall('hw_kine[0-9]*', all_couplings[icolor][0])
if m:
for kine in m:
# bizarre number for checks, must be a better option
parmsubs[kine] = 987654321.
if(not tval) :
tval = evaluate(value,model,parmsubs)
else :
tval2 = evaluate(all_couplings[icolor][0],model,parmsubs)
if(abs(tval[i]-tval2)>1e-6) :
raise SkipThisVertex()
# cleanup and return the answer
return value.replace("(1.0) * ","").replace(" * (1)","")
def vectorCouplings(vertex,value,prefactors,L,lorentztag,pos,
all_couplings,append,qcd,order) :
structures=extractStructures(L)
terms=[]
signs=[]
if(lorentztag=="VVV") :
terms=[['P(%s,%s)' % (order[2],order[0]),'Metric(%s,%s)' % (order[0],order[1])],
['P(%s,%s)' % (order[2],order[1]),'Metric(%s,%s)' % (order[0],order[1])],
['P(%s,%s)' % (order[1],order[0]),'Metric(%s,%s)' % (order[0],order[2])],
['P(%s,%s)' % (order[1],order[2]),'Metric(%s,%s)' % (order[0],order[2])],
['P(%s,%s)' % (order[0],order[1]),'Metric(%s,%s)' % (order[1],order[2])],
['P(%s,%s)' % (order[0],order[2]),'Metric(%s,%s)' % (order[1],order[2])]]
signs=[1.,-1.,-1.,1.,1.,-1.]
elif(lorentztag=="VVVV") :
terms=[['Metric(%s,%s)' % (order[0],order[3]),'Metric(%s,%s)' % (order[1],order[2])],
['Metric(%s,%s)' % (order[0],order[2]),'Metric(%s,%s)' % (order[1],order[3])],
['Metric(%s,%s)' % (order[0],order[1]),'Metric(%s,%s)' % (order[2],order[3])]]
signs=[1.,1.,1.]
elif(lorentztag=="VVVS") :
terms=[['P(%s,%s)' % (order[2],order[0]),'Metric(%s,%s)' % (order[0],order[1])],
['P(%s,%s)' % (order[2],order[1]),'Metric(%s,%s)' % (order[0],order[1])],
['P(%s,%s)' % (order[1],order[0]),'Metric(%s,%s)' % (order[0],order[2])],
['P(%s,%s)' % (order[1],order[2]),'Metric(%s,%s)' % (order[0],order[2])],
['P(%s,%s)' % (order[0],order[1]),'Metric(%s,%s)' % (order[1],order[2])],
['P(%s,%s)' % (order[0],order[2]),'Metric(%s,%s)' % (order[1],order[2])],
['Epsilon(1,2,3,-1)','P(-1,1)'],['Epsilon(1,2,3,-1)','P(-1,2)'],
['Epsilon(1,2,3,-1)','P(-1,3)']]
signs=[1.,-1.,-1.,1.,1.,-1.,1.,1.,1.]
# extract the couplings
new_couplings = [False]*len(terms)
iterm=0
try :
for term in terms:
for perm in itertools.permutations(term):
label = '*'.join(perm)
for istruct in range(0,len(structures)) :
if label in structures[istruct] :
reminder = structures[istruct].replace(label,'1.',1)
structures[istruct] = "Done"
val = eval(reminder, {'cmath':cmath} )*signs[iterm]
if(new_couplings[iterm]) :
new_couplings[iterm] += val
else :
new_couplings[iterm] = val
iterm += 1
except :
raise SkipThisVertex()
# check we've handled all the terms
for val in structures:
if(val!="Done") :
raise SkipThisVertex()
# set the couplings
for icoup in range(0,len(new_couplings)) :
if(new_couplings[icoup]) :
new_couplings[icoup] = '(%s) * (%s) *(%s)' % (new_couplings[icoup],prefactors,value)
if(len(all_couplings)==0) :
all_couplings=new_couplings
else :
for icoup in range(0,len(new_couplings)) :
if(new_couplings[icoup] and all_couplings[icoup]) :
all_couplings[icoup] = '(%s) * (%s) *(%s) + (%s) ' % (new_couplings[icoup],prefactors,value,all_couplings[icoup])
elif(new_couplings[icoup]) :
all_couplings[icoup] = new_couplings[icoup]
# ordering for VVV type vertices
if(len(pos[8]) != 3 and (lorentztag=="VVV" or lorentztag=="VVVS")) :
append = VVVordering(vertex)
return all_couplings,append
def processVectorCouplings(lorentztag,vertex,model,parmsubs,all_couplings,append,header) :
value = False
tval = False
if(lorentztag=="VVV") :
for icolor in range(0,len(all_couplings)) :
# loop over the different terms
for ix in range(0,len(all_couplings[icolor])) :
if(not value) :
value = all_couplings[icolor][ix]
tval = evaluate(value,model,parmsubs)
else :
tval2 = evaluate(all_couplings[icolor][ix],model,parmsubs)
if(abs(tval-tval2)>1e-6) :
raise SkipThisVertex()
elif(lorentztag=="VVVV") :
order=[]
colours = vertex.color
if(len(colours)==1) :
tval=[]
for i in range(0,3) :
tval.append(evaluate(all_couplings[0][i],model,parmsubs))
if(compare(tval[2],-2.*tval[1]) and
compare(tval[2],-2.*tval[0]) ) :
order=[0,1,2,3]
value = "0.5*(%s)" % all_couplings[0][2]
elif(compare(tval[1],-2.*tval[2]) and
compare(tval[1],-2.*tval[0]) ) :
order=[0,2,1,3]
value = "0.5*(%s)" % all_couplings[0][1]
elif(compare(tval[0],-2.*tval[2]) and
compare(tval[0],-2.*tval[1]) ) :
order=[0,3,1,2]
value = "0.5*(%s)" % all_couplings[0][0]
else:
- sys.stderr.write(
- 'Warning: unsupported {tag} ( {ps} ) Lorentz structure in {name}:\n'
- .format(tag="VVVV", name=vertex.name, ps=' '.join(map(str,vertex.particles)))
- )
raise SkipThisVertex()
pattern = \
"bool done[4]={false,false,false,false};\n" + \
" tcPDPtr part[4]={p1,p2,p3,p4};\n" + \
" unsigned int iorder[4]={0,0,0,0};\n" + \
" for(unsigned int ix=0;ix<4;++ix) {\n" + \
" if(!done[0] && part[ix]->id()==%s) {done[0]=true; iorder[%s] = ix; continue;}\n" + \
" if(!done[1] && part[ix]->id()==%s) {done[1]=true; iorder[%s] = ix; continue;}\n" + \
" if(!done[2] && part[ix]->id()==%s) {done[2]=true; iorder[%s] = ix; continue;}\n" + \
" if(!done[3] && part[ix]->id()==%s) {done[3]=true; iorder[%s] = ix; continue;}\n" + \
" }\n" + \
" setType(2);\n" + \
" setOrder(iorder[0],iorder[1],iorder[2],iorder[3]);"
+ # order doesn't matter here same spin
append = pattern % ( vertex.particles[0].pdg_code,order[0],
vertex.particles[1].pdg_code,order[1],
vertex.particles[2].pdg_code,order[2],
vertex.particles[3].pdg_code,order[3] )
else :
for icolor in range(0,len(all_couplings)) :
col=colours[icolor].split("*")
if(len(col)==2 and "f(" in col[0] and "f(" in col[1]) :
sign = 1
for i in range(0,2) :
col[i],stemp = extractAntiSymmetricIndices(col[i],"f(")
for ix in range(0,len(col[i])): col[i][ix]=int(col[i][ix])
sign *=stemp
if(col[0][0]>col[1][0]) : col[0],col[1] = col[1],col[0]
# first flow
if(col[0][0]==1 and col[0][1]==2 and col[1][0] ==3 and col[1][1] == 4) :
if(all_couplings[icolor][2] or not all_couplings[icolor][0] or
not all_couplings[icolor][1]) :
raise SkipThisVertex()
if(not value) :
- value = all_couplings[icolor][0]
+ value = all_couplings[icolor][1]
tval = evaluate(value,model,parmsubs)
- tval2 = evaluate(all_couplings[icolor][0],model,parmsubs)
- tval3 = -evaluate(all_couplings[icolor][1],model,parmsubs)
+ tval2 = -evaluate(all_couplings[icolor][0],model,parmsubs)
+ tval3 = evaluate(all_couplings[icolor][1],model,parmsubs)
elif(col[0][0]==1 and col[0][1]==3 and col[1][0] ==2 and col[1][1] == 4) :
if(all_couplings[icolor][1] or not all_couplings[icolor][0] or
not all_couplings[icolor][2]) :
raise SkipThisVertex()
if(not value) :
- value = all_couplings[icolor][0]
+ value = all_couplings[icolor][2]
tval = evaluate(value,model,parmsubs)
- tval2 = evaluate(all_couplings[icolor][0],model,parmsubs)
- tval3 = -evaluate(all_couplings[icolor][2],model,parmsubs)
+ tval2 = -evaluate(all_couplings[icolor][0],model,parmsubs)
+ tval3 = evaluate(all_couplings[icolor][2],model,parmsubs)
elif(col[0][0]==1 and col[0][1]==4 and col[1][0] ==2 and col[1][1] == 3) :
if(all_couplings[icolor][0] or not all_couplings[icolor][1] or
not all_couplings[icolor][2]) :
raise SkipThisVertex()
if(not value) :
- value = all_couplings[icolor][1]
+ value = all_couplings[icolor][2]
tval = evaluate(value,model,parmsubs)
- tval2 = evaluate(all_couplings[icolor][1],model,parmsubs)
- tval3 = -evaluate(all_couplings[icolor][2],model,parmsubs)
+ tval2 = -evaluate(all_couplings[icolor][1],model,parmsubs)
+ tval3 = evaluate(all_couplings[icolor][2],model,parmsubs)
else :
raise SkipThisVertex()
if(abs(tval-tval2)>1e-6 or abs(tval-tval3)>1e-6 ) :
raise SkipThisVertex()
append = 'setType(1);\nsetOrder(0,1,2,3);'
else :
print 'unknown colour structure for VVVV vertex'
raise SkipThisVertex()
elif(lorentztag=="VVVS") :
try :
# two distinct cases 0-5 = , 6-8=
if(all_couplings[0][0]) :
imin=0
imax=6
header="scalar(true);"
else :
imin=6
imax=9
header="scalar(false);"
for icolor in range(0,len(all_couplings)) :
# loop over the different terms
for ix in range(imin,imax) :
if(not value) :
value = all_couplings[icolor][ix]
tval = evaluate(value,model,parmsubs)
else :
tval2 = evaluate(value,model,parmsubs)
if(abs(tval-tval2)>1e-6) :
raise SkipThisVertex()
except :
SkipThisVertex()
# cleanup and return the answer
value = value.replace("(1.0) * ","").replace(" * (1)","")
return (value,append,header)
def fermionCouplings(value,prefactors,L,all_couplings,order) :
new_couplings=[False,False]
try :
new_couplings[0],new_couplings[1] = parse_lorentz(L.structure)
except :
raise SkipThisVertex()
for i in range(0,2) :
if new_couplings[i]:
new_couplings[i] = '(%s) * (%s) * (%s)' % (prefactors,new_couplings[i],value)
if(len(all_couplings)==0) :
all_couplings=new_couplings
else :
for i in range(0,len(new_couplings)) :
if(new_couplings[i] and all_couplings[i]) :
all_couplings[i] = '(%s) + (%s) ' % (new_couplings[i],all_couplings[i])
elif(new_couplings[i]) :
all_couplings[i] = new_couplings[i]
return all_couplings
-def processFermionCouplings(lorentztag,vertex,model,parmsubs,all_couplings) :
+def processFermionCouplings(lorentztag,vertex,model,parmsubs,all_couplings,order) :
leftcontent = all_couplings[0][0] if all_couplings[0][0] else "0."
rightcontent = all_couplings[0][1] if all_couplings[0][1] else "0."
tval=[evaluate( leftcontent,model,parmsubs),
evaluate(rightcontent,model,parmsubs)]
for icolor in range(0,len(all_couplings)) :
# loop over the different terms
for ix in range(0,len(all_couplings[icolor])) :
tval2 = evaluate(all_couplings[icolor][ix],model,parmsubs) if all_couplings[icolor][ix] else 0.
if(abs(tval[ix]-tval2)>1e-6) :
raise SkipThisVertex()
normcontent = "1."
append=""
if lorentztag == 'FFV':
append = ('if(p1->id()!=%s) {Complex ltemp=left(), rtemp=right(); left(-rtemp); right(-ltemp);}'
- % vertex.particles[0].pdg_code)
+ % vertex.particles[order[0]-1].pdg_code)
return normcontent,leftcontent,rightcontent,append
def RSCouplings(value,prefactors,L,all_couplings,order) :
raise SkipThisVertex()
diff --git a/Models/Feynrules/python/ufo2peg/converter.py b/Models/Feynrules/python/ufo2peg/converter.py
--- a/Models/Feynrules/python/ufo2peg/converter.py
+++ b/Models/Feynrules/python/ufo2peg/converter.py
@@ -1,162 +1,185 @@
"""
AST visitor class to convert Python expressions into C++ as used by ThePEG
"""
import ast
+convertHerwig=False
-def py2cpp(expr):
+def py2cpp(expr,con=False):
"""Convert expr to C++ form. Wraps the converter class."""
+ global convertHerwig
+ convertHerwig=con
result = PyToCpp().parse(expr)
return result
class PyToCppException(Exception):
"""Base class for all PyToCpp exceptions."""
class PyToCpp(ast.NodeVisitor):
"""Convert Python math expressions into C++.
Returns a tuple (expr,syms):
expr -- C++-compatible expression
syms -- set of all free variables
Usage:
>>> expr = '3+2**a*b'
>>> PyToCpp().parse(expr)
('(3.0+(pow(2.0,a)*b))', set(['a', 'b']))
Note:
The converter is currently not generic, it relies on the
conventions of Feynrules' UFO format on the one hand and ThePEG's
C++ types on the other.
"""
def parse(self,expression):
"""Convert expression to C++ format."""
self.result = []
self.symbols = set()
+ expression=expression.replace("abs(","cmath.abs(")
tree = ast.parse(expression)
#print ast.dump(tree)
return self.visit(tree)
##################################
def visit_Module(self,node):
self.generic_visit(node)
return ''.join(self.result), self.symbols
def generic_visit(self,node):
typename = type(node).__name__
harmless = ['Module','Expr']
if typename not in harmless:
raise PyToCppException('Missing implementation for %s' % typename)
super(PyToCpp,self).generic_visit(node)
def visit_UnaryOp(self,node):
self.result.append('(')
self.visit(node.op)
self.visit(node.operand)
self.result.append(')')
def visit_BinOp(self,node):
if type(node.op) == type(ast.Pow()):
return self.pow_node(node)
self.result.append('(')
self.visit(node.left)
self.visit(node.op)
self.visit(node.right)
self.result.append(')')
def pow_node(self,node):
if is_square(node):
self.result.append('sqr(')
self.visit(node.left)
self.result.append(')')
else:
self.result.append('pow(')
self.visit(node.left)
self.result.append(',')
self.visit(node.right)
self.result.append(')')
def visit_Call(self,node):
if is_ii(node):
self.result.append('ii')
else:
self.visit(node.func)
self.result.append('(')
for a in node.args:
self.visit(a)
self.result.append(',')
if self.result[-1] == ',':
del self.result[-1]
self.result.append(')')
def visit_Attribute(self,node):
if node.value.id != 'cmath':
err = "Don't know how to convert %s module." % node.value.id
raise PyToCppException(err)
self.result.append(node.attr)
def visit_Num(self,node):
# some zeros are encoded as 0j
if node.n == 0: text = '0.0'
- else: text = str(float(node.n))
+ elif (node.n==complex("1j") ) :
+ text = "ii"
+ elif (node.n==complex("-1j") ) :
+ text = "-ii"
+ elif (node.n==complex("2j") ) :
+ text = "2.*ii"
+ else:
+ text = str(float(node.n))
self.result.append(text)
def visit_Name(self,node):
text = str(node.id)
if text == 'complex':
text = 'Complex'
elif text == 'complexconjugate':
text = 'conj'
+ elif convertHerwig :
+ if text == 'I' :
+ text = "ii"
+ elif ( text.find("UnitRemoval")==0) :
+ text = "%s::%s" % (text[:11],text[11:])
+ elif(text[0]=="P" or text[0]=="E" or text[0] == "V") :
+ if text[-1] in ["x","y","z","t"] :
+ text = "%s.%s()" % (text[0:-1],text[-1])
+ elif(text[0]=="R") :
+ text = "%s.%s()" % (text[:-3],text[-3:])
+ elif(text[0]=="s") :
+ text = "%s.%s()" % (text[:-2],text[-2:])
elif text not in []:
self.symbols.add(text)
self.result.append(text)
def visit_Mult(self,node):
self.result.append('*')
def visit_Add(self,node):
self.result.append('+')
def visit_Sub(self,node):
self.result.append('-')
def visit_USub(self,node):
self.result.append('-')
def visit_UAdd(self,node):
self.result.append('+')
def visit_Div(self,node):
self.result.append('/')
def visit_Pow(self,node):
err = "Shold never get here. BinaryOp catches Pow calls."
raise PyToCppException(err)
### Helpers
def is_square(node):
"""Check if a Pow object is just a square."""
try:
return node.right.n == 2.0
except:
return False
def is_ii(node):
"""Check if a Call object is just the imaginary unit."""
try:
return ( node.func.id == 'complex'
and node.args[0].n == 0
and node.args[1].n == 1 )
except:
return False
if __name__ == "__main__":
import doctest
doctest.testmod()
diff --git a/Models/Feynrules/python/ufo2peg/general_lorentz.py b/Models/Feynrules/python/ufo2peg/general_lorentz.py
new file mode 100644
--- /dev/null
+++ b/Models/Feynrules/python/ufo2peg/general_lorentz.py
@@ -0,0 +1,3018 @@
+import copy
+from .helpers import SkipThisVertex,def_from_model
+from .converter import py2cpp
+import string,re
+from string import Template
+
+epsValue=[[[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],
+ [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]],
+ [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],
+ [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]],
+ [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],
+ [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]],
+ [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],
+ [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]]]
+
+epsValue[0][1][2][3] = -1.
+epsValue[0][1][3][2] = 1.
+epsValue[0][2][1][3] = 1.
+epsValue[0][2][3][1] = -1.
+epsValue[0][3][1][2] = -1.
+epsValue[0][3][2][1] = 1.
+epsValue[1][0][2][3] = 1.
+epsValue[1][0][3][2] = -1.
+epsValue[1][2][0][3] = -1.
+epsValue[1][2][3][0] = 1.
+epsValue[1][3][0][2] = 1.
+epsValue[1][3][2][0] = -1.
+epsValue[2][0][1][3] = -1.
+epsValue[2][0][3][1] = 1.
+epsValue[2][1][0][3] = 1.
+epsValue[2][1][3][0] = -1.
+epsValue[2][3][0][1] = -1.
+epsValue[2][3][1][0] = 1.
+epsValue[3][0][1][2] = 1.
+epsValue[3][0][2][1] = -1.
+epsValue[3][1][0][2] = -1.
+epsValue[3][1][2][0] = 1.
+epsValue[3][2][0][1] = 1.
+epsValue[3][2][1][0] = -1.
+
+# self contracted tensor propagator
+tPropA=[[],[],[],[]]
+tPropA[0].append(Template("-2. / 3. * (M${iloc}2 + 2 * P${iloc}t ** 2) * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[0].append(Template("-4. / 3. * P${iloc}t * P${iloc}x * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[0].append(Template("-4. / 3. * P${iloc}t * P${iloc}y * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[0].append(Template("-4. / 3. * P${iloc}t * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[1].append(Template("-4. / 3. * P${iloc}t * P${iloc}x * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[1].append(Template(" 2. / 3. * (M${iloc}2 - 2 * P${iloc}x ** 2) * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[1].append(Template("-4. / 3. * P${iloc}x * P${iloc}y * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[1].append(Template("-4. / 3. * P${iloc}x * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[2].append(Template("-4. / 3. * P${iloc}t * P${iloc}y * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[2].append(Template("-4. / 3. * P${iloc}x * P${iloc}y * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[2].append(Template(" 2. / 3. * (M${iloc}2 - 2 * P${iloc}y ** 2) * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[2].append(Template("-4. / 3. * P${iloc}y * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[3].append(Template("-4. / 3. * P${iloc}t * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[3].append(Template("-4. / 3. * P${iloc}x * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[3].append(Template("-4. / 3. * P${iloc}y * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2"))
+tPropA[3].append(Template(" 2. / 3. * (M${iloc}2 - 2 * P${iloc}z ** 2) * (M${iloc}2 -p2)*OM${iloc}**2"))
+
+# tensor propagator 1 index contracted
+tPropB=[[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]]
+tPropB[0][0].append(Template("4. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (1. - OM${iloc} * P${iloc}t ** 2)"))
+tPropB[0][0].append(Template("-2 * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}x - 2. / 3. * (1. - OM${iloc} * P${iloc}t ** 2) * (${V}x - ${dot}*OM${iloc} * P${iloc}x)"))
+tPropB[0][0].append(Template(" -2 * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}y - 2. / 3. * (1. - OM${iloc} * P${iloc}t ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[0][0].append(Template(" -2 * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}z - 2. / 3. * (1. - OM${iloc} * P${iloc}t ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[0][1].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}x / 3. + (1. - OM${iloc} * P${iloc}t ** 2) * (${V}x - ${dot}*OM${iloc} * P${iloc}x)"))
+tPropB[0][1].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1. - OM${iloc} * P${iloc}x ** 2) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}x - ${dot}*OM${iloc} * P${iloc}x) / 3."))
+tPropB[0][1].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y - OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[0][1].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[0][2].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}y / 3. + (1. - OM${iloc} * P${iloc}t ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[0][2].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y - OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x)"))
+tPropB[0][2].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1. - OM${iloc} * P${iloc}y ** 2) - OM${iloc} * P${iloc}t * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) / 3."))
+tPropB[0][2].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[0][3].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}z / 3. + (1. - OM${iloc} * P${iloc}t ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[0][3].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x)"))
+tPropB[0][3].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[0][3].append(Template("(${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1. - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}t * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3."))
+
+tPropB[1][0].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}x / 3. + (1 - OM${iloc} * P${iloc}t ** 2) * (${V}x - ${dot}*OM${iloc} * P${iloc}x)"))
+tPropB[1][0].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}x ** 2) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}x - ${dot}*OM${iloc} * P${iloc}x) / 3."))
+tPropB[1][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y - OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[1][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[1][1].append(Template(" -2*OM${iloc} * P${iloc}t * P${iloc}x * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropB[1][1].append(Template(" 4. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropB[1][1].append(Template(" -2 * (${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}y - 2. / 3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[1][1].append(Template(" -2 * (${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}z - 2. / 3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[1][2].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y"))
+tPropB[1][2].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}y / 3. + (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[1][2].append(Template(" (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}y ** 2) - OM${iloc} * P${iloc}x * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) / 3."))
+tPropB[1][2].append(Template("-(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[1][3].append(Template("-OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z"))
+tPropB[1][3].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}z / 3. + (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[1][3].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[1][3].append(Template("(${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}x * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3."))
+
+tPropB[2][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}y / 3. + (1 - OM${iloc} * P${iloc}t ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[2][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y - OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x)"))
+tPropB[2][0].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}y ** 2) - OM${iloc} * P${iloc}t * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) / 3."))
+tPropB[2][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[2][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y"))
+tPropB[2][1].append(Template("-(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}y / 3. + (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[2][1].append(Template(" (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}y ** 2) - OM${iloc} * P${iloc}x * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) / 3."))
+tPropB[2][1].append(Template("-(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[2][2].append(Template(" -2*OM${iloc} * P${iloc}t * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropB[2][2].append(Template(" -2*OM${iloc} * P${iloc}x * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - 2. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropB[2][2].append(Template("4. / 3. * (${V}y - ${dot}*OM${iloc} * P${iloc}y) * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropB[2][2].append(Template(" -2 * (${V}y - ${dot}*OM${iloc} * P${iloc}y)*OM${iloc} * P${iloc}y * P${iloc}z - 2. / 3. * (-1 - OM${iloc} * P${iloc}y ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[2][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropB[2][3].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropB[2][3].append(Template(" -(${V}y - ${dot}*OM${iloc} * P${iloc}y)*OM${iloc} * P${iloc}y * P${iloc}z / 3. + (-1 - OM${iloc} * P${iloc}y ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[2][3].append(Template(" (${V}y - ${dot}*OM${iloc} * P${iloc}y) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}y * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3."))
+
+tPropB[3][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}z / 3. + (1 - OM${iloc} * P${iloc}t ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[3][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x)"))
+tPropB[3][0].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[3][0].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}t * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3."))
+tPropB[3][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z"))
+tPropB[3][1].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}z / 3. + (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[3][1].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y)"))
+tPropB[3][1].append(Template(" (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}x * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3."))
+tPropB[3][2].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropB[3][2].append(Template("-OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropB[3][2].append(Template(" -(${V}y - ${dot}*OM${iloc} * P${iloc}y)*OM${iloc} * P${iloc}y * P${iloc}z / 3. + (-1 - OM${iloc} * P${iloc}y ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)"))
+tPropB[3][2].append(Template(" (${V}y - ${dot}*OM${iloc} * P${iloc}y) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}y * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3."))
+tPropB[3][3].append(Template(" -2*OM${iloc} * P${iloc}t * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) - 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropB[3][3].append(Template("-2*OM${iloc} * P${iloc}x * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) - 2. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropB[3][3].append(Template("-2*OM${iloc} * P${iloc}y * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) - 2. / 3. * (${V}y - ${dot}*OM${iloc} * P${iloc}y) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropB[3][3].append(Template("4. / 3. * (${V}z - ${dot}*OM${iloc} * P${iloc}z) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+# tensor propagator, no contracted indices
+tPropC=[[[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]],
+ [[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]],
+ [[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]],
+ [[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]]]
+tPropC[0][0][0].append(Template("4./3. * (1 - OM${iloc} * P${iloc}t ** 2) ** 2"))
+tPropC[0][0][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}x"))
+tPropC[0][0][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}y"))
+tPropC[0][0][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}z"))
+tPropC[0][0][1].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}x"))
+tPropC[0][0][1].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[0][0][1].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y"))
+tPropC[0][0][1].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z"))
+tPropC[0][0][2].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}y"))
+tPropC[0][0][2].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y"))
+tPropC[0][0][2].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[0][0][2].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[0][0][3].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}z"))
+tPropC[0][0][3].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z"))
+tPropC[0][0][3].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[0][0][3].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[0][1][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}x"))
+tPropC[0][1][0].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 /3."))
+tPropC[0][1][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3."))
+tPropC[0][1][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3."))
+tPropC[0][1][1].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 /3."))
+tPropC[0][1][1].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[0][1][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[0][1][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[0][1][2].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3."))
+tPropC[0][1][2].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[0][1][2].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[0][1][2].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[0][1][3].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3."))
+tPropC[0][1][3].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[0][1][3].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[0][1][3].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[0][2][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}y"))
+tPropC[0][2][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3."))
+tPropC[0][2][0].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 /3."))
+tPropC[0][2][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[0][2][1].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3."))
+tPropC[0][2][1].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[0][2][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3."))
+tPropC[0][2][1].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[0][2][2].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 /3."))
+tPropC[0][2][2].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3."))
+tPropC[0][2][2].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[0][2][2].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[0][2][3].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[0][2][3].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[0][2][3].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[0][2][3].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[0][3][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}z"))
+tPropC[0][3][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3."))
+tPropC[0][3][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[0][3][0].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 /3."))
+tPropC[0][3][1].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3."))
+tPropC[0][3][1].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[0][3][1].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[0][3][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3."))
+tPropC[0][3][2].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[0][3][2].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[0][3][2].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[0][3][2].append(Template("-OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[0][3][3].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 /3."))
+tPropC[0][3][3].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3."))
+tPropC[0][3][3].append(Template("-OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[0][3][3].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[1][0][0].append(Template(" -4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}x"))
+tPropC[1][0][0].append(Template(" (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 /3."))
+tPropC[1][0][0].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3."))
+tPropC[1][0][0].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3."))
+tPropC[1][0][1].append(Template(" (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 /3."))
+tPropC[1][0][1].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][0][1].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][0][1].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][0][2].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3."))
+tPropC[1][0][2].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][0][2].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[1][0][2].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[1][0][3].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3."))
+tPropC[1][0][3].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][0][3].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[1][0][3].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[1][1][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][1][0].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][1][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][1][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][1][1].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][1][1].append(Template(" 4./3. * (-1 - OM${iloc} * P${iloc}x ** 2) ** 2"))
+tPropC[1][1][1].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}y"))
+tPropC[1][1][1].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}z"))
+tPropC[1][1][2].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][1][2].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}y"))
+tPropC[1][1][2].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[1][1][2].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z + 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[1][1][3].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][1][3].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}z"))
+tPropC[1][1][3].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z + 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[1][1][3].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[1][2][0].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y"))
+tPropC[1][2][0].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][2][0].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3."))
+tPropC[1][2][0].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[1][2][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][2][1].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}y "))
+tPropC[1][2][1].append(Template(" (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 /3. "))
+tPropC[1][2][1].append(Template(" -(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[1][2][2].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3."))
+tPropC[1][2][2].append(Template(" (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 /3. "))
+tPropC[1][2][2].append(Template(" -4./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[1][2][2].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[1][2][3].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[1][2][3].append(Template(" -(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[1][2][3].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[1][2][3].append(Template(" 2*OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[1][3][0].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z"))
+tPropC[1][3][0].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][3][0].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[1][3][0].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3."))
+tPropC[1][3][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[1][3][1].append(Template("-4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}z "))
+tPropC[1][3][1].append(Template("-(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[1][3][1].append(Template("(-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[1][3][2].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[1][3][2].append(Template("-(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[1][3][2].append(Template("2*OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[1][3][2].append(Template("-OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[1][3][3].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3."))
+tPropC[1][3][3].append(Template("(-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[1][3][3].append(Template("-OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[1][3][3].append(Template("-4./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[2][0][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}y "))
+tPropC[2][0][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3. "))
+tPropC[2][0][0].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 /3. "))
+tPropC[2][0][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3. "))
+tPropC[2][0][1].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3. "))
+tPropC[2][0][1].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[2][0][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3."))
+tPropC[2][0][1].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[2][0][2].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 /3. "))
+tPropC[2][0][2].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3."))
+tPropC[2][0][2].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][0][2].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[2][0][3].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3. "))
+tPropC[2][0][3].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[2][0][3].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[2][0][3].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[2][1][0].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y"))
+tPropC[2][1][0].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[2][1][0].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3."))
+tPropC[2][1][0].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[2][1][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[2][1][1].append(Template("-4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}y "))
+tPropC[2][1][1].append(Template("(-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 /3. "))
+tPropC[2][1][1].append(Template("-(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[2][1][2].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3."))
+tPropC[2][1][2].append(Template("(-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 /3. "))
+tPropC[2][1][2].append(Template("-4./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][1][2].append(Template("OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[2][1][3].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[2][1][3].append(Template("-(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[2][1][3].append(Template("OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[2][1][3].append(Template("2*OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[2][2][0].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][0].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][0].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][0].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][1].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][1].append(Template("2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][1].append(Template("-4./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][1].append(Template("2*OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][2].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][2].append(Template("-4./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][2].append(Template("4./3. * (-1 - OM${iloc} * P${iloc}y ** 2) ** 2 "))
+tPropC[2][2][2].append(Template("-4./3. * (-1 - OM${iloc} * P${iloc}y ** 2)*OM${iloc} * P${iloc}y * P${iloc}z "))
+tPropC[2][2][3].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][3].append(Template("2*OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2) "))
+tPropC[2][2][3].append(Template("-4./3. * (-1 - OM${iloc} * P${iloc}y ** 2)*OM${iloc} * P${iloc}y * P${iloc}z "))
+tPropC[2][2][3].append(Template("2*OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[2][3][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[2][3][0].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[2][3][0].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[2][3][0].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[2][3][1].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[2][3][1].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z + 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[2][3][1].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[2][3][1].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[2][3][2].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[2][3][2].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[2][3][2].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}y ** 2)*OM${iloc} * P${iloc}y * P${iloc}z "))
+tPropC[2][3][2].append(Template(" (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[2][3][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[2][3][3].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[2][3][3].append(Template(" (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[2][3][3].append(Template(" -4./3.*OM${iloc} * P${iloc}y * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2) "))
+
+tPropC[3][0][0].append(Template(" -4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}z "))
+tPropC[3][0][0].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3. "))
+tPropC[3][0][0].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3. "))
+tPropC[3][0][0].append(Template(" (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[3][0][1].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3. "))
+tPropC[3][0][1].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[3][0][1].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[3][0][1].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3."))
+tPropC[3][0][2].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3. "))
+tPropC[3][0][2].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[3][0][2].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[3][0][2].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[3][0][3].append(Template(" (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[3][0][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3."))
+tPropC[3][0][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[3][0][3].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[3][1][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z"))
+tPropC[3][1][0].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[3][1][0].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[3][1][0].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3."))
+tPropC[3][1][1].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)"))
+tPropC[3][1][1].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}z "))
+tPropC[3][1][1].append(Template(" -(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[3][1][1].append(Template(" (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[3][1][2].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z "))
+tPropC[3][1][2].append(Template(" -(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3."))
+tPropC[3][1][2].append(Template(" 2*OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[3][1][2].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[3][1][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3."))
+tPropC[3][1][3].append(Template(" (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[3][1][3].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[3][1][3].append(Template(" -4./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2) "))
+
+tPropC[3][2][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[3][2][0].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[3][2][0].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[3][2][0].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[3][2][1].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z"))
+tPropC[3][2][1].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z + 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[3][2][1].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[3][2][1].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[3][2][2].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[3][2][2].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)"))
+tPropC[3][2][2].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}y ** 2)*OM${iloc} * P${iloc}y * P${iloc}z"))
+tPropC[3][2][2].append(Template(" (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[3][2][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[3][2][3].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3."))
+tPropC[3][2][3].append(Template(" (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 /3. "))
+tPropC[3][2][3].append(Template(" -4./3.*OM${iloc} * P${iloc}y * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+
+tPropC[3][3][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][0].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2) "))
+tPropC[3][3][1].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][1].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][1].append(Template(" 2*OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][1].append(Template(" -4./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2) "))
+tPropC[3][3][2].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][2].append(Template(" 2*OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][2].append(Template(" 2*OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][2].append(Template(" -4./3.*OM${iloc} * P${iloc}y * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][3].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][3].append(Template(" -4./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][3].append(Template(" -4./3.*OM${iloc} * P${iloc}y * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)"))
+tPropC[3][3][3].append(Template(" 4./3. * (-1 - OM${iloc} * P${iloc}z ** 2) ** 2"))
+
+imap=["t","x","y","z"]
+
+RSDotProduct = Template("${s}ts${si}*${v}t-${s}xs${si}*${v}x-${s}ys${si}*${v}y-${s}zs${si}*${v}z")
+
+vTemplateT="""\
+{header} {{
+ if({type}W{iloc}.id()=={id}) {{
+ return {normal};
+ }}
+ else {{
+ return {transpose};
+ }}
+ }};
+"""
+
+vTemplate4="""\
+{header} {{
+{swap}
+ if(id{iloc1}=={id1}) {{
+ if(id{iloc2}=={id2}) {{
+ return {res1};
+ }}
+ else {{
+ return {res2};
+ }}
+ }}
+ else {{
+ if(id{iloc2}=={id2}) {{
+ return {res3};
+ }}
+ else {{
+ return {res4};
+ }}
+ }}
+}};
+
+"""
+
+vecTemplate="""\
+ Energy2 p2 = P{iloc}.m2();
+ LorentzPolarizationVector vtemp = {res};
+ Complex fact = -Complex(0.,1.)*({cf})*propagator(iopt,p2,out,mass,width);
+ if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass();
+ complex<Energy2> mass2 = sqr(mass);
+ if(mass.real()==ZERO) {{
+ vtemp =fact*vtemp;
+ }}
+ else {{
+ complex<Energy> dot = P{iloc}*vtemp;
+ vtemp = fact*(vtemp-dot/mass2*P{iloc});
+ }}
+ return VectorWaveFunction(P{iloc},out,vtemp.x(),vtemp.y(),vtemp.z(),vtemp.t());
+"""
+
+
+sTemplate="""\
+ Energy2 p2 = P{iloc}.m2();
+ if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass();
+ Complex fact = Complex(0.,1.)*({cf})*propagator(iopt,p2,out,mass,width);
+ Lorentz{offTypeA}<double> newSpin = fact*({res});
+ return {offTypeB}(P{iloc},out,newSpin);
+"""
+
+RSTemplate="""\
+ if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass();
+ Energy2 p2 = P{iloc}.m2();
+ Complex fact = Complex(0.,-1.)*({cf})*propagator(iopt,p2,out,mass,width);
+ complex<InvEnergy> Omass = mass.real()==ZERO ? InvEnergy(ZERO) : 1./mass;
+ Lorentz{offTypeA}<double> newSpin = fact*({res});
+ return {offTypeB}(P{iloc},out,newSpin);
+"""
+
+scaTemplate="""\
+ if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass();
+ Energy2 p2 = P{iloc}.m2();
+ Complex fact = Complex(0.,1.)*({cf})*propagator(iopt,p2,out,mass,width);
+ complex<double> output = fact*({res});
+ return ScalarWaveFunction(P{iloc},out,output);
+"""
+
+tenTemplate="""\
+ if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass();
+ InvEnergy2 OM{iloc} = mass.real()==ZERO ? InvEnergy2(ZERO) : 1./sqr(mass.real());
+ Energy2 M{iloc}2 = sqr(mass.real());
+ Energy2 p2 = P{iloc}.m2();
+ Complex fact = Complex(0.,1.)*({cf})*propagator(iopt,p2,out,mass,width);
+ LorentzTensor<double> output = fact*({res});
+ return TensorWaveFunction(P{iloc},out,output);
+"""
+
+# various strings for matrixes
+I4 = "Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]])"
+G5 = "Matrix([[-1.,0,0,0],[0,-1.,0,0],[0,0,1.,0],[0,0,0,1.]])"
+PM = "Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,0,0],[0,0,0,0]])"
+PP = "Matrix([[0,0,0,0],[0,0,0,0],[0,0,1.,0],[0,0,0,1.]])"
+
+
+vslash = Template("Matrix([[0,0,${v}TMZ,-${v}XMY],[0,0,-${v}XPY,${v}TPZ],[${v}TPZ,${v}XMY,0,0],[${v}XPY,${v}TMZ,0,0]])")
+vslashS = Template("${v}TPZ=Symbol(\"${v}TPZ\")\n${v}TMZ=Symbol(\"${v}TMZ\")\n${v}XPY=Symbol(\"${v}XPY\")\n${v}XMY=Symbol(\"${v}XMY\")\n")
+momCom = Template("${v}t = Symbol(\"${v}t\")\n${v}x = Symbol(\"${v}x\")\n${v}y = Symbol(\"${v}y\")\n${v}z = Symbol(\"${v}z\")\n")
+vslashD = Template("complex<${var}> ${v}TPZ = ${v}.t()+${v}.z();\n complex<${var}> ${v}TMZ = ${v}.t()-${v}.z();\n complex<${var}> ${v}XPY = ${v}.x()+Complex(0.,1.)*${v}.y();\n complex<${var}> ${v}XMY = ${v}.x()-Complex(0.,1.)*${v}.y();")
+vslashM = Template("Matrix([[$m,0,${v}TMZ,-${v}XMY],[0,$m,-${v}XPY,${v}TPZ],[${v}TPZ,${v}XMY,$m,0],[${v}XPY,${v}TMZ,0,$m]])")
+vslashM2 = Template("Matrix([[$m,0,-${v}TMZ,${v}XMY],[0,$m,${v}XPY,-${v}TPZ],[-${v}TPZ,-${v}XMY,$m,0],[-${v}XPY,-${v}TMZ,0,$m]])")
+vslashMS = Template("${v}TPZ=Symbol(\"${v}TPZ\")\n${v}TMZ=Symbol(\"${v}TMZ\")\n${v}XPY=Symbol(\"${v}XPY\")\n${v}XMY=Symbol(\"${v}XMY\")\n${m}=Symbol(\"${m}\")\nO${m}=Symbol(\"O${m}\")\n")
+
+rslash = Template("Matrix([[$m,0,${v}TMZ,-${v}XMY],[0,$m,-${v}XPY,${v}TPZ],[${v}TPZ,${v}XMY,$m,0],[${v}XPY,${v}TMZ,0,$m]])*( ($${eta}-2./3.*O${m}**2*${v}$${A}*${v}$${B})*Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]]) -1./3.*$${DA}*$${DB} -1./3.*O${m}*(${v}$${B}*$${DA}-${v}$${A}*$${DB}))")
+rslashB = Template("Matrix([[$m,0,${v}TMZ,-${v}XMY],[0,$m,-${v}XPY,${v}TPZ],[${v}TPZ,${v}XMY,$m,0],[${v}XPY,${v}TMZ,0,$m]])*( (${v2}$${A}-2./3.*O${m}**2*${v}$${A}*${dot})*Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]]) -1./3.*$${DA}*${DB} -1./3.*O${m}*(${dot}*$${DA}-${v}$${A}*${DB}))")
+
+
+
+rslash2 = Template("Matrix([[$m,0,-${v}TMZ,${v}XMY],[0,$m,${v}XPY,-${v}TPZ],[-${v}TPZ,-${v}XMY,$m,0],[-${v}XPY,-${v}TMZ,0,$m]])*( ($${eta}-2./3.*O${m}**2*${v}$${A}*${v}$${B})*Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]]) -1./3.*$${DA}*$${DB} +1./3.*O${m}*(${v}$${B}*$${DA}-${v}$${A}*$${DB}))")
+rslash2B = Template("Matrix([[$m,0,-${v}TMZ,${v}XMY],[0,$m,${v}XPY,-${v}TPZ],[-${v}TPZ,-${v}XMY,$m,0],[-${v}XPY,-${v}TMZ,0,$m]])*( (${v2}$${B}-2./3.*O${m}**2*${dot}*${v}$${B})*Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]]) -1./3.*${DA}*$${DB} +1./3.*O${m}*(${v}$${B}*${DA}-${dot}*$${DB}))")
+
+dirac=["Matrix([[0,0,1.,0],[0,0,0,1.],[1.,0,0,0],[0,1.,0,0]])","Matrix([[0,0,0,1.],[0,0,1.,0],[0,-1.,0,0],[-1.,0,0,0]])",
+ "Matrix([[0,0,0,complex(0, -1.)],[0,0,complex(0, 1.),0],[0,complex(0, 1.),0,0],[complex(0, -1.),0,0,0]])",
+ "Matrix([[0,0,1.,0],[0,0,0,-1.],[-1.,0,0,0],[0,1.,0,0]])"]
+CC = "Matrix([[0,1.,0,0],[-1.,0,0,0],[0,0,0,-1.],[0,0,1.,0]])"
+CD = "Matrix([[0,-1.,0,0],[1.,0,0,0],[0,0,0,1.],[0,0,-1.,0]])"
+
+evaluateTemplate = """\
+{decl} {{
+ {momenta}
+ {waves}
+{swap}
+ {symbols}
+ {couplings}
+{defns}
+ {result}
+}}
+"""
+spinor = Template("Matrix([[${s}s1],[${s}s2],[${s}s3],[${s}s4]])")
+sbar = Template("Matrix([[${s}s1,${s}s2,${s}s3,${s}s4]])")
+sline = Template("${s}s1=Symbol(\"${s}s1\")\n${s}s2=Symbol(\"${s}s2\")\n${s}s3=Symbol(\"${s}s3\")\n${s}s4=Symbol(\"${s}s4\")\n")
+
+RSSpinorTemplate = Template("${type}<double>(${outxs1},\n${outxs2},\n${outxs3},\n${outxs4},\n${outys1},\n${outys2},\n${outys3},\n${outys4},\n${outzs1},\n${outzs2},\n${outzs3},\n${outzs4},\n${outts1},\n${outts2},\n${outts3},\n${outts4})")
+SpinorTemplate = Template("${type}<double>(${outs1},\n${outs2},\n${outs3},\n${outs4})")
+
+class LorentzIndex :
+ """ A simple classs to store a Lorentz index """
+ type=""
+ value=0
+ dimension=0
+ def __repr__(self):
+ if(self.type=="V" and not isinstance(self.value,int)) :
+ return self.value
+ else :
+ return "%s%s" % (self.type,self.value)
+
+ def __init__(self,val) :
+ if(isinstance(val,int)) :
+ self.dimension=0
+ if(val<0) :
+ self.type="D"
+ self.value = val
+ elif(val>0 and val/1000==0) :
+ self.type="E"
+ self.value = val
+ elif(val>0 and val/1000==1) :
+ self.type="T1"
+ self.value = val%1000
+ elif(val>0 and val/1000==2) :
+ self.type="T2"
+ self.value = val%1000
+ else :
+ print "Unknown value in Lorentz index:",val
+ raise SkipThisVertex()
+ else :
+ print "Unknown value in Lorentz index:",val
+ raise SkipThisVertex()
+
+ def __eq__(self,other):
+ if(not isinstance(other,LorentzIndex)) :
+ return False
+ return ( (self.type, self.value)
+ == (other.type, other.value) )
+
+ def __hash__(self) :
+ return hash((self.type,self.value))
+
+class DiracMatrix:
+ """A simple class to store Dirac matrices"""
+ name =""
+ value=""
+ index=0
+ def __init(self) :
+ self.name=""
+ self.value=""
+ self.index=0
+
+ def __repr__(self) :
+ if(self.value==0) :
+ return "%s" % self.index
+ else :
+ return "%s" % self.value
+
+class LorentzStructure:
+ """A simple class to store a Lorentz structures"""
+ name=""
+ value=0
+ lorentz=[]
+ spin=[]
+
+ def __init(self) :
+ self.name=""
+ self.value=0
+ self.lorentz=[]
+ self.spin=[]
+
+ def __repr__(self):
+ output = self.name
+ if((self.name=="P" or self.name=="Tensor") and self.value!=0) :
+ output += "%s" % self.value
+ if(self.name=="int" or self.name=="sign") :
+ output += "=%s" % self.value
+ elif(len(self.spin)==0) :
+ output += "("
+ for val in self.lorentz :
+ output += "%s," % val
+ output=output.rstrip(",")
+ output+=")"
+ elif(len(self.lorentz)==0) :
+ output += "("
+ for val in self.spin :
+ output += "%s," % val
+ output=output.rstrip(",")
+ output+=")"
+ else :
+ output += "("
+ for val in self.lorentz :
+ output += "%s," % val
+ for val in self.spin :
+ output += "%s," % val
+ output=output.rstrip(",")
+ output+=")"
+ return output
+
+def LorentzCompare(a,b) :
+ if(a.name=="int" and b.name=="int") :
+ return int(abs(b.value)-abs(a.value))
+ elif(a.name=="int") :
+ return -1
+ elif(b.name=="int") :
+ return 1
+ elif(len(a.spin)==0) :
+ if(len(b.spin)==0) :
+ return len(b.lorentz)-len(a.lorentz)
+ else :
+ return -1
+ elif(len(b.spin)==0) :
+ return 1
+ else :
+ if(len(a.spin)==0 or len(b.spin)==0) :
+ print 'Index problem in lorentz compare',\
+ a.name,b.name,a.spin,b.spin
+ raise SkipThisVertex()
+ if(a.spin[0]>0 or b.spin[1]>0 ) : return -1
+ if(a.spin[1]>0 or b.spin[0]>0 ) : return 1
+ if(a.spin[1]==b.spin[0]) : return -1
+ if(b.spin[1]==a.spin[0]) : return 1
+ return 0
+
+def extractIndices(struct) :
+ if(struct.find("(")<0) : return []
+ temp=struct.split("(")[1].split(")")[0].split(",")
+ output=[]
+ for val in temp :
+ output.append(int(val))
+ return output
+
+def parse_structure(structure,spins) :
+ output=[]
+ found = True
+ while(found) :
+ found = False
+ # signs between terms
+ if(structure=="+" or structure=="-") :
+ output.append(LorentzStructure())
+ output[0].name="sign"
+ output[0].value=structure[0]+"1."
+ output[0].value=float(output[0].value)
+ output[0].lorentz=[]
+ output[0].spin=[]
+ return output
+ # simple numeric pre/post factors
+ elif((structure[0]=="-" or structure[0]=="+") and
+ structure[-1]==")" and structure[1]=="(") :
+ output.append(LorentzStructure())
+ output[-1].name="int"
+ output[-1].value=structure[0]+"1."
+ output[-1].value=float(output[-1].value)
+ output[-1].lorentz=[]
+ output[-1].spin=[]
+ structure=structure[2:-1]
+ found=True
+ elif(structure[0]=="(") :
+ temp=structure.rsplit(")",1)
+ structure=temp[0][1:]
+ output.append(LorentzStructure())
+ output[-1].name="int"
+ output[-1].value="1."+temp[1]
+ output[-1].value=float(eval(output[-1].value))
+ output[-1].lorentz=[]
+ output[-1].spin=[]
+ found=True
+ elif(structure[0:2]=="-(") :
+ temp=structure.rsplit(")",1)
+ structure=temp[0][2:]
+ output.append(LorentzStructure())
+ output[-1].name="int"
+ output[-1].value="-1."+temp[1]
+ output[-1].value=float(eval(output[-1].value))
+ output[-1].lorentz=[]
+ output[-1].spin=[]
+ found=True
+ # special handling for powers
+ power = False
+ if("**" in structure ) :
+ power = True
+ structure = structure.replace("**","^")
+ structures = structure.split("*")
+ if(power) :
+ for j in range(0,len(structures)):
+ if(structures[j].find("^")>=0) :
+ temp = structures[j].split("^")
+ structures[j] = temp[0]
+ for i in range(0,int(temp[1])-1) :
+ structures.append(temp[0])
+ # split up the structure
+ for struct in structures:
+ ind = extractIndices(struct)
+ # different types of object
+ # object with only spin indices
+ if(struct.find("Identity")==0 or
+ struct.find("Proj")==0 or
+ struct.find("Gamma5")==0) :
+ output.append(LorentzStructure())
+ output[-1].spin=ind
+ output[-1].lorentz=[]
+ output[-1].name=struct.split("(")[0]
+ output[-1].value=0
+ if(len(struct.replace("%s(%s,%s)" % (output[-1].name,ind[0],ind[1]),""))!=0) :
+ print "Problem handling %s structure " % output[-1].name
+ raise SkipThisVertex()
+ # objects with 2 lorentz indices
+ elif(struct.find("Metric")==0) :
+ output.append(LorentzStructure())
+ output[-1].lorentz=[LorentzIndex(ind[0]),LorentzIndex(ind[1])]
+ output[-1].name=struct.split("(")[0]
+ output[-1].value=0
+ output[-1].spin=[]
+ if(len(struct.replace("%s(%s,%s)" % (output[-1].name,ind[0],ind[1]),""))!=0) :
+ print "Problem handling %s structure " % output[-1].name
+ raise SkipThisVertex()
+ elif(struct.find("P(")==0) :
+ output.append(LorentzStructure())
+ output[-1].lorentz=[LorentzIndex(ind[0])]
+ output[-1].name=struct.split("(")[0]
+ output[-1].value=ind[1]
+ output[-1].spin=[]
+ if(len(struct.replace("%s(%s,%s)" % (output[-1].name,ind[0],ind[1]),""))!=0) :
+ print "Problem handling %s structure " % output[-1].name
+ raise SkipThisVertex()
+ # 1 lorentz and 1 spin index
+ elif(struct.find("Gamma")==0) :
+ output.append(LorentzStructure())
+ output[-1].lorentz=[LorentzIndex(ind[0])]
+ output[-1].spin=[ind[1],ind[2]]
+ output[-1].name=struct.split("(")[0]
+ output[-1].value=1
+ if(len(struct.replace("%s(%s,%s,%s)" % (output[-1].name,ind[0],ind[1],ind[2]),""))!=0) :
+ print "problem parsing gamma matrix",struct
+ raise SkipThisVertex()
+ # objects with 4 lorentz indices
+ elif(struct.find("Epsilon")==0) :
+ output.append(LorentzStructure())
+ output[-1].lorentz=[]
+ for i in range(0,len(ind)) :
+ output[-1].lorentz.append(LorentzIndex(ind[i]))
+ output[-1].spin=[]
+ output[-1].name=struct.split("(")[0]
+ output[-1].value=1
+ if(len(struct.replace("%s(%s,%s,%s,%s)" % (output[-1].name,ind[0],ind[1],ind[2],ind[3]),""))!=0) :
+ print 'Problem parsing epsilon',struct
+ raise SkipThisVertex()
+ # scalars
+ else :
+ try :
+ output.append(LorentzStructure())
+ output[-1].value=float(struct)
+ output[-1].name="int"
+ output[-1].lorentz=[]
+ output[-1].spin=[]
+ except :
+ if(struct.find("complex")==0) :
+ vals = struct[0:-1].replace("complex(","").split(",")
+ output[-1].value=complex(float(vals[0]),float(vals[1]))
+ output[-1].name="int"
+ output[-1].lorentz=[]
+ output[-1].spin=[]
+ else :
+ print 'Problem parsing scalar',struct
+ raise SkipThisVertex()
+ # now do the sorting
+ if(len(output)==1) : return output
+ output = sorted(output,cmp=LorentzCompare)
+ # fix indices in the RS case
+ if(4 in spins) :
+ for i in range(0,len(output)) :
+ for ll in range(0,len(output[i].lorentz)) :
+ if(spins[output[i].lorentz[ll].value-1]==4 and
+ output[i].lorentz[ll].type=="E") :
+ output[i].lorentz[ll].type="R"
+ # return the answer
+ return output
+
+def constructDotProduct(ind1,ind2,defns) :
+ (ind1,ind2) = sorted((ind1,ind2),cmp=indSort)
+ dimension=ind1.dimension+ind2.dimension
+ # this product already dealt with ?
+ if((ind1,ind2) in defns) :
+ name = defns[(ind1,ind2)][0]
+ # handle the product
+ else :
+ name = "dot%s" % (len(defns)+1)
+ unit = computeUnit(dimension)
+ defns[(ind1,ind2)] = [name,"complex<%s> %s = %s*%s;" % (unit,name,ind1,ind2)]
+ return (name,dimension)
+
+def contract(parsed) :
+ for j in range(0,len(parsed)) :
+ if(parsed[j]=="") : continue
+ if(parsed[j].name=="P") :
+ # simplest case
+ if(parsed[j].lorentz[0].type=="E" or
+ parsed[j].lorentz[0].type=="P") :
+ newIndex = LorentzIndex(parsed[j].value)
+ newIndex.type="P"
+ newIndex.dimension=1
+ parsed[j].name="Metric"
+ parsed[j].lorentz.append(newIndex)
+ parsed[j].lorentz = sorted(parsed[j].lorentz,cmp=indSort)
+ continue
+ ll=1
+ found=False
+ for k in range(0,len(parsed)) :
+ if(j==k or parsed[k]=="" ) : continue
+ for i in range(0,len(parsed[k].lorentz)) :
+ if(parsed[k].lorentz[i] == parsed[j].lorentz[0]) :
+ parsed[k].lorentz[i].type="P"
+ parsed[k].lorentz[i].value = parsed[j].value
+ parsed[k].lorentz[i].dimension=1
+ if(parsed[k].name=="P") :
+ parsed[k].lorentz.append(LorentzIndex(parsed[k].value))
+ parsed[k].lorentz[1].type="P"
+ parsed[k].lorentz[1].dimension=1
+ parsed[k].name="Metric"
+ parsed[k].value = 0
+ found=True
+ break
+ if(found) :
+ parsed[j]=""
+ break
+ return [x for x in parsed if x != ""]
+
+def computeUnit(dimension) :
+ if(isinstance(dimension,int)) :
+ dtemp = dimension
+ else :
+ dtemp=dimension[1]+dimension[2]
+ if(dtemp==0) :
+ unit="double"
+ elif(dtemp==1) :
+ unit="Energy"
+ elif(dtemp==-1) :
+ unit="InvEnergy"
+ elif(dtemp>0) :
+ unit="Energy%s" % (dtemp)
+ elif(dtemp<0) :
+ unit="InvEnergy%s" % (dtemp)
+ return unit
+
+def computeUnit2(dimension,vDim) :
+ # first correct for any coupling power in vertex
+ totalDim = int(dimension[0])+dimension[2]+vDim-4
+ output=""
+ if(totalDim!=0) :
+ if(totalDim>0) :
+ if(totalDim==1) :
+ output = "1./GeV"
+ elif(totalDim==2) :
+ output = "1./GeV2"
+ else :
+ output="1."
+ for i in range(0,totalDim) :
+ output +="/GeV"
+ else :
+ if(totalDim==-1) :
+ output = "GeV"
+ elif(totalDim==-2) :
+ output = "GeV2"
+ else :
+ output="1."
+ for i in range(0,-totalDim) :
+ output +="*GeV"
+ expr=""
+ # now remove the remaining dimensionality
+ removal=dimension[1]-int(dimension[0])-vDim+4
+ if(removal!=0) :
+ if(removal>0) :
+ if(removal==1) :
+ expr = "UnitRemovalInvE"
+ else :
+ expr = "UnitRemovalInvE%s" % removal
+ else :
+ if(removal==-1) :
+ expr = "UnitRemovalE"
+ else :
+ expr = "UnitRemovalE%s" % (-removal)
+ if(output=="") : return expr
+ elif(expr=="") : return output
+ else : return "%s*%s" %(output,expr)
+
+# order the indices of a dot product
+def indSort(a,b) :
+ if(not isinstance(a,LorentzIndex) or
+ not isinstance(b,LorentzIndex)) :
+ print "Trying to sort something that's not a Lorentz index",a,b
+ raise SkipThisVertex()
+ if(a.type==b.type) :
+ i1=a.value
+ i2=b.value
+ if(i1>i2) :
+ return 1
+ elif(i1<i2) :
+ return -1
+ else :
+ return 0
+ else :
+ if(a.type=="E") :
+ return 1
+ else :
+ return -1
+
+def finishParsing(parsed,dimension,lorentztag,iloc,defns,eps) :
+ output=1.
+ # replace signs
+ if(len(parsed)==1 and parsed[0].name=="sign") :
+ if(parsed[0].value>0) :
+ output="+"
+ else :
+ output="-"
+ parsed=[]
+ return (output,parsed,dimension,eps)
+ # replace integers (really lorentz scalars)
+ for j in range(0,len(parsed)) :
+ if(parsed[j]!="" and parsed[j].name=="int") :
+ output *= parsed[j].value
+ parsed[j]=""
+ # bracket this for safety
+ if(output!="") : output = "(%s)" % output
+ # special for tensor indices
+ if("T" in lorentztag) :
+ for j in range(0,len(parsed)) :
+ if(parsed[j]=="") :continue
+ # check for tensor index
+ found=False
+ for li in parsed[j].lorentz :
+ if(li.type[0]=="T") :
+ index = li
+ found=True
+ break
+ if(not found) : continue
+ # workout the other index for the tensor
+ index2 = LorentzIndex(li.value)
+ if(index.type=="T1") :
+ index2.type="T2"
+ else :
+ index2.type="T1"
+ # special is tensor contracted with itself
+ if(parsed[j].name=="Metric" and index2 == parsed[j].lorentz[1]) :
+ parsed[j].name = "Tensor"
+ parsed[j].value = index.value
+ parsed[j].lorentz = []
+ if(iloc!=index.value) :
+ name= "traceT%s" % parsed[j].value
+ if( name in defns ) :
+ output += "*(%s)" % defns[name][0]
+ else :
+ defns[name] = [name,"Complex %s = T%s.trace();" % (name,parsed[j].value)]
+ output += "*(%s)" % defns[name][0]
+ parsed[j]=""
+ continue
+ # otherwise search for the match
+ for k in range(j+1,len(parsed)) :
+ found = False
+ for li in parsed[k].lorentz :
+ if(li == index2) :
+ found=True
+ break
+ if(not found) : continue
+ if(parsed[j].name=="P") :
+ newIndex1 = LorentzIndex(parsed[j].value)
+ newIndex1.type="P"
+ newIndex1.dimension=1
+ elif(parsed[j].name=="Metric") :
+ for li in parsed[j].lorentz :
+ if(li != index) :
+ newIndex1=li
+ break
+ else :
+ print 'Unknown object with tensor index, first object',parsed[j]
+ raise SkipThisVertex()
+ if(parsed[k].name=="P") :
+ newIndex2 = LorentzIndex(parsed[k].value)
+ newIndex2.type="P"
+ newIndex2.dimension=1
+ elif(parsed[k].name=="Metric") :
+ for li in parsed[k].lorentz :
+ if(li != index) :
+ newIndex2=li
+ break
+ elif(parsed[k].name=="Gamma") :
+ # if we can't contract
+ if(index.value==iloc or (newIndex1.type=="E" and newIndex1.value==iloc)) :
+ newIndex2=index2
+ # otherwise contract
+ else :
+ unit=computeUnit(newIndex1.dimension)
+ if(index.type=="T1") :
+ name="T%s%sF" % (index.value,newIndex1)
+ defns[name] = [name,"LorentzVector<complex<%s> > %s = T%s.preDot(%s);" % (unit,name,index.value,newIndex1)]
+ else :
+ name="T%s%sS" % (index.value,newIndex1)
+ defns[name] = [name,"LorentzVector<complex<%s> > %s = T%s.postDot(%s);" % (unit,name,index.value,newIndex1)]
+ parsed[j]=""
+ gIndex=LorentzIndex(-1)
+ gIndex.type="V"
+ gIndex.value=name
+ gIndex.dimension=newIndex1.dimension
+ parsed[k].lorentz[0] = gIndex
+ break
+ else :
+ print 'Unknown object with tensor index, second object',parsed[j],parsed[k]
+ raise SkipThisVertex()
+ if(index2.type=="T1") :
+ newIndex1,newIndex2=newIndex2,newIndex1
+ parsed[j].name = "Tensor"
+ parsed[j].value= int(index.value)
+ parsed[j].lorentz= [newIndex1,newIndex2]
+ if(parsed[k].name!="Gamma") : parsed[k]=""
+ break
+ # main handling of lorentz structures
+ for j in range(0,len(parsed)) :
+ if(parsed[j]=="") : continue
+ if(parsed[j].name=="Metric") :
+ # check whether or not we can contract
+ canContract=True
+ for ll in parsed[j].lorentz :
+ if((ll.type=="E" and ll.value==iloc) or ll.type=="R") :
+ canContract = False
+ break
+ if(not canContract) : continue
+ # if we can do it
+ (name,dTemp) = constructDotProduct(parsed[j].lorentz[0],parsed[j].lorentz[1],defns)
+ output += "*(%s)" % name
+ dimension[2] += dTemp
+ parsed[j]=""
+ elif(parsed[j].name=="Epsilon") :
+ if(not eps) : eps = True
+ # work out which, if any of the indices can be summed over
+ summable=[]
+ for ix in range(0,len(parsed[j].lorentz)) :
+ if(parsed[j].lorentz[ix].type=="P" or
+ (parsed[j].lorentz[ix].type=="E" and iloc !=parsed[j].lorentz[ix].value)) :
+ summable.append(True)
+ else :
+ summable.append(False)
+ sc = summable.count(True)
+ # less than 3 contractable indices, leave for later
+ if(sc<3) :
+ continue
+ # can contract to a vector
+ elif(sc==3) :
+ offLoc = -1
+ for i in range(0,len(summable)):
+ if(not summable[i]) :
+ offLoc = i
+ break
+ else :
+ offLoc = 0
+ indices=[]
+ dTemp=0
+ for ix in range(0,len(parsed[j].lorentz)) :
+ dTemp += parsed[j].lorentz[ix].dimension
+ if(ix!=offLoc) : indices.append(parsed[j].lorentz[ix])
+ # contract all the indices
+ if(sc==4) :
+ dimension[2] += dTemp
+ iTemp = (parsed[j].lorentz[0],parsed[j].lorentz[1],
+ parsed[j].lorentz[2],parsed[j].lorentz[3])
+ if(iTemp in defns) :
+ output += "*(%s)" % defns[iTemp][0]
+ parsed[j]=""
+ else :
+ name = "dot%s" % (len(defns)+1)
+ unit = computeUnit(dTemp)
+ defns[iTemp] = [name,"complex<%s> %s =-%s*epsilon(%s,%s,%s);" % (unit,name,parsed[j].lorentz[0],
+ indices[0],indices[1],indices[2]) ]
+ output += "*(%s)" % name
+ parsed[j]=""
+ # contract 3 indices leaving a vector
+ else :
+ iTemp = (indices[0],indices[1],indices[2])
+ sign = "1"
+ if(offLoc%2!=0) : sign="-1"
+ if(iTemp in defns) :
+ name = defns[iTemp][0]
+ else :
+ name = "V%s" % (len(defns)+1)
+ unit = computeUnit(dTemp)
+ defns[iTemp] = [name,"LorentzVector<complex<%s> > %s =-epsilon(%s,%s,%s);" % (unit,name,
+ indices[0],indices[1],indices[2]) ]
+ newIndex = LorentzIndex(int(name[1:]))
+ newIndex.type="V"
+ newIndex.dimension=dTemp
+ output += "*(%s)" % (sign)
+ oi = parsed[j].lorentz[offLoc]
+ if(oi.type!="D") :
+ parsed[j].name="Metric"
+ parsed[j].spins=[]
+ parsed[j].value=0
+ parsed[j].lorentz=[newIndex,oi]
+ else :
+ found=False
+ for k in range(0,len(parsed)):
+ if(k==j or parsed[k]=="") : continue
+ for ll in range(0,len(parsed[k].lorentz)) :
+ if(parsed[k].lorentz[ll]==oi) :
+ found=True
+ parsed[k].lorentz[ll]=newIndex
+ break
+ if(found) : break
+ if(not found) :
+ print "Problem contracting indices of Epsilon tensor"
+ raise SkipThisVertex()
+ parsed[j]=""
+ elif(parsed[j].name=="Tensor") :
+ # not an external tensor
+ if(parsed[j].value!=iloc) :
+ # now check the lorentz indices
+ con=[]
+ uncon=[]
+ dtemp=0
+ for li in parsed[j].lorentz :
+ if(li.type=="P" or li.type=="V") :
+ con.append(li)
+ dtemp+=li.dimension
+ elif(li.type=="E") :
+ if(li.value!=iloc) :
+ con.append(li)
+ else :
+ uncon.append(li)
+ else :
+ print "Can't handle index ",li,"in tensor",parsed[j]
+ raise SkipThisVertex()
+ if(len(con)==2) :
+ iTemp = ("T%s%s%s"% (parsed[j].value,con[0],con[1]))
+ dimension[2]+=dtemp
+ if(iTemp in defns) :
+ output += "*(%s)" % defns[iTemp][0]
+ else :
+ unit=computeUnit(dtemp)
+ name = "dot%s" % (len(defns)+1)
+ defns[iTemp] = [name,"complex<%s> %s = T%s.preDot(%s)*%s;" % (unit,name,parsed[j].value,con[0],con[1])]
+ output += "*(%s)" % name
+ parsed[j]=""
+ # handled in final stage
+ else :
+ continue
+ elif(parsed[j].name.find("Proj")>=0 or
+ parsed[j].name.find("Gamma")>=0 or
+ parsed[j].name.find("Identity")>=0) :
+ continue
+ elif(parsed[j].name=="P" and parsed[j].lorentz[0].type=="R") :
+ continue
+ else :
+ print 'Lorentz structure',parsed[j],'not handled'
+ raise SkipThisVertex()
+ # remove leading *
+ if(output!="" and output[0]=="*") : output = output[1:]
+ # remove any (now) empty elements
+ parsed = [x for x in parsed if x != ""]
+ return (output,parsed,dimension,eps)
+
+def finalContractions(output,parsed,dimension,lorentztag,iloc,defns) :
+ if(len(parsed)==0) :
+ return (output,dimension)
+ elif(len(parsed)!=1) :
+ print "Summation can't be handled",parsed
+ raise SkipThisVertex()
+ if(parsed[0].name=="Tensor") :
+ # contracted with off-shell vector
+ if(parsed[0].value!=iloc) :
+ found = False
+ for ll in parsed[0].lorentz :
+ if(ll.type=="E" and ll.value==iloc) :
+ found = True
+ else :
+ lo=ll
+ if(found) :
+ dimension[2]+= lo.dimension
+ unit=computeUnit(lo.dimension)
+ if(lo==parsed[0].lorentz[0]) :
+ name="T%s%sF" % (parsed[0].value,lo)
+ defns[name] = [name,"LorentzVector<complex<%s> > %s = T%s.preDot(%s);" % (unit,name,parsed[0].value,lo)]
+ else :
+ name="T%s%sS" % (parsed[0].value,lo)
+ defns[name] = [name,"LorentzVector<complex<%s> > %s = T%s.postDot(%s);" % (unit,name,parsed[0].value,lo)]
+ parsed[0]=""
+ if(output=="") : output="1."
+ output = "(%s)*(%s)" %(output,name)
+ else :
+ print "Can\'t contract tensor",lo,iloc
+ raise SkipThisVertex()
+ # off-shell tensor
+ else :
+ if(len(parsed[0].lorentz)!=0) :
+ dimension[2]+=parsed[0].lorentz[0].dimension+parsed[0].lorentz[1].dimension
+ tensor = tensorPropagator(parsed[0],defns)
+ if(output=="") : output="1."
+ output = [output,tensor,()]
+ elif(parsed[0].name=="Metric") :
+ found = False
+ for ll in parsed[0].lorentz :
+ if(ll.type=="E" and ll.value==iloc) :
+ found = True
+ else :
+ lo=ll
+ if(found) :
+ parsed[0]=""
+ dimension[2] += lo.dimension
+ if(output=="") : output="1."
+ output = "(%s)*(%s)" %(output,lo)
+ else :
+ print "Structure can't be handled",parsed,iloc
+ raise SkipThisVertex()
+ return (output,dimension)
+
+def tensorPropagator(struct,defns) :
+ # dummy index
+ i0 = LorentzIndex(-1000)
+ # index for momentum of propagator
+ ip = LorentzIndex(struct.value)
+ ip.type="P"
+ ip.dimension=1
+ # the metric tensor
+ terms=[]
+ if(len(struct.lorentz)==0) :
+ (dp,dTemp) = constructDotProduct(ip,ip,defns)
+ pre = "-1./3.*(1.-%s*OM%s)" % (dp,struct.value)
+ terms.append((pre,i0,i0))
+ pre = "-2./3.*(1.-%s*OM%s)" % (dp,struct.value)
+ terms.append(("%s*OM%s" %(pre,struct.value),ip,ip))
+ else :
+ # indices of the tensor
+ ind1 = struct.lorentz[0]
+ ind2 = struct.lorentz[1]
+ # the dot products we need
+ (d1,dtemp) = constructDotProduct(ind1,ip,defns)
+ (d2,dtemp) = constructDotProduct(ind2,ip,defns)
+ (d3,dtemp) = constructDotProduct(ind1,ind2,defns)
+ # various terms in the propagator
+ terms.append(("0.5",ind1,ind2))
+ terms.append(("-0.5*OM%s*%s"%(struct.value,d1),ip,ind2))
+ terms.append(("-0.5*OM%s*%s"%(struct.value,d2),ind1,ip))
+ terms.append(("0.5",ind2,ind1))
+ terms.append(("-0.5*OM%s*%s"%(struct.value,d2),ip,ind1))
+ terms.append(("-0.5*OM%s*%s"%(struct.value,d1),ind2,ip))
+ terms.append(("-1./3.*"+d3,i0,i0))
+ terms.append(("1./3.*OM%s*%s*%s"%(struct.value,d1,d2),i0,i0))
+ terms.append(("1./3.*OM%s*%s"%(struct.value,d3),ip,ip))
+ terms.append(("2./3.*OM%s*OM%s*%s*%s"%(struct.value,struct.value,d1,d2),ip,ip))
+ # compute the output as a dict
+ output={}
+ for i1 in imap:
+ for i2 in imap :
+ val=""
+ for term in terms:
+ if(term[0][0]!="-") :
+ pre = "+"+term[0]
+ else :
+ pre = term[0]
+ if(term[1]==i0) :
+ if(i1==i2) :
+ if(i1=="t") :
+ val += pre
+ else :
+ if(pre[0]=="+") :
+ val +="-"+pre[1:]
+ else :
+ val +="+"+pre[1:]
+
+
+ else :
+ val += "%s*%s%s*%s%s" % (pre,term[1],i1,term[2],i2)
+ output["%s%s" % (i1,i2) ] = val.replace("+1*","+").replace("-1*","-")
+ return output
+
+def generateVertex(iloc,L,parsed,lorentztag,vertex,defns) :
+ # try to import sympy and exit if required
+ try :
+ import sympy
+ from sympy import Matrix,Symbol
+ except :
+ print 'ufo2herwig uses the python sympy module to translate general lorentz structures.'
+ print 'This must be installed if you wish to use this option.'
+ print 'EXITTING'
+ quit()
+ eps=False
+ # parse the lorentz structures
+ output = [1.]*len(parsed)
+ dimension=[]
+ for i in range(0,len(parsed)) :
+ dimension.append([0,0,0])
+ for i in range (0,len(parsed)) :
+ (output[i],parsed[i],dimension[i],eps) = finishParsing(parsed[i],dimension[i],lorentztag,iloc,defns,eps)
+ # still need to process gamma matrix strings for fermions
+ if(lorentztag[0] in ["F","R"] ) :
+ return convertDirac(output,dimension,eps,iloc,L,parsed,lorentztag,vertex,defns)
+ # return the answer
+ else :
+ handled=True
+ for i in range (0,len(parsed)) :
+ if(len(parsed[i])!=0) :
+ handled = False
+ break
+ if(not handled) :
+ for i in range (0,len(parsed)) :
+ (output[i],dimension[i]) = finalContractions(output[i],parsed[i],dimension[i],lorentztag,iloc,defns)
+ return (output,dimension,eps)
+
+def convertDirac(output,dimension,eps,iloc,L,parsed,lorentztag,vertex,defns) :
+ for i in range(0,len(parsed)):
+ # skip empty elements
+ if(len(parsed[i])==0 or (len(parsed[i])==1 and parsed[i][0]=="")) : continue
+ # parse the string
+ (output[i],dimension[i],defns) = convertDiracStructure(parsed[i],output[i],dimension[i],
+ defns,iloc,L,lorentztag,vertex)
+ return (output,dimension,eps)
+
+# parse the gamma matrices
+def convertMatrix(structure,spins,unContracted,Symbols,dtemp,defns,iloc) :
+ i1 = structure.spin[0]
+ i2 = structure.spin[1]
+ if(structure.name=="Identity") :
+ output = DiracMatrix()
+ output.value = I4
+ output.index=0
+ output.name="M"
+ structure=""
+ elif(structure.name=="Gamma5") :
+ output = DiracMatrix()
+ output.value = G5
+ output.index=0
+ output.name="M"
+ structure=""
+ elif(structure.name=="ProjM") :
+ output = DiracMatrix()
+ output.value = PM
+ output.index=0
+ output.name="M"
+ structure=""
+ elif(structure.name=="ProjP") :
+ output = DiracMatrix()
+ output.value = PP
+ output.index=0
+ output.name="M"
+ structure=""
+ elif(structure.name=="Gamma") :
+ # gamma(mu) lorentz matrix contracted with dummy index
+ if(structure.lorentz[0].type=="D" or structure.lorentz[0].type=="R") :
+ if(structure.lorentz[0] not in unContracted) :
+ unContracted[structure.lorentz[0]] = 0
+ output = DiracMatrix()
+ output.value=0
+ output.index=structure.lorentz[0]
+ output.name="GMU"
+ structure=""
+ elif(structure.lorentz[0].type == "E" and
+ structure.lorentz[0].value == iloc ) :
+ if(structure.lorentz[0] not in unContracted) :
+ unContracted[structure.lorentz[0]] = 0
+ output = DiracMatrix()
+ output.value=0
+ output.index=structure.lorentz[0]
+ output.name="GMU"
+ structure=""
+ elif(structure.lorentz[0].type == "T1" or
+ structure.lorentz[0].type == "T2") :
+ if(structure.lorentz[0] not in unContracted) :
+ unContracted[structure.lorentz[0]] = 0
+ output = DiracMatrix()
+ output.value=0
+ output.index=structure.lorentz[0]
+ output.name="GMU"
+ structure=""
+ else :
+ output=DiracMatrix()
+ output.name="M"
+ output.value = vslash.substitute({ "v" : structure.lorentz[0]})
+ Symbols += vslashS.substitute({ "v" : structure.lorentz[0]})
+ variable = computeUnit(structure.lorentz[0].dimension)
+ #if(structure.lorentz[0].type!="V" or
+ # structure.lorentz[0].type=="V") :
+ dtemp[2] += structure.lorentz[0].dimension
+ defns["vv%s" % structure.lorentz[0] ] = \
+ ["vv%s" % structure.lorentz[0],
+ vslashD.substitute({ "var" : variable,
+ "v" : structure.lorentz[0]})]
+ structure=""
+ else :
+ print 'Unknown Gamma matrix structure',structure
+ raise SkipThisVertex()
+ return (i1,i2,output,structure,Symbols)
+
+
+def checkRSContract(parsed,loc,dtemp) :
+ rindex=LorentzIndex(loc)
+ rindex.type="R"
+ contract=""
+ for i in range(0,len(parsed)) :
+ if(parsed[i]=="") : continue
+ found = False
+ for ll in range(0,len(parsed[i].lorentz)) :
+ if(parsed[i].lorentz[ll]==rindex) :
+ found=True
+ break
+ if(not found) :
+ continue
+ if(parsed[i].name=="P") :
+ dtemp[2]+=1
+ contract = LorentzIndex(parsed[i].value)
+ contract.type="P"
+ contract.dimension=1
+ parsed[i]=""
+ break
+ elif(parsed[i].name=="Metric") :
+ for ll in parsed[i].lorentz :
+ if(ll==rindex) :
+ continue
+ else :
+ break
+ if(ll.type=="P") :
+ dtemp[2]+=1
+ contract=ll
+ parsed[i]=""
+ break
+ elif(parsed[i].name=="Epsilon") :
+ continue
+ else :
+ print "Unkonwn type contracted with RS spinor",parsed[i]
+ raise SkipThisVertex()
+ return contract
+
+def processChain(dtemp,parsed,spins,Symbols,unContracted,defns,iloc) :
+ # piece of dimension which is common (0.5 for sbar and spinor)
+ dtemp[0]+=1
+ # set up the spin indices
+ sind = 0
+ lind = 0
+ expr=[]
+ # now find the next thing in the matrix string
+ ii = 0
+ index=0
+ while True :
+ # already handled
+ if(parsed[ii]=="") :
+ ii+=1
+ continue
+ # start of the chain
+ elif(sind==0 and len(parsed[ii].spin)==2 and parsed[ii].spin[0]>0 ) :
+ (sind,index,matrix,parsed[ii],Symbols) \
+ = convertMatrix(parsed[ii],spins,unContracted,Symbols,dtemp,defns,iloc)
+ expr.append(matrix)
+ # next element in the chain
+ elif(index!=0 and len(parsed[ii].spin)==2 and parsed[ii].spin[0]==index) :
+ (crap,index,matrix,parsed[ii],Symbols) \
+ = convertMatrix(parsed[ii],spins,unContracted,Symbols,dtemp,defns,iloc)
+ expr.append(matrix)
+ # check the index to see if we're at the end
+ if(index>0) :
+ lind=index
+ break
+ ii+=1
+ if(ii>=len(parsed)) :
+ print "Can't parsed the chain of dirac matrices"
+ print parsed
+ raise SkipThisVertex()
+ # start and end of the spin chains
+ # first particle spin 1/2
+ if(spins[sind-1]==2) :
+ start = DiracMatrix()
+ endT = DiracMatrix()
+ start.index=0
+ endT .index=0
+ # start of chain and end of transpose
+ # off shell
+ if(sind==iloc) :
+ start.name="M"
+ endT .name="M"
+ start.value = vslashM .substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind} )
+ Symbols += vslashMS.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind} )
+ endT.value = vslashM2.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind} )
+ defns["vvP%s" % sind ] = ["vvP%s" % sind ,
+ vslashD.substitute({ "var" : "Energy",
+ "v" : "P%s" % sind })]
+ dtemp[1]+=1
+ # onshell
+ else :
+ start.name="S"
+ endT .name="S"
+ subs = {'s' : ("sbar%s" % sind)}
+ start.value = sbar .substitute(subs)
+ Symbols += sline.substitute(subs)
+ subs = {'s' : ("s%s" % sind)}
+ endT.value = spinor.substitute(subs)
+ Symbols += sline.substitute(subs)
+ # spin 3/2 fermion
+ elif spins[sind-1]==4 :
+ # check if we can easily contract
+ contract=checkRSContract(parsed,sind,dtemp)
+ # off-shell
+ if(sind==iloc) :
+ oindex = LorentzIndex(sind)
+ oindex.type="O"
+ unContracted[oindex]=0
+ Symbols += vslashMS.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind} )
+ Symbols += momCom.substitute({"v" : "P%s" %sind })
+ defns["vvP%s" % sind ] = ["vvP%s" % sind ,
+ vslashD.substitute({ "var" : "Energy",
+ "v" : "P%s" % sind })]
+ dtemp[1] += 1
+ if(contract=="") :
+ rindex = LorentzIndex(sind)
+ rindex.type="R"
+ start=DiracMatrix()
+ start.value = Template(rslash.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind, "loc" : sind }))
+ start.name = "RP"
+ start.index = (oindex,rindex)
+ endT=DiracMatrix()
+ endT.value = Template(rslash2.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind, "loc" : sind }))
+ endT.name = "RP"
+ endT.index = (rindex,oindex)
+ else :
+ # construct dot product
+ pi = LorentzIndex(sind)
+ pi.type="P"
+ pi.dimension=1
+ (name,dummy) = constructDotProduct(pi,contract,defns)
+ Symbols += momCom.substitute({"v" : contract })
+ RB = vslash.substitute({ "v" : contract})
+ Symbols += vslashS.substitute({ "v" : contract })
+ Symbols += "%s = Symbol('%s')\n" % (name,name)
+ defns["vv%s" % contract ] = ["vv%s" % contract,
+ vslashD.substitute({ "var" : computeUnit(contract.dimension),
+ "v" : "%s" % contract })]
+ start=DiracMatrix()
+ start.name="RQ"
+ start.index = oindex
+ start.value =Template( rslashB.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind, "loc" : sind,
+ "DB" : RB, "dot" : name , "v2" : contract}))
+
+ endT=DiracMatrix()
+ endT.name = "RQ"
+ endT.index = oindex
+ endT.value = Template(rslash2B.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind, "loc" : sind ,
+ "DA" : RB, "dot" : name , "v2" : contract}))
+ # on-shell
+ else :
+ start = DiracMatrix()
+ endT = DiracMatrix()
+ # no contraction
+ if(contract=="" or (contract.type=="E" and contract.value==iloc) ) :
+ if contract == "" :
+ contract = LorentzIndex(sind)
+ contract.type="R"
+ # start of matrix string
+ start.value = Template(sbar .substitute({'s' : ("Rsbar%s${L}" % sind)}))
+ start.name="RS"
+ start.index = contract
+ # end of transpose string
+ endT.value=Template(spinor.substitute({'s' : ("Rs%s${L}" % sind)}))
+ endT.name="RS"
+ endT.index = contract
+ unContracted[contract]=0
+ # variables for sympy
+ for LI in imap :
+ Symbols += sline.substitute({'s' : ("Rs%s%s" % (sind,LI))})
+ Symbols += sline.substitute({'s' : ("Rsbar%s%s" % (sind,LI))})
+ else :
+ # start of matrix string
+ start.name="S"
+ start.value = "Matrix([[%s,%s,%s,%s]])" % (RSDotProduct.substitute({'s' : ("Rsbar%s" % sind), 'v':contract, 'si' : 1}),
+ RSDotProduct.substitute({'s' : ("Rsbar%s" % sind), 'v':contract, 'si' : 2}),
+ RSDotProduct.substitute({'s' : ("Rsbar%s" % sind), 'v':contract, 'si' : 3}),
+ RSDotProduct.substitute({'s' : ("Rsbar%s" % sind), 'v':contract, 'si' : 4}))
+ endT.name="S"
+ endT.value = "Matrix([[%s],[%s],[%s],[%s]])" % (RSDotProduct.substitute({'s' : ("Rs%s" % sind), 'v':contract, 'si' : 1}),
+ RSDotProduct.substitute({'s' : ("Rs%s" % sind), 'v':contract, 'si' : 2}),
+ RSDotProduct.substitute({'s' : ("Rs%s" % sind), 'v':contract, 'si' : 3}),
+ RSDotProduct.substitute({'s' : ("Rs%s" % sind), 'v':contract, 'si' : 4}))
+ Symbols += momCom.substitute({"v" : contract })
+ for LI in ["x","y","z","t"] :
+ Symbols += sline.substitute({'s' : ("Rs%s%s" % (sind,LI))})
+ Symbols += sline.substitute({'s' : ("Rsbar%s%s" % (sind,LI))})
+ # last particle spin 1/2
+ if( spins[lind-1]==2 ) :
+ end = DiracMatrix()
+ startT = DiracMatrix()
+ end .index=0
+ startT.index=0
+ # end of chain
+ if(lind==iloc) :
+ end.name ="M"
+ startT.name="M"
+ end.value = vslashM2.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind} )
+ startT.value = vslashM.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind} )
+ Symbols += vslashMS.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind} )
+ defns["vvP%s" % lind ] = ["vvP%s" % lind ,
+ vslashD.substitute({ "var" : "Energy",
+ "v" : "P%s" % lind })]
+ dtemp[1] += 1
+ else :
+ startT.name="S"
+ end .name="S"
+ subs = {'s' : ("s%s" % lind)}
+ end.value = spinor.substitute(subs)
+ Symbols += sline.substitute(subs)
+ subs = {'s' : ("sbar%s" % lind)}
+ startT.value = sbar .substitute(subs)
+ Symbols += sline.substitute(subs)
+ # last particle spin 3/2
+ elif spins[lind-1]==4 :
+ # check if we can easily contract
+ contract=checkRSContract(parsed,lind,dtemp)
+ # off-shell
+ if(lind==iloc) :
+ oindex = LorentzIndex(lind)
+ oindex.type="O"
+ unContracted[oindex]=0
+ Symbols += vslashMS.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind} )
+ Symbols += momCom.substitute({"v" : "P%s" %lind })
+ defns["vvP%s" % lind ] = ["vvP%s" % lind ,
+ vslashD.substitute({ "var" : "Energy",
+ "v" : "P%s" % lind })]
+ dtemp[1] += 1
+ if(contract=="") :
+ rindex = LorentzIndex(lind)
+ rindex.type="R"
+ end=DiracMatrix()
+ end.value = Template(rslash2.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind, "loc" : lind }))
+ end.name = "RP"
+ end.index = (rindex,oindex)
+ startT=DiracMatrix()
+ startT.value=Template(rslash.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind, "loc" : lind }))
+ startT.name = "RP"
+ startT.index = (oindex,rindex)
+ else :
+ # construct dot product
+ pi = LorentzIndex(lind)
+ pi.type="P"
+ pi.dimension=1
+ (name,unit) = constructDotProduct(pi,contract,defns)
+ Symbols += momCom.substitute({"v" : contract })
+ RB = vslash.substitute({ "v" : contract})
+ Symbols += vslashS.substitute({ "v" : contract })
+ Symbols += "%s = Symbol('%s')\n" % (name,name)
+ defns["vv%s" % contract ] = ["vv%s" % contract,
+ vslashD.substitute({ "var" : computeUnit(contract.dimension),
+ "v" : "%s" % contract })]
+ end=DiracMatrix()
+ end.name="RQ"
+ end.index = oindex
+ end.value =Template( rslash2B.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind, "loc" : lind,
+ "DA" : RB, "dot" : name , "v2" : contract}))
+
+ startT=DiracMatrix()
+ startT.name = "RQ"
+ startT.index = oindex
+ startT.value = Template(rslashB.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind, "loc" : lind ,
+ "DB" : RB, "dot" : name , "v2" : contract}))
+ # on-shell
+ else :
+ end = DiracMatrix()
+ startT = DiracMatrix()
+ # no contraction
+ if(contract=="" or (contract.type=="E" and contract.value==iloc) ) :
+ if contract == "" :
+ contract = LorentzIndex(lind)
+ contract.type="R"
+ # end of matrix string
+ end.value = Template(spinor.substitute({'s' : ("Rs%s${L}" % lind)}))
+ end.name = "RS"
+ end.index = contract
+ # start of matrix string
+ startT.value = Template(sbar .substitute({'s' : ("Rsbar%s${L}" % lind)}))
+ startT.name = "RS"
+ startT.index = contract
+ unContracted[contract]=0
+ # variables for sympy
+ for LI in imap :
+ Symbols += sline.substitute({'s' : ("Rs%s%s" % (lind,LI))})
+ Symbols += sline.substitute({'s' : ("Rsbar%s%s" % (lind,LI))})
+ # contraction
+ else :
+ # end of the matrix string
+ end.name = "S"
+ end.value = "Matrix([[%s],[%s],[%s],[%s]])" % (RSDotProduct.substitute({'s' : ("Rs%s" % lind), 'v':contract, 'si' : 1}),
+ RSDotProduct.substitute({'s' : ("Rs%s" % lind), 'v':contract, 'si' : 2}),
+ RSDotProduct.substitute({'s' : ("Rs%s" % lind), 'v':contract, 'si' : 3}),
+ RSDotProduct.substitute({'s' : ("Rs%s" % lind), 'v':contract, 'si' : 4}))
+ startT.name = "S"
+ startT.value = "Matrix([[%s,%s,%s,%s]])" % (RSDotProduct.substitute({'s' : ("Rsbar%s" % lind), 'v':contract, 'si' : 1}),
+ RSDotProduct.substitute({'s' : ("Rsbar%s" % lind), 'v':contract, 'si' : 2}),
+ RSDotProduct.substitute({'s' : ("Rsbar%s" % lind), 'v':contract, 'si' : 3}),
+ RSDotProduct.substitute({'s' : ("Rsbar%s" % lind), 'v':contract, 'si' : 4}))
+ Symbols += momCom.substitute({"v" : contract })
+ for LI in ["x","y","z","t"] :
+ Symbols += sline.substitute({'s' : ("Rs%s%s" % (lind,LI))})
+ Symbols += sline.substitute({'s' : ("Rsbar%s%s" % (lind,LI))})
+ return(sind,lind,expr,start,startT,end,endT,Symbols)
+
+def calculateDirac(expr,start,end,startT,endT,sind,lind,Symbols,iloc) :
+ res=[]
+ for ichain in range(0,len(start)) :
+ # calculate the matrix string
+ etemp="*".join(str(x) for x in expr[ichain])
+ temp={}
+ exec("import sympy\nfrom sympy import Symbol,Matrix\n"+Symbols+"result="+
+ ( "%s*%s*%s" %(start[ichain],etemp,end[ichain]))) in temp
+ res.append(temp["result"])
+ tempT={}
+ exec("import sympy\nfrom sympy import Symbol,Matrix,Transpose\n"+Symbols+"result="+
+ ( "%s*%s*Transpose(%s)*%s*%s" %(startT[0],CC,etemp,CD,endT[0]))) in tempT
+ res.append(tempT["result"])
+ if(len(start)==1) :
+ if(iloc==0 or (iloc!=sind[0] and iloc!=lind[0])) :
+ sVal = {'s' : temp ["result"][0,0],'sT' : tempT["result"][0,0]}
+ else :
+ sVal={}
+ for jj in range(1,5) :
+ sVal["s%s" % jj] = temp ["result"][jj-1]
+ sVal["sT%s" % jj] = tempT["result"][jj-1]
+ else :
+ sVal={}
+ sVal["s" ] = res[0][0,0]*res[2][0,0]
+ sVal["sT2" ] = res[0][0,0]*res[3][0,0]
+ sVal["sT1" ] = res[1][0,0]*res[2][0,0]
+ sVal["sT12"] = res[1][0,0]*res[3][0,0]
+ return sVal
+
+def addToOutput(res,nchain,sign,rTemp) :
+ # 1 spin chain
+ if(nchain==1) :
+ for ii in range(0,2) :
+ if(rTemp[ii][0].shape[0]==1) :
+ # result is scalar
+ if(rTemp[ii][0].shape[1]==1) :
+ if(len(res[ii])==0) :
+ res[ii].append(sign*rTemp [ii][0][0,0])
+ else :
+ res[ii][0] += sign*rTemp [ii][0][0,0]
+ # result is a spinor
+ elif(rTemp[ii][0].shape[1]==4) :
+ if(len(res[ii])==0) :
+ for j in range(0,4) :
+ res[ii].append(sign*rTemp[ii][0][0,j])
+ else :
+ for j in range(0,4) :
+ res[ii][j] += sign*rTemp[ii][0][0,j]
+ else :
+ print "Size problem adding results A",sign,rTemp[ii].shape
+ raise SkipThisVertex()
+ # spinor
+ elif(rTemp[ii][0].shape[0]==4 and rTemp[ii][0].shape[1]==1 ) :
+ if(len(res[ii])==0) :
+ for j in range(0,4) :
+ res[ii].append(sign*rTemp[ii][0][j,0])
+ else :
+ for j in range(0,4) :
+ res[ii][j] += sign*rTemp[ii][0][j,0]
+ else :
+ print "Size problem adding results A",sign,rTemp[ii][0].shape
+ raise SkipThisVertex()
+ # 2 spin chains, should only be for a vertex
+ else :
+ for j1 in range(0,2) :
+ for j2 in range (0,2) :
+ val = sign*rTemp[j1][0]*rTemp[j2][1]
+ if(len(res[3])==0) :
+ res[2*j1+j2].append(val[0,0])
+ else :
+ res[2*j1+j2][0] += val[0,0]
+
+def calculateDirac2(expr,start,end,startT,endT,sind,lind,Symbols,defns,
+ iloc,unContracted,spins,lorentz) :
+ tDot=""
+ # output
+ sVal={}
+ # no of chains
+ nchain=len(expr)
+ # now deal with the uncontracted cases
+ contracted={}
+ # sort out contracted and uncontracted indices
+ keys = unContracted.keys()
+ for key in keys:
+ # summed dummy index
+ if key.type=="D" :
+ contracted[key]=0
+ del unContracted[key]
+ # RS index
+ elif key.type =="R" :
+ contracted[key]=0
+ del unContracted[key]
+ # tensor index
+ elif key.type == "T1" or key.type=="T2" :
+ contracted[key]=0
+ del unContracted[key]
+ # external index
+ elif key.type == "O" :
+ continue
+ # uncontracted vector index
+ elif key.type=="E" or key.type=="Q":
+ continue
+ else :
+ print 'Unknown type of uncontracted index',key
+ raise SkipThisVertex()
+ # check the lorentz structures
+ for lstruct in lorentz :
+ if(lstruct.name=="Epsilon" or
+ lstruct.name=="Vector") :
+ for index in lstruct.lorentz :
+ if(index.type=="E" and index.value==iloc) :
+ unContracted[index]=0
+ elif(index.type=="P" or index.type=="E"
+ or index.type=="R" or index.type=="D") :
+ contracted[index]=0
+ else :
+ print 'Unknown index',index, 'in ',lstruct
+ raise SkipThisVertex()
+ elif(lstruct.name=="Tensor") :
+ if(iloc==lstruct.value) :
+ Symbols += momCom.substitute({"v": "P%s"%lstruct.value})
+ Symbols += "OM%s = Symbol(\"OM%s\")\n" % (lstruct.value,lstruct.value)
+ Symbols += "M%s2 = Symbol(\"M%s2\")\n" % (lstruct.value,lstruct.value)
+ Symbols += "p2 = Symbol(\"p2\")\n"
+ for ival in range(1,3) :
+ newIndex=LorentzIndex(ival)
+ newIndex.type="O"
+ newIndex.dimension=0
+ lstruct.lorentz.append(newIndex)
+ unContracted[newIndex]=0
+ # contracted with self
+ if(len(lstruct.lorentz)==0) :
+ pass
+ # both indices uncontracted, deal with later
+ elif lstruct.lorentz[0].type=="T1" and lstruct.lorentz[1].type=="T2":
+ pass
+ elif lstruct.lorentz[0].type=="T1":
+ pIndex = LorentzIndex(lstruct.value)
+ pIndex.dimension=1
+ pIndex.type="P"
+ (tDot,dtemp) = constructDotProduct(pIndex,lstruct.lorentz[1],defns)
+ Symbols+="%s = Symbol(\"%s\")\n" %(tDot,tDot)
+ Symbols += momCom.substitute({"v": lstruct.lorentz[1]})
+ elif lstruct.lorentz[1].type=="T2" :
+ pIndex = LorentzIndex(lstruct.value)
+ pIndex.dimension=1
+ pIndex.type="P"
+ (tDot,dtemp) = constructDotProduct(pIndex,lstruct.lorentz[0],defns)
+ Symbols+="%s = Symbol(\"%s\")\n" %(tDot,tDot)
+ Symbols += momCom.substitute({"v": lstruct.lorentz[0]})
+ # both indices still to be contracted
+ else :
+ contracted[lstruct.lorentz[0].type]=0
+ contracted[lstruct.lorentz[1].type]=0
+ else :
+ print 'Unknown lorentz object in calculateDirac2',lstruct,iloc
+ raise SkipThisVertex()
+ # iterate over the uncontracted indices
+ while True :
+ # loop over the unContracted indices
+ res = []
+ for i in range(0,nchain) :
+ res.append([])
+ res.append([])
+ # loop over the contracted indices
+ while True :
+ # sign from metric tensor in contractions
+ sign = 1
+ for key,val in contracted.iteritems() :
+ if(val>0) : sign *=-1
+ eTemp =[]
+ sTemp =[]
+ fTemp =[]
+ sTTemp=[]
+ fTTemp=[]
+ # make the necessary replacements for remaining indices
+ for ichain in range(0,nchain) :
+ # compute the main expression
+ eTemp.append([])
+ for val in expr[ichain] :
+ # already a matrix
+ if(val.name=="M") :
+ eTemp[ichain].append(val)
+ # gamma(mu), replace with correct dirac matrix
+ elif(val.name=="GMU") :
+ if(val.index in contracted) :
+ eTemp[ichain].append(dirac[contracted[val.index]])
+ elif(val.index in unContracted) :
+ eTemp[ichain].append(dirac[unContracted[val.index]])
+ else :
+ print 'Unknown index for gamma matrix',val
+ raise SkipThisVertex()
+ # unknown to be sorted out
+ else :
+ print 'Unknown type in expr',val
+ raise SkipThisVertex()
+ # start and end
+ # start
+ if(start[ichain].name=="S" or start[ichain].name=="M" ) :
+ sTemp.append(start[ichain].value)
+ elif(start[ichain].name=="RS") :
+ if(start[ichain].index in contracted) :
+ sTemp.append(start[ichain].value.substitute({"L" : imap[ contracted[start[ichain].index]] }))
+ else :
+ sTemp.append(start[ichain].value.substitute({"L" : imap[unContracted[start[ichain].index]] }))
+ elif(start[ichain].name=="RQ") :
+ i1 = unContracted[start[ichain].index]
+ sTemp.append(start[ichain].value.substitute({"A" : imap[i1], "DA" : dirac[i1] }))
+ elif(start[ichain].name=="RP") :
+ i1 = unContracted[start[ichain].index[0]]
+ i2 = contracted[start[ichain].index[1]]
+ eta=0
+ if(i1==i2) :
+ if(i1==0) : eta = 1
+ else : eta = -1
+ sTemp.append(start[ichain].value.substitute({"eta" : eta, "A":imap[i1] , "B":imap[i2] ,
+ "DA": dirac[i1], "DB": dirac[i2]}))
+ else :
+ print 'Barred spinor not a spinor',start[ichain]
+ raise SkipThisVertex()
+ if(startT[ichain].name=="S" or startT[ichain].name=="M" ) :
+ sTTemp.append(startT[ichain].value)
+ elif(startT[ichain].name=="RS") :
+ if(startT[ichain].index in contracted) :
+ sTTemp.append(startT[ichain].value.substitute({"L" : imap[ contracted[startT[ichain].index]] }))
+ else :
+ sTTemp.append(startT[ichain].value.substitute({"L" : imap[unContracted[startT[ichain].index]] }))
+ elif(startT[ichain].name=="RQ") :
+ i1 = unContracted[startT[ichain].index]
+ sTTemp.append(startT[ichain].value.substitute({"A" : imap[i1], "DA" : dirac[i1] }))
+ elif(startT[ichain].name=="RP") :
+ i1 = unContracted[startT[ichain].index[0]]
+ i2 = contracted[startT[ichain].index[1]]
+ eta=0
+ if(i1==i2) :
+ if(i1==0) : eta = 1
+ else : eta = -1
+ sTTemp.append(startT[ichain].value.substitute({"eta" : eta, "A":imap[i1] , "B":imap[i2] ,
+ "DA": dirac[i1], "DB": dirac[i2]}))
+ else :
+ print 'barred spinorT not a spinor',startT[ichain]
+ raise SkipThisVertex()
+ # end
+ if(end[ichain].name=="S" or end[ichain].name=="M" ) :
+ fTemp.append(end[ichain].value)
+ elif(end[ichain].name=="RS") :
+ if(end[ichain].index in contracted) :
+ fTemp.append(end[ichain].value.substitute({"L" : imap[ contracted[end[ichain].index]] }))
+ else :
+ fTemp.append(end[ichain].value.substitute({"L" : imap[unContracted[end[ichain].index]] }))
+ elif(end[ichain].name=="RQ") :
+ i1 = unContracted[end[ichain].index]
+ fTemp.append(end[ichain].value.substitute({"B" : imap[i1], "DB": dirac[i1] }))
+ elif(end[ichain].name=="RP") :
+ i1 = contracted[end[ichain].index[0]]
+ i2 = unContracted[end[ichain].index[1]]
+ eta=0
+ if(i1==i2) :
+ if(i1==0) : eta = 1
+ else : eta = -1
+ fTemp.append(end[ichain].value.substitute({"eta" : eta, "A":imap[i1] , "B":imap[i2] ,
+ "DA": dirac[i1], "DB": dirac[i2]}))
+ else :
+ print 'spinor not a spinor',end[ichain]
+ raise SkipThisVertex()
+ if(endT[ichain].name=="S" or endT[ichain].name=="M" ) :
+ fTTemp.append(endT[ichain].value)
+ elif(endT[ichain].name=="RS") :
+ if(endT[ichain].index in contracted) :
+ fTTemp.append(endT[ichain].value.substitute({"L" : imap[ contracted[endT[ichain].index]] }))
+ else :
+ fTTemp.append(endT[ichain].value.substitute({"L" : imap[unContracted[endT[ichain].index]] }))
+ elif(endT[ichain].name=="RQ") :
+ i1 = unContracted[endT[ichain].index]
+ fTTemp.append(endT[ichain].value.substitute({"B" : imap[i1], "DB": dirac[i1] }))
+ elif(endT[ichain].name=="RP") :
+ i1 = contracted[endT[ichain].index[0]]
+ i2 = unContracted[endT[ichain].index[1]]
+ eta=0
+ if(i1==i2) :
+ if(i1==0) : eta = 1
+ else : eta = -1
+ fTTemp.append(endT[ichain].value.substitute({"eta" : eta, "A":imap[i1] , "B":imap[i2] ,
+ "DA": dirac[i1], "DB": dirac[i2]}))
+ else :
+ print 'spinorT not a spinor',endT[ichain]
+ raise SkipThisVertex()
+ # and none dirac lorentz structures
+ isZero = False
+ for li in lorentz:
+ # uncontracted vector
+ if(li.name=="Vector") :
+ index = unContracted[li.lorentz[0]]
+ Symbols += momCom.substitute({"v":li.value})
+ for ichain in range(0,nchain) :
+ eTemp[ichain].append("%s%s"% (li.value,imap[index]) )
+ elif(li.name=="Epsilon") :
+ value=""
+ ival=[]
+ for index in li.lorentz :
+ if(index in contracted) :
+ if(index.type=="P" or index.type=="E") :
+ value += "*%s%s" % (index,imap[contracted[index]])
+ ival.append(contracted[index])
+ elif(index.type=="R" or index.type=="D") :
+ ival.append(contracted[index])
+ else :
+ print 'Unknown index in Epsilon Tensor',index
+ raise SkipThisVertex()
+ elif(index in unContracted) :
+ ival.append(unContracted[index])
+ if(len(value)!=0 and value[0]=="*") :
+ value = value[1:]
+ eVal = epsValue[ival[0]][ival[1]][ival[2]][ival[3]]
+ if(eVal==0) :
+ isZero = True
+ else :
+ for ichain in range(0,nchain) :
+ eTemp[ichain].append("(%s*%s)"% (eVal,value) )
+ elif(li.name=="Tensor") :
+ if(li.lorentz[0] in unContracted and li.lorentz[1] in unContracted) :
+ value='0.5*(%s)'%tPropA[unContracted[li.lorentz[0]]][unContracted[li.lorentz[0]]].substitute({"iloc" : li.value})
+ for ichain in range(0,nchain) :
+ eTemp[ichain].append("(%s)"% (value) )
+ elif(len(li.lorentz)==4) :
+ if li.lorentz[0].type=="T1" and li.lorentz[1].type=="T2" :
+ value='0.5*(%s)'%tPropC[unContracted[li.lorentz[2]]][unContracted[li.lorentz[3]]][contracted[li.lorentz[0]]][contracted[li.lorentz[1]]].substitute({"iloc" : li.value})
+ elif li.lorentz[0].type=="T1":
+ value='0.5*(%s)'%tPropB[unContracted[li.lorentz[2]]][unContracted[li.lorentz[3]]][contracted[li.lorentz[0]]].substitute({"iloc" : li.value,
+ "V" : li.lorentz[1],
+ "dot" : tDot})
+ elif li.lorentz[1].type=="T2" :
+ value= '0.5*(%s)'%tPropB[unContracted[li.lorentz[2]]][unContracted[li.lorentz[3]]][contracted[li.lorentz[1]]].substitute({"iloc" : li.value,
+ "V" : li.lorentz[0],
+ "dot" : tDot})
+ else :
+ print 'Both contracted tensor indices contracted'
+ raise SkipThisVertex()
+ for ichain in range(0,nchain) :
+ eTemp[ichain].append("(%s)"% (value) )
+ else :
+ print 'Uncontracted on-shell tensor'
+ raise SkipThisVertex()
+ # unknown
+ else :
+ print 'Unknown expression in lorentz loop',li
+ raise SkipThisVertex()
+ # now evaluate the result
+ if(not isZero) :
+ rTemp =[[],[]]
+ for ichain in range(0,nchain) :
+ core = "*".join(str(x) for x in eTemp[ichain])
+ temp={}
+ exec("import sympy\nfrom sympy import Symbol,Matrix\n"+Symbols+"result="+
+ ( "(%s)*(%s)*(%s)" %(sTemp[ichain],core,fTemp[ichain]))) in temp
+ rTemp[0].append(temp["result"])
+ temp={}
+ exec("import sympy\nfrom sympy import Symbol,Matrix,Transpose\n"+Symbols+"result="+
+ ( "(%s)*(%s)*(Transpose(%s))*(%s)*(%s)" %(sTTemp[ichain],CC,core,CD,fTTemp[ichain]))) in temp
+ rTemp[1].append(temp["result"])
+ # and add it to the output
+ addToOutput(res,nchain,sign,rTemp)
+ #### END OF THE CONTRACTED LOOP #####
+ # increment the indices being summed over
+ keys=contracted.keys()
+ ii = len(keys)-1
+ while ii >=0 :
+ if(contracted[keys[ii]]<3) :
+ contracted[keys[ii]]+=1
+ break
+ else :
+ contracted[keys[ii]]=0
+ ii-=1
+ nZero=0
+ for (key,val) in contracted.iteritems() :
+ if(val==0) : nZero+=1
+ if(nZero==len(contracted)) : break
+ ###### END OF THE UNCONTRACTED LOOP ######
+ # no uncontracted indices
+ if(len(unContracted)==0) :
+ if(len(res[0])==1) :
+ # scalar
+ if(len(res)==2) :
+ sVal["s" ] = res[0]
+ sVal["sT"] = res[1]
+ # 4 fermion
+ else :
+ sVal["s" ] = res[0]
+ sVal["sT2" ] = res[1]
+ sVal["sT1" ] = res[2]
+ sVal["sT12"] = res[3]
+ # spinor
+ elif(len(res[0])==4) :
+ for k in range(0,4) :
+ sVal[ "s%s" % (k+1) ] = res[0][k]
+ sVal[ "sT%s" % (k+1) ] = res[1][k]
+ else :
+ print 'Sum problem',len(res),len(res[0])
+ raise SkipThisVertex()
+ break
+ # uncontracted indices
+ else :
+ istring = ""
+ for (key,val) in unContracted.iteritems() :
+ istring +=imap[val]
+ if(len(istring)>2) :
+ print 'Index problem',istring
+ raise SkipThisVertex()
+ sVal[istring] = res[0]
+ sVal[istring+"T"] = res[1]
+ # increment the unsummed indices
+ keys=unContracted.keys()
+ ii = len(keys)-1
+ while ii >=0 :
+ if(unContracted[keys[ii]]<3) :
+ unContracted[keys[ii]]+=1
+ break
+ else :
+ unContracted[keys[ii]]=0
+ ii-=1
+ nZero=0
+ for (key,val) in unContracted.iteritems() :
+ if(val==0) : nZero+=1
+ if(nZero==len(unContracted)) : break
+ # handle the vector case
+ if( "tt" in sVal) :
+ if(len(sVal)==32 and "tt" in sVal and len(sVal["tt"])==1) :
+ for key in sVal:
+ sVal[key] = sVal[key][0]
+ else :
+ print 'Tensor sum problem',len(sVal)
+ raise SkipThisVertex()
+ elif( "t" in sVal ) :
+ # deal with pure vectors
+ if(len(sVal)==8 and "t" in sVal and len(sVal["t"])==1) :
+ pass
+ # RS spinors
+ elif(len(sVal)==8 and "t" in sVal and len(sVal["t"])==4) :
+ pass
+ else :
+ print 'Value problem',len(sVal)
+ raise SkipThisVertex()
+ else :
+ if("s" in sVal) :
+ for key in sVal:
+ sVal[key] = sVal[key][0]
+ return sVal
+
+def convertDiracStructure(parsed,output,dimension,defns,iloc,L,lorentztag,vertex) :
+ # get the spins of the particles
+ spins = vertex.lorentz[0].spins
+ # check if we have one or two spin chains
+ nchain = (lorentztag.count("F")+lorentztag.count("R"))/2
+ # storage of the intermediate results
+ expr =[]
+ start =[]
+ end =[]
+ startT=[]
+ endT =[]
+ sind=[0]*nchain
+ lind=[0]*nchain
+ unContracted={}
+ Symbols=""
+ dtemp=[0,0,0]
+ # parse the dirac matrix strings
+ for ichain in range(0,nchain) :
+ expr .append([])
+ start .append("")
+ startT.append("")
+ end .append("")
+ endT .append("")
+ sind[ichain],lind[ichain],expr[ichain],start[ichain],startT[ichain],end[ichain],endT[ichain],Symbols =\
+ processChain(dtemp,parsed,spins,Symbols,unContracted,defns,iloc)
+ # clean up parsed
+ # check we've dealt with everything
+ parsed = [x for x in parsed if x != ""]
+ lorentz=[]
+ if(len(parsed)!=0) :
+ for i in range(0,len(parsed)) :
+ if(parsed[i].name=="Metric") :
+ found = False
+ for ll in parsed[i].lorentz :
+ if(ll.type=="E" and ll.value==iloc) :
+ found = True
+ un=ll
+ else :
+ lo=ll
+ if(found) :
+ lstruct = LorentzStructure()
+ lstruct.name="Vector"
+ lstruct.value=lo
+ lstruct.lorentz=[un]
+ lstruct.spin=[]
+ lorentz.append(lstruct)
+ parsed[i]=""
+ unContracted[un]=0
+ dimension[2] += lo.dimension
+ elif(parsed[i].name=="Epsilon") :
+ lstruct = LorentzStructure()
+ lstruct.name="Epsilon"
+ lstruct.lorentz=parsed[i].lorentz
+ lstruct.value=0
+ lstruct.spin=[]
+ for index in lstruct.lorentz:
+ if(index.type=="P") :
+ dimension[2]+=1
+ if( not index in defns) :
+ defns[(index,)]=["",""]
+ if(index.type=="P" or
+ (index.type=="E" and index.value!=iloc)) :
+ Symbols += momCom.substitute( {"v": index} )
+ lorentz.append(lstruct)
+ parsed[i]=""
+ elif(parsed[i].name=="Tensor") :
+ lstruct = LorentzStructure()
+ lstruct.name="Tensor"
+ lstruct.value=parsed[i].value
+ lstruct.lorentz=parsed[i].lorentz
+ lstruct.spin=[]
+ for index in parsed[i].lorentz:
+ dimension[2] += index.dimension
+ parsed[i]=""
+ lorentz.append(lstruct)
+ else :
+ print 'Unknown lorentz structure',parsed[i]
+ raise SkipThisVertex()
+
+ parsed = [x for x in parsed if x != ""]
+ if(len(parsed)!=0) :
+ print "Can't parse ",parsed,iloc
+ raise SkipThisVertex()
+ sVal ={}
+ dimension = list(map(lambda x, y: x + y, dtemp, dimension))
+ # deal with the simplest case first
+ if len(unContracted) == 0 and len(lorentz) == 0:
+ sVal = calculateDirac(expr,start,end,startT,endT,sind,lind,Symbols,iloc)
+ else :
+ sVal = calculateDirac2(expr,start,end,startT,endT,sind,lind,Symbols,defns,
+ iloc,unContracted,spins,lorentz)
+ # set up the output
+ old = output
+ if(nchain==1) :
+ output = [old,sVal,(lind[0],sind[0])]
+ else :
+ output = [old,sVal,(lind[0],sind[0],lind[1],sind[1])]
+ return (output,dimension,defns)
+
+def convertLorentz(Lstruct,lorentztag,order,vertex,iloc,defns,evalVertex) :
+ eps = False
+ # split the structure into individual terms
+ structures=Lstruct.structure.split()
+ parsed=[]
+ # parse structures and convert lorentz contractions to dot products
+ for struct in structures :
+ ptemp = parse_structure(struct,Lstruct.spins)
+ parsed.append(contract(ptemp))
+ # now in a position to generate the code
+ vals=generateVertex(iloc,Lstruct,parsed,lorentztag,vertex,defns)
+ evalVertex.append((vals[0],vals[1]))
+ if(vals[2]) : eps=True
+ return eps
+
+def swapOrder(vertex,iloc,momenta,fIndex) :
+ names=['','sca','sp','v']
+ waves=['','sca','' ,'E']
+ output=""
+ for i in range(1,4) :
+ ns = vertex.lorentz[0].spins.count(i)
+ if((ns<=1 and i!=2) or (ns<=2 and i==2)) : continue
+ if(i!=3 and i!=1) :
+ print 'Swap problem',i
+ raise SkipThisVertex()
+ sloc=[]
+ for j in range(0,len(vertex.lorentz[0].spins)) :
+ if(vertex.lorentz[0].spins[j]==i) : sloc.append(j+1)
+ if iloc in sloc : sloc.remove(iloc)
+ if(len(sloc)==1) : continue
+ for j in range(0,len(sloc)) :
+ output += " long id%s = %sW%s.id();\n" % (sloc[j],names[i],sloc[j])
+ for j in range(0,len(sloc)) :
+ for k in range(j+1,len(sloc)) :
+ code = vertex.particles[sloc[j]-1].pdg_code
+ output += " if(id%s!=%s) {\n" % (sloc[j],code)
+ output += " swap(id%s,id%s);\n" % (sloc[j],sloc[k])
+ output += " swap(%s%s,%s%s);\n" % (waves[i],sloc[j],waves[i],sloc[k])
+ if(momenta[sloc[j]-1][0] or momenta[sloc[k]-1][0]) :
+ momenta[sloc[j]-1][0] = True
+ momenta[sloc[k]-1][0] = True
+ output += " swap(P%s,P%s);\n" % (sloc[j],sloc[k])
+ output += " };\n"
+ return output
+
+def swapOrderFFFF(vertex,iloc,fIndex) :
+ output=""
+ for j in range(0,len(fIndex)) :
+ if(j%2==0) :
+ output += " SpinorWaveFunction s%s = sW%s;\n" % (fIndex[j],fIndex[j])
+ else :
+ output += " SpinorBarWaveFunction sbar%s = sbarW%s;\n" % (fIndex[j],fIndex[j])
+
+ for j in range(0,len(fIndex)) :
+ if(j%2==0) :
+ output += " long id%s = sW%s.id();\n" % (fIndex[j],fIndex[j])
+ else :
+ output += " long id%s = sbarW%s.id();\n" % (fIndex[j],fIndex[j])
+
+ for j in range(0,2) :
+ code = vertex.particles[fIndex[j]-1].pdg_code
+ output += " if(id%s!=%s) {\n" % (fIndex[j],code)
+ output += " swap(id%s,id%s);\n" % (fIndex[j],fIndex[j+2])
+ wave="s"
+ if(j==1) : wave = "sbar"
+ output += " swap(%s%s,%s%s);\n" % (wave,fIndex[j],wave,fIndex[j+2])
+ output += " };\n"
+ return output
+
+def constructSignature(vertex,order,iloc,decls,momenta,waves,fIndex) :
+ nf=0
+ poff=""
+ offType="Complex"
+ for i in order :
+ spin = vertex.lorentz[0].spins[i-1]
+ if(i==iloc) :
+ if(spin==1) :
+ offType="ScalarWaveFunction"
+ elif(spin==2) :
+ if(i%2==1) :
+ offType="SpinorBarWaveFunction"
+ else :
+ offType="SpinorWaveFunction"
+ nf+=1
+ elif(spin==4) :
+ if(i%2==1) :
+ offType="RSSpinorBarWaveFunction"
+ else :
+ offType="RSSpinorWaveFunction"
+ nf+=1
+ elif(spin==3) :
+ offType="VectorWaveFunction"
+ elif(spin==5) :
+ offType="TensorWaveFunction"
+ else :
+ print 'Unknown spin',spin
+ raise SkipThisVertex()
+ momenta.append([False,""])
+ else :
+ if(spin==1) :
+ decls.append("ScalarWaveFunction & scaW%s" % (i))
+ momenta.append([False,"Lorentz5Momentum P%s =-scaW%s.momentum();" % (i,i)])
+ waves.append("Complex sca%s = scaW%s.wave();" % (i,i))
+ elif(spin==2) :
+ if(i%2==1) :
+ decls.append("SpinorWaveFunction & sW%s" % (fIndex[i-1]))
+ momenta.append([False,"Lorentz5Momentum P%s =-sW%s.momentum();" % (fIndex[i-1],fIndex[i-1])])
+ waves.append("LorentzSpinor<double> s%s = sW%s.wave();" % (fIndex[i-1],fIndex[i-1]))
+ nf+=1
+ else :
+ decls.append("SpinorBarWaveFunction & sbarW%s" % (fIndex[i-1]))
+ momenta.append([False,"Lorentz5Momentum P%s =-sbarW%s.momentum();" % (fIndex[i-1],fIndex[i-1])])
+ waves.append("LorentzSpinorBar<double> sbar%s = sbarW%s.wave();" % (fIndex[i-1],fIndex[i-1]))
+ nf+=1
+ elif(spin==3) :
+ decls.append("VectorWaveFunction & vW%s" % (i))
+ momenta.append([False,"Lorentz5Momentum P%s =-vW%s.momentum();" % (i,i)])
+ waves.append("LorentzPolarizationVector E%s = vW%s.wave();" % (i,i))
+ elif(spin==4) :
+ if(i%2==1) :
+ decls.append("RSSpinorWaveFunction & RsW%s" % (i))
+ momenta.append([False,"Lorentz5Momentum P%s =-RsW%s.momentum();" % (i,i)])
+ waves.append("LorentzRSSpinor<double> Rs%s = RsW%s.wave();" % (i,i))
+ nf+=1
+ else :
+ decls.append("RSSpinorBarWaveFunction & RsbarW%s" % (i))
+ momenta.append([False,"Lorentz5Momentum P%s =-RsbarW%s.momentum();" % (i,i)])
+ waves.append("LorentzRSSpinorBar<double> Rsbar%s = RsbarW%s.wave();" % (i,i))
+ nf+=1
+ elif(spin==5) :
+ decls.append("TensorWaveFunction & tW%s" % (i))
+ momenta.append([False,"Lorentz5Momentum P%s =-tW%s.momentum();" % (i,i)])
+ waves.append("LorentzTensor<double> T%s = tW%s.wave();" % (i,i))
+ else :
+ print 'Unknown spin',spin
+ raise SkipThisVertex()
+ poff += "-P%s" % (i)
+ # ensure unbarred spinor first
+ ibar=-1
+ isp=-1
+ for i in range(0,len(decls)) :
+ if(decls[i].find("Bar")>0 and ibar==-1) :
+ ibar=i
+ elif(decls[i].find("Spinor")>=0 and isp==-1) :
+ isp=i
+ if(isp!=-1 and ibar!=-1 and isp>ibar) :
+ decls[ibar],decls[isp] = decls[isp],decls[ibar]
+ # constrct the signature
+ poff = ("Lorentz5Momentum P%s = " % iloc ) + poff
+ sig=""
+ if(iloc==0) :
+ sig="%s evaluate(Energy2, const %s)" % (offType,", const ".join(decls))
+ # special for VVT vertex
+ if(len(vertex.lorentz[0].spins)==3 and vertex.lorentz[0].spins.count(3)==2 and
+ vertex.lorentz[0].spins.count(5)==1) :
+ sig = sig[0:-1] + ", Energy vmass=-GeV)"
+ else :
+ sig="%s evaluate(Energy2, int iopt, tcPDPtr out, const %s, complex<Energy> mass=-GeV, complex<Energy> width=-GeV)" % (offType,", const ".join(decls))
+ momenta.append([True,poff+";"])
+ # special for VVT vertex
+ if(len(vertex.lorentz[0].spins)==3 and vertex.lorentz[0].spins.count(3)==2 and
+ vertex.lorentz[0].spins.count(5)==1 and vertex.lorentz[0].spins[iloc-1]==5) :
+ sig=sig.replace("complex<Energy> mass=-GeV","Energy vmass=-GeV, complex<Energy> mass=-GeV")
+ for i in range(0,len(momenta)) : momenta[i][0]=True
+ return offType,nf,poff,sig
+
+def combineResult(res,nf,ispin,vertex) :
+ # extract the vals and dimensions
+ (vals,dim) = res
+ # construct the output structure
+ # vertex and off-shell scalars
+ if(ispin<=1) :
+ otype={'res':""}
+ # spins
+ elif(ispin==2) :
+ otype={'s1':"",'s2':"",'s3':"",'s4':""}
+ # vectors
+ elif(ispin==3) :
+ if( "t" in vals[0][1] ) :
+ otype={'t':"",'x':"",'y':"",'z':""}
+ else :
+ otype={"res":""}
+ # RS spinors
+ elif(ispin==4) :
+ otype={}
+ for i1 in imap :
+ for i in range(1,5) :
+ otype["%ss%s"% (i1,i)]=""
+ # off-shell tensors
+ elif(ispin==5) :
+ otype={}
+ for i1 in imap :
+ for i2 in imap :
+ otype["%s%s"%(i1,i2)]=""
+ else :
+ print 'Unknown spin',ispin
+ raise SkipThisVertex()
+ expr=[otype]
+ for i in range(0,nf-1) :
+ expr.append(copy.copy(otype))
+ # dimension for checking
+ dimCheck=dim[0]
+ for i in range(0,len(vals)) :
+ # simple signs
+ if(vals[i]=="+" or vals[i]=="-") :
+ for ii in range(0,len(expr)) :
+ for(key,val) in expr[ii].iteritems() :
+ expr[ii][key] = expr[ii][key]+vals[i]
+ continue
+ # check the dimensions
+ if(dimCheck[0]!=dim[i][0] or dimCheck[1]!=dim[i][1] or
+ dimCheck[2]!=dim[i][2]) :
+ print "Dimension problem in result",i,dimCheck,dim,vertex
+ print vertex.lorentz
+ for j in range(0,len(vals)) :
+ print j,dim[j],vals[j]
+ raise SkipThisVertex()
+ # simplest case
+ if(isinstance(vals[i], basestring)) :
+ for ii in range(0,len(expr)) :
+ for(key,val) in expr[ii].iteritems() :
+ expr[ii][key] = expr[ii][key]+vals[i]
+ continue
+ # more complex structures
+ pre = vals[i][0]
+ if(pre=="(1.0)") : pre=""
+ if(not isinstance(vals[i][1],dict)) :
+ print 'must be a dict here'
+ raise SkipThisVertex()
+ # tensors
+ if("tt" in vals[i][1]) :
+ for i1 in imap :
+ for i2 in imap :
+ key="%s%s"%(i1,i2)
+ if(pre=="") :
+ expr[0][key] += "(%s)" % vals[i][1][key]
+ else :
+ expr[0][key] += "%s*(%s)" % (pre,vals[i][1][key])
+ if(len(expr)==2) :
+ if(pre=="") :
+ expr[1][key] +="(%s)" % vals[i][1][key+"T"]
+ else :
+ expr[1][key] +="%s*(%s)" % (pre,vals[i][1][key+"T"])
+ # standard fermion vertex case
+ elif(len(vals[i][1])==2 and "s" in vals[i][1] and "sT" in vals[i][1]) :
+ if(pre=="") :
+ expr[0]["res"] += "(%s)" % vals[i][1]["s"]
+ expr[1]["res"] += "(%s)" % vals[i][1]["sT"]
+ else :
+ expr[0]["res"] += "%s*(%s)" % (pre,vals[i][1]["s"])
+ expr[1]["res"] += "%s*(%s)" % (pre,vals[i][1]["sT"])
+ # spinor case
+ elif(len(vals[i][1])==8 and "s1" in vals[i][1]) :
+ for jj in range(1,5) :
+ if(pre=="") :
+ expr[0]["s%s" % jj] += "(%s)" % vals[i][1]["s%s" % jj]
+ expr[1]["s%s" % jj] += "(%s)" % vals[i][1]["sT%s" % jj]
+ else :
+ expr[0]["s%s" % jj] += "%s*(%s)" % (pre,vals[i][1]["s%s" % jj])
+ expr[1]["s%s" % jj] += "%s*(%s)" % (pre,vals[i][1]["sT%s" % jj])
+ # vector
+ elif(len(vals[i][1])%4==0 and "t" in vals[i][1] and len(vals[i][1]["t"])==1 ) :
+ for i1 in imap :
+ if(pre=="") :
+ expr[0][i1] += "(%s)" % vals[i][1][i1][0]
+ else :
+ expr[0][i1] += "%s*(%s)" % (pre,vals[i][1][i1][0])
+ if(len(expr)==2) :
+ if(pre=="") :
+ expr[1][i1] +="(%s)" % vals[i][1][i1+"T"][0]
+ else :
+ expr[1][i1] +="%s*(%s)" % (pre,vals[i][1][i1+"T"][0])
+ # 4 fermion vertex case
+ elif(len(vals[i][1])==4 and "sT12" in vals[i][1]) :
+ if(pre=="") :
+ expr[0]["res"] += "(%s)" % vals[i][1]["s"]
+ expr[1]["res"] += "(%s)" % vals[i][1]["sT2"]
+ expr[2]["res"] += "(%s)" % vals[i][1]["sT1"]
+ expr[3]["res"] += "(%s)" % vals[i][1]["sT12"]
+ else :
+ expr[0]["res"] += "%s*(%s)" % (pre,vals[i][1]["s"])
+ expr[1]["res"] += "%s*(%s)" % (pre,vals[i][1]["sT2"])
+ expr[2]["res"] += "(%s)" % vals[i][1]["sT1"]
+ expr[3]["res"] += "(%s)" % vals[i][1]["sT12"]
+ # RS spinor
+ elif(len(vals[i][1])%4==0 and "t" in vals[i][1] and len(vals[i][1]["t"])==4 ) :
+ for i1 in imap :
+ for k in range(1,5) :
+ key = "%ss%s" % (i1,k)
+ if(pre=="") :
+ expr[0][key] += "(%s)" % vals[i][1][i1][k-1]
+ expr[1][key] += "(%s)" % vals[i][1][i1+"T"][k-1]
+ else :
+ expr[0][key] += "%s*(%s)" % (pre,vals[i][1][i1][k-1])
+ expr[1][key] += "%s*(%s)" % (pre,vals[i][1][i1+"T"][k-1])
+ else :
+ print 'problem with type',vals[i]
+ raise SkipThisVertex()
+ # no of particles in the vertex
+ vDim = len(vertex.lorentz[0].spins)
+ # compute the unit and apply it
+ unit = computeUnit2(dimCheck,vDim)
+ if(unit!="") :
+ for ii in range(0,len(expr)) :
+ for (key,val) in expr[ii].iteritems() :
+ expr[ii][key] = "(%s)*(%s)" % (val,unit)
+ return expr
+
+def headerReplace(inval) :
+ return inval.replace("virtual","").replace("ScalarWaveFunction","").replace("SpinorWaveFunction","") \
+ .replace("SpinorBarWaveFunction","").replace("VectorWaveFunction","").replace("TensorWaveFunction","") \
+ .replace("Energy2","q2").replace("int","").replace("complex<Energy>","").replace("Energy","").replace("=-GeV","") \
+ .replace("const &","").replace("tcPDPtr","").replace(" "," ").replace("Complex","")
+
+def combineComponents(result,offType,RS) :
+ for i in range(0,len(result)) :
+ for (key,value) in result[i].iteritems() :
+ output=py2cpp(value.strip(),True)
+ result[i][key]=output[0]
+ # simplest case, just a value
+ if(len(result[0])==1 and "res" in result[0]) :
+ for i in range(0,len(result)) :
+ result[i] = result[i]["res"]
+ result[i]=result[i].replace("1j","ii")
+ return
+ # calculate the substitutions
+ if(not isinstance(result[0],basestring)) :
+ subs=[]
+ for ii in range(0,len(result)) :
+ subs.append({})
+ for (key,val) in result[ii].iteritems() :
+ subs[ii]["out%s" % key]= val
+ # spinors
+ if("s1" in result[0]) :
+ stype = "LorentzSpinor"
+ sbtype = "LorentzSpinorBar"
+ if(offType.find("Bar")>0) : (stype,sbtype)=(sbtype,stype)
+ subs[0]["type"] = stype
+ result[0] = SpinorTemplate.substitute(subs[0])
+ subs[1]["type"] = sbtype
+ result[1] = SpinorTemplate.substitute(subs[1])
+ # tensors
+ elif("tt" in result[0]) :
+ for ii in range(0,len(result)) :
+ result[ii] = Template("LorentzTensor<double>(${outxx},\n${outxy},\n${outxz},\n${outxt},\n${outyx},\n${outyy},\n${outyz},\n${outyt},\n${outzx},\n${outzy},\n${outzz},\n${outzt},\n${outtx},\n${outty},\n${outtz},\n${outtt})").substitute(subs[ii])
+ result[ii]=result[ii].replace("(+","(")
+ # vectors
+ elif("t" in result[0]) :
+ for ii in range(0,len(result)) :
+ result[ii] = Template("LorentzVector<Complex>(${outx},\n${outy},\n${outz},\n${outt})").substitute(subs[ii])
+ result[ii]=result[ii].replace("(+","(")
+ # RS spinors
+ elif("ts1" in result[0]) :
+ stype = "LorentzRSSpinor"
+ sbtype = "LorentzRSSpinorBar"
+ if(offType.find("Bar")>0) : (stype,sbtype)=(sbtype,stype)
+ subs[0]["type"] = stype
+ result[0] = RSSpinorTemplate.substitute(subs[0])
+ subs[1]["type"] = sbtype
+ result[1] = RSSpinorTemplate.substitute(subs[1])
+ else :
+ print 'Type not implemented',result
+ raise SkipThisVertex()
+ for i in range(0,len(result)) :
+ result[i]=result[i].replace("1j","ii")
+
+def generateEvaluateFunction(model,vertex,iloc,values,defns,vertexEval,cf,order) :
+ RS = "R" in vertex.lorentz[0].name
+ FM = "F" in vertex.lorentz[0].name
+ # extract the start and end of the spin chains
+ if( RS or FM ) :
+ fIndex = vertexEval[0][0][0][2]
+ else :
+ fIndex=0
+ # first construct the signature of the function
+ decls=[]
+ momenta=[]
+ waves=[]
+ offType,nf,poff,sig = constructSignature(vertex,order,iloc,decls,momenta,waves,fIndex)
+ # combine the different terms in the result
+ symbols=set()
+ localCouplings=[]
+ result=[]
+ ispin = 0
+ if(iloc!=0) :
+ ispin = vertex.lorentz[0].spins[iloc-1]
+ # put the lorentz structures and couplings together
+ for j in range(0,len(vertexEval)) :
+ # get the lorentz structure piece
+ expr = combineResult(vertexEval[j],nf,ispin,vertex)
+ # get the coupling for this bit
+ val, sym = py2cpp(values[j])
+ localCouplings.append("Complex local_C%s = %s;\n" % (j,val))
+ symbols |=sym
+ # put them together
+ vtype="Complex"
+ if("res" in expr[0] and offType=="VectorWaveFunction") :
+ vtype="LorentzPolarizationVector"
+ if(len(result)==0) :
+ for ii in range(0,len(expr)) :
+ result.append({})
+ for (key,val) in expr[ii].iteritems() :
+ result[ii][key] = " %s((local_C%s)*(%s)) " % (vtype,j,val)
+ else :
+ for ii in range(0,len(expr)) :
+ for (key,val) in expr[ii].iteritems():
+ result[ii][key] += " + %s((local_C%s)*(%s)) " % (vtype,j,val)
+ # for more complex types merge the spin/lorentz components
+ combineComponents(result,offType,RS)
+ # multiple by scalar wavefunctions
+ scalars=""
+ for i in range (0,len(vertex.lorentz[0].spins)) :
+ if(vertex.lorentz[0].spins[i]==1 and i+1!=iloc) :
+ scalars += "sca%s*" % (i+1)
+ if(scalars!="") :
+ for ii in range(0,len(result)) :
+ result[ii] = "(%s)*(%s)" % (result[ii],scalars[0:-1])
+ # vertex, just return the answer
+ if(iloc==0) :
+ result[0] = "return (%s)*(%s);\n" % (result[0],py2cpp(cf)[0])
+ if(FM or RS) :
+ for i in range(1,len(result)) :
+ result[i] = "return (%s)*(%s);\n" % (result[i],py2cpp(cf)[0])
+ # off-shell particle
+ else :
+ # off-shell scalar
+ if(vertex.lorentz[0].spins[iloc-1] == 1 ) :
+ result[0] = scaTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],res=result[0])
+ if(FM or RS) :
+ result[1] = scaTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],res=result[1])
+ # off-shell fermion
+ elif(vertex.lorentz[0].spins[iloc-1] == 2 ) :
+ result[0] = sTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],offTypeA=offType.replace("WaveFunction",""),
+ res=result[0].replace( "M%s" % iloc, "mass" ),offTypeB=offType)
+ if(FM or RS) :
+ if(offType.find("Bar")>0) :
+ offTypeT=offType.replace("Bar","")
+ else :
+ offTypeT=offType.replace("Spinor","SpinorBar")
+ result[1] = sTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],offTypeA=offTypeT.replace("WaveFunction",""),
+ res=result[1].replace( "M%s" % iloc, "mass" ),offTypeB=offTypeT)
+ # off-shell vector
+ elif(vertex.lorentz[0].spins[iloc-1] == 3 ) :
+ result[0] = vecTemplate.format(iloc=iloc,res=result[0],cf=py2cpp(cf)[0])
+ if(FM or RS) :
+ result[1] = vecTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],res=result[1])
+ elif(vertex.lorentz[0].spins[iloc-1] == 4 ) :
+ if(offType.find("Bar")>0) :
+ offTypeT=offType.replace("Bar","")
+ else :
+ offTypeT=offType.replace("Spinor","SpinorBar")
+ result[1] = RSTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],offTypeA=offTypeT.replace("WaveFunction",""),
+ res=result[1].replace( "M%s" % iloc, "mass" ),offTypeB=offTypeT)
+ result[0] = RSTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],offTypeA=offType.replace("WaveFunction",""),
+ res=result[0].replace( "M%s" % iloc, "mass" ),offTypeB=offType)
+ # tensors
+ elif(vertex.lorentz[0].spins[iloc-1]) :
+ if(RS) :
+ print "RS spinors and tensors not handled"
+ raise SkipThisVertex()
+ result[0] = tenTemplate.format(iloc=iloc,cf=py2cpp(cf)[0],res=result[0])
+ if(FM or RS) :
+ result[1] = tenTemplate.format(iloc=iloc,cf=py2cpp(cf)[0],res=result[1])
+ else :
+ print 'Unknown spin for off-shell particle',vertex.lorentz[0].spins[iloc-1]
+ raise SkipThisVertex()
+ # check if momenta defns needed to clean up compile of code
+ for (key,val) in defns.iteritems() :
+ if( isinstance(key, basestring)) :
+ if(key.find("vvP")==0) :
+ momenta[int(key[3])-1][0] = True
+ else :
+ for vals in key :
+ if(vals.type=="P") :
+ momenta[vals.value-1][0] = True
+ # cat the definitions
+ defString=""
+ for (key,value) in defns.iteritems() :
+ if(value[0]=="") : continue
+ if(value[0][0]=="V" or value[0][0]=="T") :
+ defString+=" %s\n" %value[1]
+ for (key,value) in defns.iteritems() :
+ if(value[0]=="") : continue
+ if(value[0][0]!="V" and value[0][0]!="T") :
+ defString+=" %s\n" %value[1]
+ if(len(result)<=2) :
+ sorder=swapOrder(vertex,iloc,momenta,fIndex)
+ else :
+ sorder=""
+ momentastring=""
+ for i in range(0,len(momenta)) :
+ if(momenta[i][0] and momenta[i][1]!="") :
+ momentastring+=momenta[i][1]+"\n "
+ # special for 4-point VVVV
+ if(vertex.lorentz[0].spins.count(3)==4 and iloc==0) :
+ sig=sig.replace("Energy2","Energy2,int")
+
+ header="virtual %s" % sig
+ sig=sig.replace("=-GeV","")
+ symboldefs = [ def_from_model(model,s) for s in symbols ]
+ function = evaluateTemplate.format(decl=sig,momenta=momentastring,defns=defString,
+ waves="\n ".join(waves),symbols='\n '.join(symboldefs),
+ couplings="\n ".join(localCouplings),
+ result=result[0],swap=sorder)
+
+ # special for transpose
+ if(FM or RS) :
+ h2=header
+ if(not RS) :
+ h2=header.replace("evaluate","evaluateN")
+ function=function.replace("evaluate(","evaluateN(")
+ headers=[]
+ newHeader=""
+ for ifunction in range(1,len(result)) :
+ waveNew=[]
+ momentastring=""
+ htemp = header.split(",")
+ irs=-1
+ isp=-1
+ # RS case
+ if(RS) :
+ # sort out the wavefunctions
+ for i in range(0,len(waves)) :
+ if(waves[i].find("Spinor")<0) :
+ waveNew.append(waves[i])
+ continue
+ if(waves[i].find("Bar")>0) :
+ waveNew.append(waves[i].replace("Bar","").replace("bar",""))
+ else :
+ waveNew.append(waves[i].replace("Spinor","SpinorBar").replace(" s"," sbar").replace("Rs","Rsbar"))
+ # sort out the momenta definitions
+ for i in range(0,len(momenta)) :
+ if(momenta[i][0] and momenta[i][1]!="") :
+ if(momenta[i][1].find("barW")>0) :
+ momentastring+=momenta[i][1].replace("barW","W")+"\n "
+ elif(momenta[i][1].find("sW")>0) :
+ momentastring+=momenta[i][1].replace("sW","sbarW")+"\n "
+ else :
+ momentastring+=momenta[i][1]+"\n "
+ # header string
+ for i in range(0,len(htemp)) :
+ if(htemp[i].find("RS")>0) :
+ if(htemp[i].find("Bar")>0) :
+ htemp[i]=htemp[i].replace("Bar","").replace("RsbarW","RsW")
+ else :
+ htemp[i]=htemp[i].replace("Spinor","SpinorBar").replace("RsW","RsbarW")
+ if(i>0) : irs=i
+ elif(htemp[i].find("Spinor")>0) :
+ if(htemp[i].find("Bar")>0) :
+ htemp[i]=htemp[i].replace("Bar","").replace("sbarW","sW")
+ else :
+ htemp[i]=htemp[i].replace("Spinor","SpinorBar").replace("sW","sbarW")
+ if(i>0) : isp=i
+ if(irs>0 and isp >0) :
+ htemp[irs],htemp[isp] = htemp[isp],htemp[irs]
+ # fermion case
+ else :
+ htemp2 = header.split(",")
+ # which fermions to exchange
+ if(len(fIndex)==2) :
+ isp = (fIndex[0],)
+ ibar = (fIndex[1],)
+ else :
+ if(ifunction==1) :
+ isp = (fIndex[2],)
+ ibar = (fIndex[3],)
+ elif(ifunction==2) :
+ isp = (fIndex[0],)
+ ibar = (fIndex[1],)
+ elif(ifunction==3) :
+ isp = (fIndex[0],fIndex[2])
+ ibar = (fIndex[1],fIndex[3])
+ # wavefunctions
+ for i in range(0,len(waves)) :
+ if(waves[i].find("Spinor")<0) :
+ waveNew.append(waves[i])
+ continue
+ if(waves[i].find("Bar")>0) :
+ found=False
+ for itest in range(0,len(ibar)) :
+ if(waves[i].find("sbarW%s"%ibar[itest])>=0) :
+ waveNew.append(waves[i].replace("Bar","").replace("bar",""))
+ found=True
+ break
+ if(not found) : waveNew.append(waves[i])
+ else :
+ found=False
+ for itest in range(0,len(isp)) :
+ if(waves[i].find("sW%s"%isp[itest])>=0) :
+ waveNew.append(waves[i].replace("Spinor","SpinorBar").replace(" s"," sbar"))
+ found=True
+ break
+ if(not found) : waveNew.append(waves[i])
+ # momenta definitions
+ for i in range(0,len(momenta)) :
+ if(momenta[i][0] and momenta[i][1]!="") :
+ if(momenta[i][1].find("barW")>0) :
+ found = False
+ for itest in range(0,len(ibar)) :
+ if(momenta[i][1].find("barW%s"%ibar[itest])>=0) :
+ momentastring+=momenta[i][1].replace("barW","W")+"\n "
+ found=True
+ break
+ if(not found) :
+ momentastring+=momenta[i][1]+"\n "
+ elif(momenta[i][1].find("sW")>0) :
+ found=False
+ for itest in range(0,len(isp)) :
+ if(momenta[i][1].find("sW%s"%isp[itest])>=0) :
+ momentastring+=momenta[i][1].replace("sW","sbarW")+"\n "
+ found=True
+ break
+ if(not found) :
+ momentastring+=momenta[i][1]+"\n "
+ else :
+ momentastring+=momenta[i][1]+"\n "
+ # header
+ for i in range(0,len(htemp)) :
+ if(htemp[i].find("Spinor")<0) : continue
+ if(htemp[i].find("Bar")>0) :
+ if(i==0) :
+ htemp[i] =htemp [i].replace("Bar","")
+ htemp2[i]=htemp2[i].replace("Bar","")
+ continue
+ for itest in range(0,len(ibar)) :
+ if(htemp[i].find("sbarW%s"%ibar[itest])>=0) :
+ htemp[i] =htemp [i].replace("Bar","").replace("sbarW","sW")
+ htemp2[i]=htemp2[i].replace("Bar","").replace("sbarW%s"%ibar[itest],"sW%s"%isp[itest])
+ break
+ else :
+ if(i==0) :
+ htemp [i]=htemp [i].replace("Spinor","SpinorBar")
+ htemp2[i]=htemp2[i].replace("Spinor","SpinorBar")
+ continue
+ for itest in range(0,len(isp)) :
+ if(htemp[i].find("sW%s"%isp[itest])>=0) :
+ htemp [i]=htemp [i].replace("Spinor","SpinorBar").replace("sW","sbarW")
+ htemp2[i]=htemp2[i].replace("Spinor","SpinorBar").replace("sW%s"%isp[itest],"sbarW%s"%ibar[itest])
+ break
+ # header for transposed function
+ hnew = ','.join(htemp)
+ hnew = hnew.replace("virtual ","").replace("=-GeV","")
+ if(not RS) :
+ theader = ','.join(htemp2)
+ theader = theader.replace("virtual ","").replace("=-GeV","")
+ if(len(result)==2) :
+ hnew =hnew .replace("evaluate","evaluateT")
+ theader=theader.replace("evaluate","evaluateT")
+ else :
+ hnew =hnew .replace("evaluate","evaluateT%s" % ifunction)
+ theader=theader.replace("evaluate","evaluateT%s" % ifunction)
+ if(iloc not in fIndex) :
+ theader = headerReplace(theader)
+ else :
+ theader = headerReplace(h2).replace("evaluateN","evaluateT")
+ headers.append(theader)
+ newHeader += hnew +";\n"
+ else :
+ newHeader += hnew
+ fnew = evaluateTemplate.format(decl=hnew,momenta=momentastring,defns=defString,
+ waves="\n ".join(waveNew),symbols='\n '.join(symboldefs),
+ couplings="\n ".join(localCouplings),
+ result=result[ifunction],swap=sorder)
+ function +="\n" + fnew
+
+
+ if(FM and not RS) :
+ if(len(result)==2) :
+ if(iloc!=fIndex[1]) :
+ fi=1
+ stype="sbar"
+ else :
+ fi=0
+ stype="s"
+ header = vTemplateT.format(header=header.replace("Energy2,","Energy2 q2,"),
+ normal=headerReplace(h2),
+ transpose=theader,type=stype,
+ iloc=fIndex[fi],id=vertex.particles[fIndex[fi]-1].pdg_code) \
+ +newHeader+h2.replace("virtual","")
+ else :
+ sorder = swapOrderFFFF(vertex,iloc,fIndex)
+ header = vTemplate4.format(header=header.replace("Energy2,","Energy2 q2,"),
+ iloc1=fIndex[1],iloc2=fIndex[3],swap=sorder,
+ id1=vertex.particles[fIndex[1]-1].pdg_code,
+ id2=vertex.particles[fIndex[3]-1].pdg_code,
+ cf=py2cpp(cf)[0],
+ res1=headerReplace(h2).replace("W",""),
+ res2=headers[0].replace("W",""),
+ res3=headers[1].replace("W",""),
+ res4=headers[2].replace("W",""))\
+ +newHeader+h2.replace("virtual","")
+ else :
+ header=header + ";\n" + newHeader
+ return (header,function)
+
+
+evaluateMultiple = """\
+{decl} {{
+{code}
+}}
+"""
+
+def multipleEvaluate(vertex,spin,defns) :
+ if(spin==1) :
+ name="scaW"
+ elif(spin==3) :
+ name="vW"
+ else :
+ print 'Evaluate multiple problem',spin
+ raise SkipThisVertex()
+ if(len(defns)==0) : return ("","")
+ header = defns[0]
+ ccdefn = header.replace("=-GeV","").replace("virtual ","").replace("Energy2","Energy2 q2")
+ code=""
+ spins=vertex.lorentz[0].spins
+ iloc=1
+ waves=[]
+ for i in range(0,len(spins)) :
+ if(spins[i]==spin) :
+ waves.append("%s%s" %(name,i+1))
+ for i in range(0,len(spins)) :
+ if(spins[i]==spin) :
+ if(iloc==1) : el=""
+ else : el="else "
+ call = headerReplace(defns[iloc])
+ if(iloc!=1) :
+ call = call.replace(waves[0],waves[iloc-1])
+ pdgid = vertex.particles[i].pdg_code
+ code += " %sif(out->id()==%s) return %s;\n" % (el,pdgid,call)
+ iloc+=1
+ code+=" else assert(false);\n"
+ return (header,evaluateMultiple.format(decl=ccdefn,code=code))
+
+
diff --git a/Models/Feynrules/python/ufo2peg/helpers.py b/Models/Feynrules/python/ufo2peg/helpers.py
--- a/Models/Feynrules/python/ufo2peg/helpers.py
+++ b/Models/Feynrules/python/ufo2peg/helpers.py
@@ -1,273 +1,266 @@
from string import Template
from os import path
import sys,cmath
import re
"""
Helper functions for the Herwig Feynrules converter
"""
class CheckUnique:
"""Uniqueness checker.
An object of this class remembers the value it was called with first.
Any subsequent call to it will only succeed if the same value is passed again.
For example,
>>> f = CheckUnique()
>>> f(5)
>>> f(5)
>>> f(4)
Traceback (most recent call last):
...
AssertionError
"""
def __init__(self):
self.val = None
def __call__(self,val):
"""Store value on first call, then compare."""
if self.val is None:
self.val = val
else:
assert( val == self.val )
def is_number(s):
"""Check if a value is a number."""
try:
float(s)
except ValueError:
return False
return True
def getTemplate(name):
"""Create a python string template from a file."""
templatename = '{name}.template'.format(name=name)
# assumes the template files sit next to this script
moduledir = path.dirname(path.abspath(__file__))
templatepath = path.join(moduledir,templatename)
with open(templatepath, 'r') as f:
templateText = f.read()
return Template( templateText )
-
def writeFile(filename, text):
"""Write text to a filename."""
with open(filename,'w') as f:
f.write(text)
-
-
-
-
-def qcd_qed_orders(vertex, coupling):
+def coupling_orders(vertex, coupling, defns):
# if more than one take QCD over QED and then lowest order in QED
if type(coupling) is list:
+ print 'not sure this happens'
+ quit()
qed = 0
qcd = 0
for coup in coupling :
qed1 = coup.order.get('QED',0)
qcd1 = coup.order.get('QCD',0)
if qcd1 != 0:
if qcd == 0 or (qcd1 != 0 and qcd1 < qcd):
qcd=qcd1
qed=qed1
else:
if qed == 0 or (qed1 != 0 and qed1 < qed):
qed=qed1
else:
- qed = coupling.order.get('QED',0)
- qcd = coupling.order.get('QCD',0)
- # WARNING: FIX FOR CASES WHEN BOTH ARE ZERO
- # Is there a better way to treat this?
- if qed + qcd + 2 != len(vertex.particles):
- qed = len(vertex.particles) - qcd - 2
-
- return qcd, qed
+ output={}
+ for ctype in defns :
+ output[ctype]=coupling.order.get(ctype,0)
+ return output
def def_from_model(FR,s):
"""Return a C++ line that defines parameter s as coming from the model file."""
if("hw_kine" in s) :return ""
stype = typemap(getattr(FR.parameters,s).type)
return '{t} {s} = model_->{s}();'.format(t=stype,s=s)
_typemap = {'complex':'Complex',
'real':'double'}
def typemap(s):
return _typemap[s]
def add_brackets(expr, syms):
result = expr
for s in syms:
pattern = r'({symb})(\W|$)'.format(symb=s)
result = re.sub(pattern, r'\1()\2', result)
return result
def banner():
return """\
===============================================================================================================
______ ______ _ __ _ _ _
| ___| | ___ \ | | / /| | | | (_) _ _
| |_ ___ _ _ _ __ | |_/ /_ _ | | ___ ___ / / | |_| | ___ _ __ __ __ _ __ _ _| |_ _| |_
| _|/ _ \| | | || \_ \ | /| | | || | / _ \/ __| / / | _ | / _ \| \__|\ \ /\ / /| | / _` ||_ _||_ _|
| | | __/| |_| || | | || |\ \| |_| || || __/\__ \ / / | | | || __/| | \ V V / | || (_| | |_| |_|
\_| \___| \__, ||_| |_|\_| \_|\__,_||_| \___||___//_/ \_| |_/ \___||_| \_/\_/ |_| \__, |
__/ | __/ |
|___/ |___/
===============================================================================================================
generating model/vertex/.model/.in files
please be patient!
===============================================================================================================
"""
#################### ??? #######################
# function that replaces alphaS (aS)-dependent variables
# with their explicit form which also contains strongCoupling
def aStoStrongCoup(stringin, paramstoreplace, paramstoreplace_expressions):
#print stringin
for xx in range(0,len(paramstoreplace)):
#print paramstoreplace[xx], paramstoreplace_expressions[xx]
stringout = stringin.replace(paramstoreplace[xx], '(' + PyMathToThePEGMath(paramstoreplace_expressions[xx],allparams) + ')')
stringout = stringout.replace('aS', '(sqr(strongCoupling(q2))/(4.0*Constants::pi))')
#print 'resulting string', stringout
return stringout
# function that replaces alphaEW (aEW)-dependent variables
# with their explicit form which also contains weakCoupling
def aEWtoWeakCoup(stringin, paramstoreplace, paramstoreplace_expressions):
#print stringin
for xx in range(0,len(paramstoreplace)):
#print paramstoreplace[xx], paramstoreplace_expressions[xx]
stringout = stringin.replace(paramstoreplace[xx], '(' + PyMathToThePEGMath(paramstoreplace_expressions[xx],allparams) + ')')
stringout = stringout.replace('aEWM1', '(1/(sqr(electroMagneticCoupling(q2))/(4.0*Constants::pi)))')
#print 'resulting string', stringout
return stringout
if __name__ == "__main__":
import doctest
doctest.testmod()
if False:
# Check if the Vertex is self-conjugate or not
pdgcode = [0,0,0,0]
notsmvertex = False
vhasw = 0
vhasz = 0
vhasf = 0
vhasg = 0
vhash = 0
vhasp = 0
# print 'printing particles in vertex'
for i in range(len(v.particles)):
# print v.particles[i].pdg_code
pdgcode[i] = v.particles[i].pdg_code
if pdgcode[i] == 23:
vhasz += 1
if pdgcode[i] == 22:
vhasp += 1
if pdgcode[i] == 25:
vhash += 1
if pdgcode[i] == 21:
vhasg += 1
if pdgcode[i] == 24:
vhasw += 1
if abs(pdgcode[i]) < 7 or (abs(pdgcode[i]) > 10 and abs(pdgcode[i]) < 17):
vhasf += 1
if pdgcode[i] not in SMPARTICLES:
notsmvertex = True
# treat replacement of SM vertices with BSM vertices?
if notsmvertex == False:
if( (vhasf == 2 and vhasz == 1) or (vhasf == 2 and vhasw == 1) or (vhasf == 2 and vhash == 1) or (vhasf == 2 and vhasg == 1) or (vhasf == 2 and vhasp == 0) or (vhasg == 3) or (vhasg == 4) or (vhasw == 2 and vhash == 1) or (vhasw == 3) or (vhasw == 4) or (vhash == 1 and vhasg == 2) or (vhash == 1 and vhasp == 2)):
#print 'VERTEX INCLUDED IN STANDARD MODEL!'
v.include = 0
notincluded += 1
#continue
selfconjugate = 0
for j in range(len(pdgcode)):
for k in range(len(pdgcode)):
if j != k and j != 0 and abs(pdgcode[j]) == abs(pdgcode[k]):
selfconjugate = 1
#print 'self-conjugate vertex'
# print pdgcode[j]
# if the Vertex is not self-conjugate, then add the conjugate vertex
# automatically
scfac = [1,1,1,1]
if selfconjugate == 0:
#first find the self-conjugate particles
for u in range(len(v.particles)):
if v.particles[u].selfconjugate == 0:
scfac[u] = -1
# print 'particle ', v.particles[u].pdg_code, ' found not to be self-conjugate'
if selfconjugate == 0:
plistarray[1] += str(scfac[1] * v.particles[1].pdg_code) + ',' + str(scfac[0] * v.particles[0].pdg_code) + ',' + str(scfac[2] * v.particles[2].pdg_code)
if len(v.particles) is 4:
plistarray[1] += ',' + str(scfac[3] * v.particles[3].pdg_code)
#print 'Conjugate vertex:', plistarray[1]
class SkipThisVertex(Exception):
pass
def extractAntiSymmetricIndices(instring,funct) :
terms = instring.strip(funct).strip(")").split(",")
sign=1.
for iy in range(0,len(terms)) :
for ix in range(-1,-len(terms)+iy,-1) :
swap = False
if(len(terms[ix])==1 and len(terms[ix-1])==1) :
swap = int(terms[ix])<int(terms[ix-1])
elif(len(terms[ix])==2 and len(terms[ix-1])==2) :
swap = int(terms[ix][1])<int(terms[ix-1][1])
elif(len(terms[ix])==1 and len(terms[ix-1])==2) :
swap = True
if(swap) :
sign *=-1.
terms[ix],terms[ix-1] = terms[ix-1],terms[ix]
return (terms,sign)
def isGoldstone(p) :
"""check if particle is a Goldstone"""
def gstest(name):
try:
return getattr(p,name)
except AttributeError:
return False
# names of goldstone bosons
gsnames = ['goldstone','goldstoneboson','GoldstoneBoson']
if any(map(gstest, gsnames)):
return True
return False
def isGhost(p) :
"""Check if particle is a ghost"""
try:
getattr(p,'GhostNumber')
except AttributeError:
return False
return p.GhostNumber != 0
diff --git a/Models/Feynrules/python/ufo2peg/vertices.py b/Models/Feynrules/python/ufo2peg/vertices.py
--- a/Models/Feynrules/python/ufo2peg/vertices.py
+++ b/Models/Feynrules/python/ufo2peg/vertices.py
@@ -1,663 +1,851 @@
import sys,pprint
-from .helpers import CheckUnique,getTemplate,writeFile,qcd_qed_orders,def_from_model
+from .helpers import CheckUnique,getTemplate,writeFile,coupling_orders,def_from_model
from .converter import py2cpp
from .collapse_vertices import collapse_vertices
from .check_lorentz import tensorCouplings,VVVordering,lorentzScalar,\
processTensorCouplings,scalarCouplings,processScalarCouplings,scalarVectorCouplings,\
processScalarVectorCouplings,vectorCouplings,processVectorCouplings,fermionCouplings,processFermionCouplings,\
RSCouplings
+from .general_lorentz import convertLorentz,generateEvaluateFunction,multipleEvaluate
from .helpers import SkipThisVertex,extractAntiSymmetricIndices,isGoldstone
# prefactors for vertices
lfactors = {
'FFV' : '-complex(0,1)', # ok
'VVV' : 'complex(0,1)', # changed to fix ttbar
'VVVS' : 'complex(0,1)', # should be as VVV
'VVVV' : 'complex(0,1)',
'VVS' : '-complex(0,1)',
'VSS' : '-complex(0,1)', # changed to minus to fix dL ->x1 W- d
'SSS' : '-complex(0,1)', # ok
'VVSS' : '-complex(0,1)', # ok
'VVT' : 'complex(0,2)',
'VVVT' : '-complex(0,2)',
'SSSS' : '-complex(0,1)', # ok
'FFS' : '-complex(0,1)', # ok
'SST' : 'complex(0,2)',
'FFT' : '-complex(0,8)',
'FFVT' : '-complex(0,4)',
'RFS' : 'complex(0,1)',
'RFV' : 'complex(0,1)',
}
+genericVertices=['FFFF','FFVV','FFSS','FFVS','VVVV','VVVT','FFVT',
+ 'RFVV','RFVS','RFSS','SSST','VVST','FFST']
+
+skipped5Point=False
+
# template for the header for a vertex
VERTEXHEADER = """\
#include "ThePEG/Helicity/Vertex/{spindirectory}/{lorentztag}Vertex.h"
"""
+GENERALVERTEXHEADER = """\
+#include "ThePEG/Helicity/Vertex/Abstract{lorentztag}Vertex.h"
+"""
# template for the implmentation for a vertex
VERTEXCLASS = getTemplate('Vertex_class')
+GENERALVERTEXCLASS = getTemplate('GeneralVertex_class')
# template for the .cc file for vertices
VERTEX = getTemplate('Vertex.cc')
vertexline = """\
-create Herwig::{modelname}V_{vname} /Herwig/{modelname}/V_{vname}
-insert {modelname}:ExtraVertices 0 /Herwig/{modelname}/V_{vname}
+create Herwig::FRModel{classname} /Herwig/{modelname}/{classname}
+insert {modelname}:ExtraVertices 0 /Herwig/{modelname}/{classname}
"""
-
def get_lorentztag(spin):
"""Produce a ThePEG spin tag for the given numeric FR spins."""
spins = { 1 : 'S', 2 : 'F', 3 : 'V', 4 : 'R', 5 : 'T', -1 : 'U' }
result=[]
for i in range(0,len(spin)) :
result.append((spins[spin[i]],i+1))
def spinsort(a,b):
"""Helper function for ThePEG's FVST spin tag ordering."""
(a1,a2) = a
(b1,b2) = b
if a1 == b1: return 0
for letter in 'URFVST':
if a1 == letter: return -1
if b1 == letter: return 1
result = sorted(result, cmp=spinsort)
order=[]
output=""
for i in range(0,len(result)) :
(a,b) = result[i]
order.append(b)
output+=a
return (output,order)
def unique_lorentztag(vertex):
"""Check and return the Lorentz tag of the vertex."""
unique = CheckUnique()
for l in vertex.lorentz:
(lorentztag,order) = get_lorentztag(l.spins)
unique( lorentztag )
lname = l.name[:len(lorentztag)]
if sorted(lorentztag) != sorted(lname):
raise Exception("Lorentztags: %s is not %s in %s"
% (lorentztag,lname,vertex))
return (lorentztag,order)
def colors(vertex) :
try:
unique = CheckUnique()
for pl in vertex.particles_list:
struct = [ p.color for p in pl ]
unique(struct)
except:
struct = [ p.color for p in vertex.particles ]
pos = colorpositions(struct)
L = len(struct)
return (L,pos)
+def coloursort(a,b) :
+ if a == b: return 0
+ i1=int(a[4])
+ i2=int(b[4])
+ if(i1==i2) : return 0
+ elif(i1<i2) : return -1
+ else : return 1
+
def colorfactor(vertex,L,pos,lorentztag):
def match(patterns,color=vertex.color):
result = [ p == t
for p,t in zip(patterns,color) ]
return all(result)
label = None
l = lambda c: len(pos[c])
if l(1) == L:
label = ('1',)
- if match(label): return ('1',)
+ if match(label): return ("SINGLET",('1.',))
elif l(3) == l(-3) == 1 and l(1) == L-2:
nums = [pos[3][0], pos[-3][0]]
label = ('Identity({0},{1})'.format(*sorted(nums)),)
- if match(label): return ('1',)
+ if match(label): return ("DELTA",('1.',))
elif l(6) == l(-6) == 1 and l(1) == L-2:
nums = [pos[6][0], pos[-6][0]]
label = ('Identity({0},{1})'.format(*sorted(nums)),)
- if match(label): return ('1',)
+ if match(label): return ("DELTA",('1.',))
elif l(6) == l(-6) == 2 and L==4:
sys.stderr.write(
'Warning: Unknown colour structure 6 6 6~ 6~ ( {ps} ) in {name}.\n'
.format(name=vertex.name, ps=' '.join(map(str,vertex.particles)))
)
raise SkipThisVertex()
elif l(8) == l(3) == l(-3) == 1 and l(1) == L-3:
label = ('T({g},{q},{qb})'.format(g=pos[8][0],q=pos[3][0],qb=pos[-3][0]),)
- if match(label): return ('1',)
+ if match(label): return ("SU3TFUND",('1.',))
elif l(8) == l(6) == l(-6) == 1 and l(1) == L-3:
label = ('T6({g},{s},{sb})'.format(g=pos[8][0],s=pos[6][0],sb=pos[-6][0]),)
- if match(label): return ('1',)
+ if match(label): return ("SU3T6",('1.',))
elif l(6) == 1 and l(-3) == 2 and L==3:
label = ('K6({s},{qb1},{qb2})'.format(s=pos[6][0],qb1=pos[-3][0],qb2=pos[-3][1]),)
- if match(label): return ('1',)
+ if match(label): return ("SU3K6",('1.',))
elif l(-6) == 1 and l(3) == 2 and L==3:
label = ('K6Bar({sb},{q1},{q2})'.format(sb=pos[-6][0],q1=pos[3][0],q2=pos[3][1]),)
- if match(label): return ('1',)
+ if match(label): return ("SU3K6",('1.',))
elif l(3) == L == 3:
colors=[]
for color in vertex.color :
order,sign = extractAntiSymmetricIndices(color,"Epsilon(")
colors.append("Epsilon(%s,%s,%s)" % (order[0],order[1],order[2]))
label = ('Epsilon(1,2,3)',)
- if match(label,colors): return ('1',) # TODO check factor!
+ if match(label,colors): return ("EPS",('1.',)) # TODO check factor!
elif l(-3) == L == 3:
colors=[]
for color in vertex.color :
order,sign = extractAntiSymmetricIndices(color,"EpsilonBar(")
colors.append("Epsilon(%s,%s,%s)" % (order[0],order[1],order[2]))
label = ('EpsilonBar(1,2,3)',)
- if match(label): return ('1',) # TODO check factor!
+ if match(label): return ("EPS",('1.',)) # TODO check factor!
elif l(8) == L == 3:
colors=[]
for color in vertex.color :
order,sign = extractAntiSymmetricIndices(color,"f(")
colors.append("f(%s,%s,%s)" % (order[0],order[1],order[2]))
# if lorentz is FFV get extra minus sign
if lorentztag in ['FFV'] : sign *=-1
label = ('f(1,2,3)',)
- if match(label,colors): return ('-complex(0,1)*(%s)'%sign,)
+ if match(label,colors): return ("SU3F",('-complex(0,1.)*(%s)'%sign,))
+ elif l(8) == 3 and l(1)==1 and L == 4:
+ colors=[]
+ for color in vertex.color :
+ order,sign = extractAntiSymmetricIndices(color,"f(")
+ colors.append("f(%s,%s,%s)" % (order[0],order[1],order[2]))
+ if(pos[1][0]==1) :
+ label = ('f(2,3,4)',)
+ elif(pos[1][0]==2) :
+ label = ('f(1,3,4)',)
+ elif(pos[1][0]==3) :
+ label = ('f(1,2,4)',)
+ elif(pos[1][0]==4) :
+ label = ('f(1,2,3)',)
+ if match(label,colors): return ("SU3F",('-complex(0,1.)*(%s)'%sign,))
elif l(8) == L == 4:
colors=[]
for color in vertex.color :
f = color.split("*")
(o1,s1) = extractAntiSymmetricIndices(f[0],"f(")
(o2,s2) = extractAntiSymmetricIndices(f[1],"f(")
if(o2[0]<o1[0]) : o1,o2=o2,o1
colors.append("f(%s)*f(%s)" % (",".join(o1),",".join(o2)))
- def coloursort(a,b) :
- if a == b: return 0
- i1=int(a[4])
- i2=int(b[4])
- if(i1==i2) : return 0
- elif(i1<i2) : return -1
- else : return 1
colors=sorted(colors,cmp=coloursort)
label = ('f(1,2,-1)*f(3,4,-1)',
'f(1,3,-1)*f(2,4,-1)',
'f(1,4,-1)*f(2,3,-1)')
nmatch=0
for c1 in label:
for c2 in colors :
if(c1==c2) : nmatch+=1
if(nmatch==2 and lorentztag=="VVSS") :
- return ('1','1')
+ return ("SU3FF",('1.','1.'))
elif(nmatch==3 and lorentztag=="VVVV") :
- return ('-1.','-1.','-1.')
+ return ("SU3FF",('1.','1.','1.'))
elif l(8) == 2 and l(3) == l(-3) == 1 and L==4:
subs = {
'g1' : pos[8][0],
'g2' : pos[8][1],
'qq' : pos[3][0],
'qb' : pos[-3][0]
}
- label = ('T({g1},-1,{qb})*T({g2},{qq},-1)'.format(**subs),
- 'T({g1},{qq},-1)*T({g2},-1,{qb})'.format(**subs))
- if match(label): return ('1.','1.')
+ if(vertex.lorentz[0].spins.count(1)==2) :
+ label = ('T({g1},-1,{qb})*T({g2},{qq},-1)'.format(**subs),
+ 'T({g1},{qq},-1)*T({g2},-1,{qb})'.format(**subs))
+ if match(label): return ("SU3TTFUNDS",('1.','1.'))
+ elif(vertex.lorentz[0].spins.count(2)==2) :
+ label = ('f({g1},{g2},-1)*T(-1,{qq},{qb})'.format(**subs),)
+ if match(label): return ("SU3TTFUNDD",('-complex(0.,1.)',))
+ label = ('f(-1,{g1},{g2})*T(-1,{qq},{qb})'.format(**subs),)
+ if match(label): return ("SU3TTFUNDD",('-complex(0.,1.)',))
elif l(8) == 2 and l(6) == l(-6) == 1 and L==4:
subs = {
'g1' : pos[8][0],
'g2' : pos[8][1],
'qq' : pos[6][0],
'qb' : pos[-6][0]
}
label = ('T6({g1},-1,{qb})*T6({g2},{qq},-1)'.format(**subs),
'T6({g1},{qq},-1)*T6({g2},-1,{qb})'.format(**subs))
- if match(label): return ('1.','1.')
+ if match(label): return ("SU3TT6",('1.','1.'))
elif l(8) == 2 and l(8)+l(1)==L :
subs = { 'g1' : pos[8][0], 'g2' : pos[8][1] }
label = ('Identity({g1},{g2})'.format(**subs),)
- if match(label) : return ('1.',)
+ if match(label) : return ("DELTA",('1.',))
elif l(8) == 3 and l(1)==1 and L==4 :
colors=[]
for color in vertex.color :
order,sign = extractAntiSymmetricIndices(color,"f(")
colors.append("f(%s,%s,%s)" % (order[0],order[1],order[2]))
label = ('f(1,2,3)',)
- if match(label,colors): return ('-complex(0,1)*(%s)'%sign,)
+ if match(label,colors): return ("SU3F",('-complex(0.,1.)*(%s)'%sign,))
+ elif l(3)==2 and l(-3) == 2 and L==4 and lorentztag=="FFFF" :
+ labels=["Identity(1,2)*Identity(3,4)",
+ "Identity(1,4)*Identity(2,3)",
+ "T(-1,2,1)*T(-1,4,3)",
+ "T(-1,2,3)*T(-1,4,1)"]
+ cstruct=["SU3I12I34","SU3I14I23","SU3T21T43","SU3T23T41"]
+ oname=[]
+ ovalue=[]
+ for color in vertex.color :
+ for i in range(0,len(labels)) :
+ if labels[i]==color : break
+ if(i<len(labels)) :
+ oname.append(cstruct[i])
+ ovalue.append("1.")
+ else :
+ sys.stderr.write(
+ "Warning: Unknown colour structure {color} ( {ps} ) in {name} for FFFF vertex.\n"
+ .format(color = ' '.join(vertex.color), name = vertex.name,
+ ps = ' '.join(map(str,vertex.particles)))
+ )
+ raise SkipThisVertex()
+ return(oname,ovalue)
+
sys.stderr.write(
"Warning: Unknown colour structure {color} ( {ps} ) in {name}.\n"
.format(color = ' '.join(vertex.color), name = vertex.name,
ps = ' '.join(map(str,vertex.particles)))
)
raise SkipThisVertex()
def colorpositions(struct):
positions = {
1 : [],
3 : [],
-3 : [],
6 : [],
-6 : [],
8 : [],
}
for i,s in enumerate(struct,1):
positions[s].append(i)
return positions
def spindirectory(lt):
"""Return the spin directory name for a given Lorentz tag."""
if 'T' in lt:
spin_directory = 'Tensor'
elif 'S' in lt:
spin_directory = 'Scalar'
elif 'V' in lt:
spin_directory = 'Vector'
else:
raise Exception("Unknown Lorentz tag {lt}.".format(lt=lt))
return spin_directory
def write_vertex_file(subs):
'Write the .cc file for some vertices'
newname = '%s_Vertices_%03d.cc' % (subs['ModelName'],subs['vertexnumber'])
subs['newname'] = newname
writeFile( newname, VERTEX.substitute(subs) )
def checkGhostGoldstoneVertex(lorentztag,vertex) :
'check if vertex has ghosts or goldstones'
# remove vertices involving ghost fields
if 'U' in lorentztag:
return True
# remove vertices involving goldstones
for p in vertex.particles:
if(isGoldstone(p)):
return True
return False
-def calculatePrefactor(globalsign,lorentztag,lf,cf) :
- if(globalsign!=1.) :
- prefactors = '(%s) * (%s) * (%s)' \
- % (globalsign**(len(lorentztag)-2),lf,cf)
- else :
- prefactors = '(%s) * (%s)' \
- % (lf,cf)
- return prefactors
- # fact=[]
- # if(globalsign!=1.) :
- # fact.append(globalsign**(len(lorentztag)-2))
- # if(lf!="1") :
- # fact.append(lf)
- # if(cf!="1") :
- # fact.append(cf)
- # if(len(fact)==0) : return "1"
- # prefactor = '(%s)' % fact[0]
- # for ix in range(1,len(fact)) :
- # prefactor = '%s * (%s)' % (prefactor,fact[ix])
- # return prefactor
+def calculatePrefactor(lf,cf) :
+ prefactor = '(%s) * (%s)' % (lf,cf)
+ return prefactor
def couplingValue(coupling) :
if type(coupling) is not list:
value = coupling.value
else:
value = "("
for coup in coupling :
value += '+(%s)' % coup.value
value +=")"
return value
def epsilonSign(vertex,couplingptrs,append) :
EPSSIGN = """\
double sign = {epssign};
if((p1->id()=={id1} && p2->id()=={id3} && p3->id()=={id2}) ||
(p1->id()=={id2} && p2->id()=={id1} && p3->id()=={id3}) ||
(p1->id()=={id3} && p2->id()=={id2} && p3->id()=={id1})) {{
sign *= -1.;
}}
norm(norm()*sign);
"""
if(not "p1" in couplingptrs[0]) :
couplingptrs[0] += ' p1'
if(not "p2" in couplingptrs[1]) :
couplingptrs[1] += ' p2'
if(not "p3" in couplingptrs[2]) :
couplingptrs[2] += ' p3'
if("Bar" not in vertex.color[0]) :
order,sign = extractAntiSymmetricIndices(vertex.color[0],"Epsilon(")
else :
order,sign = extractAntiSymmetricIndices(vertex.color[0],"EpsilonBar(")
subs = {"id1" : vertex.particles[int(order[0])-1].pdg_code,
"id2" : vertex.particles[int(order[1])-1].pdg_code,
"id3" : vertex.particles[int(order[2])-1].pdg_code,
"epssign" : sign }
append+=EPSSIGN.format(**subs)
return couplingptrs,append
class VertexConverter:
'Convert the vertices in a FR model to extract the information ThePEG needs.'
- def __init__(self,model,parmsubs) :
+ def __init__(self,model,parmsubs,defns) :
'Initialize the parameters'
- self.ONE_EACH=True
self.verbose=False
self.vertex_skipped=False
self.ignore_skipped=False
self.model=model
self.all_vertices= []
+ self.vertex_names = {}
self.modelname=""
- self.globalsign=self.global_sign()
self.no_generic_loop_vertices = False
self.parmsubs = parmsubs
-
- def global_sign(self):
- 'Initial pass to find global sign at the moment does nothing'
- return 1.0
- # for v in self.model.all_vertices:
- # pids = sorted([ p.pdg_code for p in v.particles ])
- # if pids != [-11,11,22]: continue
- # coup = v.couplings
- # assert( len(coup) == 1 )
- # val = coup.values()[0].value
- # val = evaluate(val)
- # assert( val.real == 0 )
- # return 1 if val.imag > 0 else -1
+ self.couplingDefns = defns
+ self.genericTensors = False
def readArgs(self,args) :
'Extract the relevant command line arguments'
self.ignore_skipped = args.ignore_skipped
self.verbose = args.verbose
self.modelname = args.name
self.no_generic_loop_vertices = args.no_generic_loop_vertices
-
+ self.include_generic = args.include_generic
+ self.genericTensors = args.use_generic_for_tensors
+
def should_print(self) :
'Check if we should output the results'
return not self.vertex_skipped or self.ignore_skipped
def convert(self) :
'Convert the vertices'
if(self.verbose) :
print 'verbose mode on: printing all vertices'
print '-'*60
labels = ('vertex', 'particles', 'Lorentz', 'C_L', 'C_R', 'norm')
pprint.pprint(labels)
- # check if we should merge vertices
- if(self.ONE_EACH) :
- self.all_vertices = self.model.all_vertices
- else:
- self.all_vertices = collapse_vertices(self.model.all_vertices)
+ # extract the vertices
+ self.all_vertices = self.model.all_vertices
# convert the vertices
vertexclasses, vertexheaders = [], set()
+ ifile=1
+ icount=0
for vertexnumber,vertex in enumerate(self.all_vertices,1) :
# process the vertex
(skip,vertexClass,vertexHeader) = \
self.processVertex(vertexnumber,vertex)
# check it can be handled
if(skip) : continue
# add to the list
+ icount +=1
vertexclasses.append(vertexClass)
vertexheaders.add(vertexHeader)
WRAP = 25
- if vertexnumber % WRAP == 0:
- write_vertex_file({'vertexnumber' : vertexnumber//WRAP,
+ if icount % WRAP == 0 or vertexHeader.find("Abstract")>=0:
+ write_vertex_file({'vertexnumber' : ifile,
'vertexclasses' : '\n'.join(vertexclasses),
'vertexheaders' : ''.join(vertexheaders),
'ModelName' : self.modelname})
vertexclasses = []
vertexheaders = set()
+ icount=0
+ ifile+=1
# exit if there's vertices we can't handle
if not self.should_print():
sys.stderr.write(
"""
Error: The conversion was unsuccessful, some vertices could not be
generated. If you think the missing vertices are not important
and want to go ahead anyway, use --ignore-skipped.
Herwig may not give correct results, though.
"""
)
sys.exit(1)
# if still stuff to output it do it
if vertexclasses:
- write_vertex_file({'vertexnumber' : vertexnumber//WRAP + 1,
+ write_vertex_file({'vertexnumber' : ifile + 1,
'vertexclasses' : '\n'.join(vertexclasses),
'vertexheaders' : ''.join(vertexheaders),
'ModelName' : self.modelname})
print '='*60
def setCouplingPtrs(self,lorentztag,qcd,append,prepend) :
couplingptrs = [',tcPDPtr']*len(lorentztag)
if lorentztag == 'VSS':
couplingptrs[1] += ' p2'
elif lorentztag == 'FFV':
couplingptrs[0] += ' p1'
elif (lorentztag == 'VVV' or lorentztag == 'VVVS' or
lorentztag == "SSS" or lorentztag == "VVVT" ) \
and (append or prepend ) :
couplingptrs[0] += ' p1'
couplingptrs[1] += ' p2'
couplingptrs[2] += ' p3'
- elif (lorentztag == 'VVVV' and qcd != 2) or\
+ elif (lorentztag == 'VVVV' and qcd < 2) or\
(lorentztag == "SSSS" and prepend ):
couplingptrs[0] += ' p1'
couplingptrs[1] += ' p2'
couplingptrs[2] += ' p3'
couplingptrs[3] += ' p4'
return couplingptrs
def processVertex(self,vertexnumber,vertex) :
+ global skipped5Point
# get the Lorentz tag for the vertex
lorentztag,order = unique_lorentztag(vertex)
# check if we should skip the vertex
vertex.herwig_skip_vertex = checkGhostGoldstoneVertex(lorentztag,vertex)
+ # check the order of the vertex and skip 5 points
+ if(len(lorentztag)>=5) :
+ vertex.herwig_skip_vertex = True
+ if(not skipped5Point) :
+ skipped5Point = True
+ print "Skipping 5 point vertices which aren\'t used in Herwig7"
+
if(vertex.herwig_skip_vertex) :
return (True,"","")
- # get the factor for the vertex
- try:
- lf = lfactors[lorentztag]
- except KeyError:
+ # check if we support this at all
+ if( lorentztag not in lfactors and
+ lorentztag not in genericVertices) :
msg = 'Warning: Lorentz structure {tag} ( {ps} ) in {name} ' \
'is not supported.\n'.format(tag=lorentztag, name=vertex.name,
ps=' '.join(map(str,vertex.particles)))
sys.stderr.write(msg)
vertex.herwig_skip_vertex = True
self.vertex_skipped=True
return (True,"","")
+ # get the factor for the vertex
+ generic = False
+ try:
+ lf = lfactors[lorentztag]
+ if( self.genericTensors and "T" in lorentztag) :
+ raise KeyError()
+ except KeyError:
+ if(not self.include_generic) :
+ msg = 'Warning: Lorentz structure {tag} ( {ps} ) in {name} ' \
+ 'is not supported.\n'.format(tag=lorentztag, name=vertex.name,
+ ps=' '.join(map(str,vertex.particles)))
+ sys.stderr.write(msg)
+ vertex.herwig_skip_vertex = True
+ self.vertex_skipped=True
+ return (True,"","")
+ else :
+ lf=1.
+ generic=True
# get the ids of the particles at the vertex
- if self.ONE_EACH:
- plistarray = [ ','.join([ str(vertex.particles[o-1].pdg_code) for o in order ]) ]
- else:
- plistarray = [ ','.join([ str(p.pdg_code) for p in pl ])
- for pl in vertex.particles_list ]
+ plistarray = [ ','.join([ str(vertex.particles[o-1].pdg_code) for o in order ]) ]
# parse the colour structure for the vertex
try:
L,pos = colors(vertex)
- cf = colorfactor(vertex,L,pos,lorentztag)
+ cs,cf = colorfactor(vertex,L,pos,lorentztag)
except SkipThisVertex:
msg = 'Warning: Color structure for vertex ( {ps} ) in {name} ' \
'is not supported.\n'.format(tag=lorentztag, name=vertex.name,
ps=' '.join(map(str,vertex.particles)))
sys.stderr.write(msg)
vertex.herwig_skip_vertex = True
self.vertex_skipped=True
return (True,"","")
-
### classname
classname = 'V_%s' % vertex.name
- # try to extract the couplings
- try:
- (all_couplings,header,qcd,qed,prepend,append) = \
- self.extractCouplings(lorentztag,pos,lf,cf,vertex,order)
- except SkipThisVertex:
- msg = 'Warning: Lorentz structure {tag} ( {ps} ) in {name} ' \
- 'is not supported, may have a non-perturbative form.\n'.format(tag=lorentztag, name=vertex.name,
- ps=' '.join(map(str,vertex.particles)))
- sys.stderr.write(msg)
- vertex.herwig_skip_vertex = True
- self.vertex_skipped=True
- return (True,"","")
-
- # set the coupling ptrs in the setCoupling call
- couplingptrs = self.setCouplingPtrs(lorentztag,qcd,append != '',prepend != '')
-
- # final processing of the couplings
- try :
+ if(not generic) :
+ try :
+ return self.extractGeneric(vertex,order,lorentztag,classname,plistarray,pos,lf,cf,cs)
+ except SkipThisVertex:
+ if(not self.include_generic) :
+ msg = 'Warning: Lorentz structure {tag} ( {ps} ) in {name} ' \
+ 'is not supported, may have a non-perturbative form.\n'.format(tag=lorentztag, name=vertex.name,
+ ps=' '.join(map(str,vertex.particles)))
+
+ sys.stderr.write(msg)
+ vertex.herwig_skip_vertex = True
+ self.vertex_skipped=True
+ return (True,"","")
+ else :
+ try :
+ return self.extractGeneral(vertex,order,lorentztag,classname,plistarray,pos,cf,cs)
+ except SkipThisVertex:
+ msg = 'Warning: Lorentz structure {tag} ( {ps} ) in {name} ' \
+ 'is not supported, may have a non-perturbative form.\n'.format(tag=lorentztag, name=vertex.name,
+ ps=' '.join(map(str,vertex.particles)))
+
+ sys.stderr.write(msg)
+ vertex.herwig_skip_vertex = True
+ self.vertex_skipped=True
+ return (True,"","")
+ else :
+ try :
+ return self.extractGeneral(vertex,order,lorentztag,classname,plistarray,pos,cf,cs)
+ except SkipThisVertex:
+ msg = 'Warning: Lorentz structure {tag} ( {ps} ) in {name} ' \
+ 'is not supported, may have a non-perturbative form.\n'.format(tag=lorentztag, name=vertex.name,
+ ps=' '.join(map(str,vertex.particles)))
+
+ sys.stderr.write(msg)
+ vertex.herwig_skip_vertex = True
+ self.vertex_skipped=True
+ return (True,"","")
+
+
+ def extractGeneric(self,vertex,order,lorentztag,classname,plistarray,pos,lf,cf,cs) :
+ classes=""
+ headers=""
+ # identify the maximum colour flow and orders of the couplings
+ maxColour=0
+ couplingOrders=[]
+ self.vertex_names[vertex.name] = [classname]
+ for (color_idx,lorentz_idx),coupling in vertex.couplings.iteritems():
+ maxColour=max(maxColour,color_idx)
+ orders = coupling_orders(vertex, coupling, self.couplingDefns)
+ if(orders not in couplingOrders) : couplingOrders.append(orders)
+ # loop the order of the couplings
+ iorder = 0
+ for corder in couplingOrders :
+ iorder +=1
+ cname=classname
+ if(iorder!=1) :
+ cname= "%s_%s" % (classname,iorder)
+ self.vertex_names[vertex.name].append(cname)
+ header = ""
+ prepend=""
+ append=""
+ all_couplings=[]
+ for ix in range(0,maxColour+1) :
+ all_couplings.append([])
+ # loop over the colour structures
+ for colour in range(0,maxColour+1) :
+ for (color_idx,lorentz_idx),coupling in vertex.couplings.iteritems() :
+ # check colour structure and coupling order
+ if(color_idx!=colour) : continue
+ if(coupling_orders(vertex, coupling, self.couplingDefns)!=corder) : continue
+ # get the prefactor for the lorentz structure
+ L = vertex.lorentz[lorentz_idx]
+ prefactors = calculatePrefactor(lf,cf[color_idx])
+ # calculate the value of the coupling
+ value = couplingValue(coupling)
+ # handling of the different types of couplings
+ if lorentztag in ['FFS','FFV']:
+ all_couplings[color_idx] = fermionCouplings(value,prefactors,L,all_couplings[color_idx],order)
+ elif 'T' in lorentztag :
+ append, all_couplings[color_idx] = tensorCouplings(vertex,value,prefactors,L,lorentztag,pos,
+ all_couplings[color_idx],order)
+ elif 'R' in lorentztag :
+ all_couplings[color_idx] = RSCouplings(value,prefactors,L,all_couplings[color_idx],order)
+ elif lorentztag == 'VVS' or lorentztag == "VVSS" or lorentztag == "VSS" :
+ all_couplings[color_idx] = scalarVectorCouplings(value,prefactors,L,lorentztag,
+ all_couplings[color_idx],order)
+ elif lorentztag == "SSS" or lorentztag == "SSSS" :
+ prepend, header, all_couplings[color_idx] = scalarCouplings(vertex,value,prefactors,L,lorentztag,
+ all_couplings[color_idx],prepend,header)
+ elif "VVV" in lorentztag :
+ all_couplings[color_idx],append = vectorCouplings(vertex,value,prefactors,L,lorentztag,pos,
+ all_couplings[color_idx],append,corder["QCD"],order)
+ else:
+ raise SkipThisVertex()
+ # set the coupling ptrs in the setCoupling call
+ couplingptrs = self.setCouplingPtrs(lorentztag,corder["QCD"],append != '',prepend != '')
+ # final processing of the couplings
symbols = set()
if(lorentztag in ['FFS','FFV']) :
(normcontent,leftcontent,rightcontent,append) = processFermionCouplings(lorentztag,vertex,
self.model,self.parmsubs,
- all_couplings)
+ all_couplings,order)
elif('T' in lorentztag) :
(leftcontent,rightcontent,normcontent) = processTensorCouplings(lorentztag,vertex,self.model,
- self.parmsubs,all_couplings)
+ self.parmsubs,all_couplings,order)
elif(lorentztag=="SSS" or lorentztag=="SSSS") :
normcontent = processScalarCouplings(self.model,self.parmsubs,all_couplings)
elif(lorentztag=="VVS" or lorentztag =="VVSS" or lorentztag=="VSS") :
normcontent,append,lorentztag,header,sym = processScalarVectorCouplings(lorentztag,vertex,
self.model,self.parmsubs,
all_couplings,header,order)
symbols |=sym
elif("VVV" in lorentztag) :
normcontent,append,header =\
processVectorCouplings(lorentztag,vertex,self.model,self.parmsubs,all_couplings,append,header)
else :
SkipThisVertex()
- except SkipThisVertex:
- msg = 'Warning: Lorentz structure {tag} ( {ps} ) in {name} ' \
- 'is not supported, may have a non-perturbative form.\n'.format(tag=lorentztag, name=vertex.name,
- ps=' '.join(map(str,vertex.particles)))
+ ### do we need left/right?
+ if 'FF' in lorentztag and lorentztag != "FFT":
+ #leftcalc = aStoStrongCoup(py2cpp(leftcontent)[0], paramstoreplace_, paramstoreplace_expressions_)
+ #rightcalc = aStoStrongCoup(py2cpp(rightcontent)[0], paramstoreplace_, paramstoreplace_expressions_)
+ leftcalc, sym = py2cpp(leftcontent)
+ symbols |= sym
+ rightcalc, sym = py2cpp(rightcontent)
+ symbols |= sym
+ left = 'left(' + leftcalc + ');'
+ right = 'right(' + rightcalc + ');'
+ else:
+ left = ''
+ right = ''
+ leftcalc = ''
+ rightcalc = ''
+ #normcalc = aStoStrongCoup(py2cpp(normcontent)[0], paramstoreplace_, paramstoreplace_expressions_)
+ normcalc, sym = py2cpp(normcontent)
+ symbols |= sym
+ # UFO is GeV by default
+ if lorentztag in ['VVS','SSS']:
+ normcalc = 'Complex((%s) * GeV / UnitRemoval::E)' % normcalc
+ elif lorentztag in ['GeneralVVS']:
+ normcalc = 'Complex(-(%s) * UnitRemoval::E / GeV )' % normcalc
+ elif lorentztag in ['FFT','VVT', 'SST', 'FFVT', 'VVVT' , 'VVVS' ]:
+ normcalc = 'Complex((%s) / GeV * UnitRemoval::E)' % normcalc
+ norm = 'norm(' + normcalc + ');'
+ # finally special handling for eps tensors
+ if(len(vertex.color)==1 and vertex.color[0].find("Epsilon")>=0) :
+ couplingptrs, append = epsilonSign(vertex,couplingptrs,append)
+ # define unkown symbols from the model
+ symboldefs = [ def_from_model(self.model,s) for s in symbols ]
+ couplingOrder=""
+ for coupName,coupVal in corder.iteritems() :
+ couplingOrder+=" orderInCoupling(CouplingType::%s,%s);\n" %(coupName,coupVal)
+ ### assemble dictionary and fill template
+ subs = { 'lorentztag' : lorentztag, # ok
+ 'classname' : cname, # ok
+ 'symbolrefs' : '\n '.join(symboldefs),
+ 'left' : left, # doesn't always exist in base
+ 'right' : right, # doesn't always exist in base
+ 'norm' : norm, # needs norm, too
+ 'addToPlist' : '\n'.join([ 'addToList(%s);'%s for s in plistarray]),
+ 'parameters' : '',
+ 'couplingOrders' : couplingOrder,
+ 'colourStructure' : cs,
+ 'couplingptrs' : ''.join(couplingptrs),
+ 'spindirectory' : spindirectory(lorentztag),
+ 'ModelName' : self.modelname,
+ 'prepend' : prepend,
+ 'append' : append,
+ 'header' : header
+ } # ok
+
+ # print info if required
+ if self.verbose:
+ print '-'*60
+ pprint.pprint(( classname, plistarray, leftcalc, rightcalc, normcalc ))
+ headers+=VERTEXHEADER.format(**subs)
+ classes+=VERTEXCLASS.substitute(subs)
+ return (False,classes,headers)
+
+ def extractGeneral(self,vertex,order,lorentztag,classname,plistarray,pos,cf,cs) :
+ eps=False
+ classes=""
+ headers=""
+ # check the colour flows, three cases supported either 1 flow or 3 in gggg
+ # or multiple wierd ones in FFFF
+ cidx=-1
+ gluon4point = (len(pos[8])==4 and vertex.lorentz[0].spins.count(3)==4)
+ FFFF = (len(pos[3])==2 and len(pos[-3])==2 and vertex.lorentz[0].spins.count(2)==4)
+ couplingOrders=[]
+ colours={}
+
+ for (color_idx,lorentz_idx),coupling in vertex.couplings.iteritems() :
+ orders = coupling_orders(vertex, coupling, self.couplingDefns)
+ if(orders not in couplingOrders) : couplingOrders.append(orders)
+ if(gluon4point) :
+ color = vertex.color[color_idx]
+ f = color.split("*")
+ (o1,s1) = extractAntiSymmetricIndices(f[0],"f(")
+ (o2,s2) = extractAntiSymmetricIndices(f[1],"f(")
+ if(o2[0]<o1[0]) : o1,o2=o2,o1
+ color = "f(%s)*f(%s)" % (",".join(o1),",".join(o2))
+ label = 'f(1,3,-1)*f(2,4,-1)'
+ if(label==color) :
+ cidx=color_idx
+ colours[cidx] = (cs,cf[cidx])
+ elif (FFFF) :
+ colours[color_idx] = (cs[color_idx],cf[color_idx])
+ else :
+ cidx=color_idx
+ if(color_idx!=0) :
+ vertex.herwig_skip_vertex = True
+ self.vertex_skipped=True
+ msg = 'Warning: General spin structure code currently only '\
+ 'supports 1 colour structure for {tag} ( {ps} ) in {name}\n'.format(tag=lorentztag, name=vertex.name,
+ ps=' '.join(map(str,vertex.particles)))
+ sys.stderr.write(msg)
+ return (True,"","")
+ if(isinstance(cs,basestring)) :
+ colours[cidx] = (cs,cf[cidx])
+ else :
+ vertex.herwig_skip_vertex = True
+ self.vertex_skipped=True
+ msg = 'Warning: General spin structure code currently only '\
+ 'supports 1 colour structure for {tag} ( {ps} ) in {name}\n'.format(tag=lorentztag, name=vertex.name,
+ ps=' '.join(map(str,vertex.particles)))
+ sys.stderr.write(msg)
+ return (True,"","")
+ if(len(colours)==0) :
+ msg = 'Warning: General spin structure code currently only '\
+ 'supports 1 colour structure for {tag} ( {ps} ) in {name}\n'.format(tag=lorentztag, name=vertex.name,
+ ps=' '.join(map(str,vertex.particles)))
sys.stderr.write(msg)
vertex.herwig_skip_vertex = True
self.vertex_skipped=True
return (True,"","")
-
-
- ### do we need left/right?
- if 'FF' in lorentztag and lorentztag != "FFT":
- #leftcalc = aStoStrongCoup(py2cpp(leftcontent)[0], paramstoreplace_, paramstoreplace_expressions_)
- #rightcalc = aStoStrongCoup(py2cpp(rightcontent)[0], paramstoreplace_, paramstoreplace_expressions_)
- leftcalc, sym = py2cpp(leftcontent)
- symbols |= sym
- rightcalc, sym = py2cpp(rightcontent)
- symbols |= sym
- left = 'left(' + leftcalc + ');'
- right = 'right(' + rightcalc + ');'
- else:
- left = ''
- right = ''
- leftcalc = ''
- rightcalc = ''
- #normcalc = aStoStrongCoup(py2cpp(normcontent)[0], paramstoreplace_, paramstoreplace_expressions_)
- normcalc, sym = py2cpp(normcontent)
- symbols |= sym
- # UFO is GeV by default (?)
- if lorentztag in ['VVS','SSS']:
- normcalc = 'Complex((%s) * GeV / UnitRemoval::E)' % normcalc
- elif lorentztag in ['GeneralVVS']:
- normcalc = 'Complex(-(%s) * UnitRemoval::E / GeV )' % normcalc
- elif lorentztag in ['FFT','VVT', 'SST', 'FFVT', 'VVVT' , 'VVVS' ]:
- normcalc = 'Complex((%s) / GeV * UnitRemoval::E)' % normcalc
- norm = 'norm(' + normcalc + ');'
- # finally special handling for eps tensors
- if(len(vertex.color)==1 and vertex.color[0].find("Epsilon")>=0) :
- couplingptrs, append = epsilonSign(vertex,couplingptrs,append)
- # define unkown symbols from the model
- symboldefs = [ def_from_model(self.model,s) for s in symbols ]
- ### assemble dictionary and fill template
- subs = { 'lorentztag' : lorentztag, # ok
- 'classname' : classname, # ok
- 'symbolrefs' : '\n '.join(symboldefs),
- 'left' : left, # doesn't always exist in base
- 'right' : right, # doesn't always exist in base
- 'norm' : norm, # needs norm, too
-
- #################### need survey which different setter methods exist in base classes
-
- 'addToPlist' : '\n'.join([ 'addToList(%s);'%s for s in plistarray]),
- 'parameters' : '',
- 'setCouplings' : '',
- 'qedorder' : qed,
- 'qcdorder' : qcd,
- 'couplingptrs' : ''.join(couplingptrs),
- 'spindirectory' : spindirectory(lorentztag),
- 'ModelName' : self.modelname,
- 'prepend' : prepend,
- 'append' : append,
- 'header' : header
- } # ok
-
- # print info if required
- if self.verbose:
- print '-'*60
- pprint.pprint(( classname, plistarray, leftcalc, rightcalc, normcalc ))
-
- return (False,VERTEXCLASS.substitute(subs),VERTEXHEADER.format(**subs))
+ # loop over the different orders in the couplings
+ # and colour structures
+ iorder=0
+ self.vertex_names[vertex.name]=[classname]
+ for corder in couplingOrders :
+ for (cidx,(cstruct,cfactor)) in colours.iteritems() :
+ iorder +=1
+ cname=classname
+ if(iorder!=1) :
+ cname= "%s_%s" % (classname,iorder)
+ self.vertex_names[vertex.name].append(cname)
+ defns=[]
+ vertexEval=[]
+ values=[]
+ imax = len(vertex.particles)+1
+ if lorentztag in genericVertices :
+ imax=1
+ for (color_idx,lorentz_idx),coupling in vertex.couplings.iteritems() :
+ # only the colour structre and coupling order we want
+ if(color_idx != cidx) : continue
+ if(coupling_orders(vertex, coupling, self.couplingDefns)!=corder) : continue
+ # calculate the value of the coupling
+ values.append(couplingValue(coupling))
+ # now to convert the spin structures
+ for i in range(0,imax) :
+ if(len(defns)<i+1) :
+ defns.append({})
+ vertexEval.append([])
+ eps |= convertLorentz(vertex.lorentz[lorentz_idx],lorentztag,order,vertex,
+ i,defns[i],vertexEval[i])
+ # we can now generate the evaluate member functions
+ header=""
+ impls=""
+ spins=vertex.lorentz[0].spins
+ mult={}
+ for i in range(1,6) :
+ if( spins.count(i)>1 and i!=2) : mult[i] = []
+ for i in range(0,imax) :
+ (evalHeader,evalCC) = generateEvaluateFunction(self.model,vertex,i,values,defns[i],vertexEval[i],cfactor,order)
+ if(i!=0 and spins[i-1] in mult) :
+ if(len(mult[spins[i-1]])==0) : mult[spins[i-1]].append(evalHeader)
+ evalHeader=evalHeader.replace("evaluate(","evaluate%s(" % i)
+ evalCC =evalCC .replace("evaluate(","evaluate%s(" % i)
+ mult[spins[i-1]].append(evalHeader)
+ header+=" "+evalHeader+";\n"
+ impls+=evalCC
+ # combine the multiple defn if needed
+ for (key,val) in mult.iteritems() :
+ (evalHeader,evalCC) = multipleEvaluate(vertex,key,val)
+ if(evalHeader!="") : header += " "+evalHeader+";\n"
+ if(evalCC!="") : impls += evalCC
+ impls=impls.replace("evaluate", "FRModel%s::evaluate" % cname)
+ couplingOrder=""
+ for coupName,coupVal in corder.iteritems() :
+ couplingOrder+=" orderInCoupling(CouplingType::%s,%s);\n" %(coupName,coupVal)
+ ### assemble dictionary and fill template
+ subs = { 'lorentztag' : lorentztag,
+ 'classname' : cname,
+ 'addToPlist' : '\n'.join([ 'addToList(%s);'%s for s in plistarray]),
+ 'ModelName' : self.modelname,
+ 'couplingOrders' : couplingOrder,
+ 'colourStructure' : cstruct,
+ 'evaldefs' : header,
+ 'evalimpls' : impls}
+ newHeader = GENERALVERTEXHEADER.format(**subs)
+ if(eps) : newHeader +="#include \"ThePEG/Helicity/epsilon.h\"\n"
+ headers+=newHeader
+ classes+=GENERALVERTEXCLASS.substitute(subs)
+ return (False,classes,headers)
def get_vertices(self,libname):
vlist = ['library %s\n' % libname]
for v in self.all_vertices:
if v.herwig_skip_vertex: continue
- vlist.append( vertexline.format(modelname=self.modelname, vname=v.name) )
+ for name in self.vertex_names[v.name] :
+ vlist.append( vertexline.format(modelname=self.modelname, classname=name) )
if( not self.no_generic_loop_vertices) :
vlist.append('insert {modelname}:ExtraVertices 0 /Herwig/{modelname}/V_GenericHPP\n'.format(modelname=self.modelname) )
vlist.append('insert {modelname}:ExtraVertices 0 /Herwig/{modelname}/V_GenericHGG\n'.format(modelname=self.modelname) )
return ''.join(vlist)
- def extractCouplings(self,lorentztag,pos,lf,cf,vertex,order) :
- coup_left = []
- coup_right = []
- coup_norm = []
- header = ""
- qcd=0
- qed=0
- prepend=""
- append=""
- unique_qcd = CheckUnique()
- unique_qed = CheckUnique()
- maxColour=0
- for (color_idx,lorentz_idx),coupling in vertex.couplings.iteritems():
- maxColour=max(maxColour,color_idx)
- all_couplings=[]
- for ix in range(0,maxColour+1) :
- all_couplings.append([])
- for colour in range(0,maxColour+1) :
- for (color_idx,lorentz_idx),coupling in vertex.couplings.iteritems() :
- if(color_idx!=colour) : continue
- qcd, qed = qcd_qed_orders(vertex, coupling)
- try :
- unique_qcd( qcd )
- unique_qed( qed )
- except :
- msg = 'Different powers of QCD and QED couplings for the same vertex'\
- ' is not currently supported for {ps} in {name}.\n'.format(tag=lorentztag, name=vertex.name,
- ps=' '.join(map(str,vertex.particles)))
- sys.stderr.write(msg)
- raise SkipThisVertex()
- L = vertex.lorentz[lorentz_idx]
- prefactors = calculatePrefactor(self.globalsign,lorentztag,lf,cf[color_idx])
- # calculate the value of the coupling
- value = couplingValue(coupling)
- # handling of the different types of couplings
- if lorentztag in ['FFS','FFV']:
- all_couplings[color_idx] = fermionCouplings(value,prefactors,L,all_couplings[color_idx],order)
- elif 'T' in lorentztag :
- append, all_couplings[color_idx] = tensorCouplings(vertex,value,prefactors,L,lorentztag,pos,
- all_couplings[color_idx],order)
- elif 'R' in lorentztag :
- all_couplings[color_idx] = RSCouplings(value,prefactors,L,all_couplings[color_idx],order)
- elif lorentztag == 'VVS' or lorentztag == "VVSS" or lorentztag == "VSS" :
- all_couplings[color_idx] = scalarVectorCouplings(value,prefactors,L,lorentztag,
- all_couplings[color_idx],order)
- elif lorentztag == "SSS" or lorentztag == "SSSS" :
- prepend, header, all_couplings[color_idx] = scalarCouplings(vertex,value,prefactors,L,lorentztag,
- all_couplings[color_idx],prepend,header)
- elif "VVV" in lorentztag :
- all_couplings[color_idx],append = vectorCouplings(vertex,value,prefactors,L,lorentztag,pos,
- all_couplings[color_idx],append,qcd,order)
- else:
- raise SkipThisVertex()
-
- # return the result
- return (all_couplings,header,qcd,qed,prepend,append)
diff --git a/Models/General/GenericHGGVertex.cc b/Models/General/GenericHGGVertex.cc
--- a/Models/General/GenericHGGVertex.cc
+++ b/Models/General/GenericHGGVertex.cc
@@ -1,169 +1,170 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the GenericHGGVertex class.
//
#include "GenericHGGVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Looptools/clooptools.h"
using namespace Herwig;
GenericHGGVertex::GenericHGGVertex() : setup_(false), q2Last_(ZERO), coupLast_(0.), idLast_(0) {
orderInGs(2);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
IBPtr GenericHGGVertex::clone() const {
return new_ptr(*this);
}
IBPtr GenericHGGVertex::fullclone() const {
return new_ptr(*this);
}
void GenericHGGVertex::persistentOutput(PersistentOStream & os) const {
os << bosons_ << setup_ << vertices_ << model_;
}
void GenericHGGVertex::persistentInput(PersistentIStream & is, int) {
is >> bosons_ >> setup_ >> vertices_ >> model_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<GenericHGGVertex,VVSLoopVertex>
describeHerwigGenericHGGVertex("Herwig::GenericHGGVertex", "Herwig.so");
void GenericHGGVertex::Init() {
static ClassDocumentation<GenericHGGVertex> documentation
("The GenericHGGVertex class implements the coupling of"
" the Higgs bosons to gluons in a generic model.");
static RefVector<GenericHGGVertex,ParticleData> interfaceBosons
("Bosons",
"The Higgs bosons in the model.",
&GenericHGGVertex::bosons_, -1, false, false, true, false, false);
}
void GenericHGGVertex::doinit() {
for(unsigned int ix=0;ix<bosons_.size();++ix) {
addToList(21,21,bosons_[ix]->id());
}
VVSLoopVertex::doinit();
if(loopToolsInitialized()) Looptools::ltexi();
}
void GenericHGGVertex::setCoupling (Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
if(!setup_) initializeVertex();
assert(part1->id()==ParticleID::g && part2->id()==ParticleID::g);
// find the particles in the loop
map<cPDPtr,vector<Interaction> >::iterator it = vertices_.find(part3);
// check there are some
if(it==vertices_.end()) {
norm(0.);
return;
}
Looptools::clearcache();
// overall factor
if( q2 != q2Last_ || coupLast_ == 0. || part3->id() != idLast_ ) {
q2Last_ = q2;
idLast_ = part3->id();
coupLast_ = sqr(strongCoupling(q2));
// loop over the loop particles
masses.clear();
type.clear();
couplings.clear();
setNParticles(it->second.size());
for(unsigned int ix=0;ix<it->second.size();++ix) {
masses.push_back(model_->mass(q2,it->second[ix].particle));
if(it->second[ix].particle->iSpin()==PDT::Spin0) {
type.push_back(PDT::Spin0);
it->second[ix].scalar->setCoupling(q2,part3,it->second[ix].particle,it->second[ix].particle->CC());
couplings.push_back(make_pair(0.5*it->second[ix].scalar->norm(),0.5*it->second[ix].scalar->norm()));
}
else if(it->second[ix].particle->iSpin()==PDT::Spin1Half) {
type.push_back(PDT::Spin1Half);
assert(it->second[ix].fermion);
it->second[ix].fermion->setCoupling(q2,it->second[ix].particle,it->second[ix].particle->CC(),part3);
Complex coupling = it->second[ix].fermion->norm();
Complex lc = it->second[ix].fermion->left ();
Complex rc = it->second[ix].fermion->right();
couplings.push_back(make_pair(0.5*coupling*lc,0.5*coupling*rc));
}
else
assert(false);
}
VVSLoopVertex::setCoupling(q2, part1, part2, part3);
}
norm(coupLast_);
}
void GenericHGGVertex::initializeVertex() {
// get the model
model_ = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
if(!model_) throw InitException();
// loop over all the vertices
unsigned int nv(model_->numberOfVertices());
for(unsigned int ib=0;ib<bosons_.size();++ib) {
for(unsigned int iv = 0; iv < nv; ++iv) {
// 3-point vertex with boson as incoming
if( model_->vertex(iv)->getNpoint()>3) continue;
if( !model_->vertex(iv)->isIncoming(bosons_[ib])) continue;
for(unsigned int il = 0; il < 3; ++il) {
tPDVector decaylist = model_->vertex(iv)->search(il, bosons_[ib]);
tPDVector::size_type nd = decaylist.size();
for( tPDVector::size_type i = 0; i < nd; i += 3 ) {
tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]);
if( pb->id() == bosons_[ib]->id() ) swap(pa, pb);
if( pc->id() == bosons_[ib]->id() ) swap(pa, pc);
// check coloured and particle antiparticle
if( pb->CC() != pc || !pb->coloured() || !pc->coloured())
continue;
// only know how to deal with triplets
assert(pb->iColour()==PDT::Colour3 || pb->iColour()==PDT::Colour3bar);
// scalar loop
if(pb->iSpin()==PDT::Spin0) {
SSSVertexPtr vertex = dynamic_ptr_cast<SSSVertexPtr>(model_->vertex(iv));
if(!vertex) continue;
map<cPDPtr,vector<Interaction> >::iterator it = vertices_.find(bosons_[ib]);
if(it!=vertices_.end()) {
it->second.push_back(Interaction(pb->id()>0?pb:pc,vertex,FFSVertexPtr()));
}
else {
vertices_.insert(make_pair(bosons_[ib],vector<Interaction>(1,Interaction(pb->id()>0?pb:pc,vertex,FFSVertexPtr()))));
}
}
// fermion loop
else if(pb->iSpin()==PDT::Spin1Half) {
FFSVertexPtr vertex = dynamic_ptr_cast<FFSVertexPtr>(model_->vertex(iv));
if(!vertex) continue;
map<cPDPtr,vector<Interaction> >::iterator it = vertices_.find(bosons_[ib]);
if(it!=vertices_.end()) {
it->second.push_back(Interaction(pb->id()>0?pb:pc,SSSVertexPtr(),vertex));
}
else {
vertices_.insert(make_pair(bosons_[ib],vector<Interaction>(1,Interaction(pb->id()>0?pb:pc,SSSVertexPtr(),vertex))));
}
}
else
assert(false);
}
}
}
}
// set up now
setup_ = true;
}
diff --git a/Models/General/GenericHPPVertex.cc b/Models/General/GenericHPPVertex.cc
--- a/Models/General/GenericHPPVertex.cc
+++ b/Models/General/GenericHPPVertex.cc
@@ -1,205 +1,206 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the GenericHPPVertex class.
//
#include "GenericHPPVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Looptools/clooptools.h"
using namespace Herwig;
GenericHPPVertex::GenericHPPVertex() : setup_(false), q2Last_(ZERO), coupLast_(0.), idLast_(0) {
orderInGs(0);
orderInGem(3);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr GenericHPPVertex::clone() const {
return new_ptr(*this);
}
IBPtr GenericHPPVertex::fullclone() const {
return new_ptr(*this);
}
void GenericHPPVertex::persistentOutput(PersistentOStream & os) const {
os << bosons_ << setup_ << vertices_ << model_;
}
void GenericHPPVertex::persistentInput(PersistentIStream & is, int) {
is >> bosons_ >> setup_ >> vertices_ >> model_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<GenericHPPVertex,VVSLoopVertex>
describeHerwigGenericHPPVertex("Herwig::GenericHPPVertex", "Herwig.so");
void GenericHPPVertex::Init() {
static ClassDocumentation<GenericHPPVertex> documentation
("The GenericHPPVertex class implements the coupling of"
" the Higgs bosons to gluons in a generic model.");
static RefVector<GenericHPPVertex,ParticleData> interfaceBosons
("Bosons",
"The Higgs bosons in the model.",
&GenericHPPVertex::bosons_, -1, false, false, true, false, false);
}
void GenericHPPVertex::doinit() {
for(unsigned int ix=0;ix<bosons_.size();++ix) {
addToList(22,22,bosons_[ix]->id());
}
VVSLoopVertex::doinit();
if(loopToolsInitialized()) Looptools::ltexi();
}
void GenericHPPVertex::setCoupling (Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
if(!setup_) initializeVertex();
assert(part1->id()==ParticleID::gamma && part2->id()==ParticleID::gamma);
// find the particles in the loop
map<cPDPtr,vector<Interaction> >::iterator it = vertices_.find(part3);
// check there are some
if(it==vertices_.end()) {
norm(0.);
return;
}
Looptools::clearcache();
// overall factor
if( q2 != q2Last_ || coupLast_ == 0. || part3->id() != idLast_ ) {
q2Last_ = q2;
idLast_ = part3->id();
coupLast_ = sqr(electroMagneticCoupling(q2));
// loop over the loop particles
masses.clear();
type.clear();
couplings.clear();
setNParticles(it->second.size());
for(unsigned int ix=0;ix<it->second.size();++ix) {
masses.push_back(model_->mass(q2,it->second[ix].particle));
// charge and colour factor
double fact(1.);
fact *= sqr(double(it->second[ix].particle->iCharge())/3.);
if(it->second[ix].particle->iColour()==PDT::Colour3||
it->second[ix].particle->iColour()==PDT::Colour3bar)
fact *=3.;
else if(it->second[ix].particle->iColour()==PDT::Colour0)
fact *= 1.;
else {
assert(false);
}
// spin-0
if(it->second[ix].particle->iSpin()==PDT::Spin0) {
type.push_back(PDT::Spin0);
it->second[ix].scalar->setCoupling(q2,part3,it->second[ix].particle,it->second[ix].particle->CC());
couplings.push_back(make_pair(fact*it->second[ix].scalar->norm(),
fact*it->second[ix].scalar->norm()));
}
else if(it->second[ix].particle->iSpin()==PDT::Spin1Half) {
type.push_back(PDT::Spin1Half);
assert(it->second[ix].fermion);
it->second[ix].fermion->setCoupling(q2,it->second[ix].particle,it->second[ix].particle->CC(),part3);
Complex coupling = fact*it->second[ix].fermion->norm();
Complex lc = it->second[ix].fermion->left ();
Complex rc = it->second[ix].fermion->right();
couplings.push_back(make_pair(coupling*lc,coupling*rc));
}
else if(it->second[ix].particle->iSpin()==PDT::Spin1) {
type.push_back(PDT::Spin1);
assert(it->second[ix].vector);
it->second[ix].vector->setCoupling(q2,it->second[ix].particle,it->second[ix].particle->CC(),part3);
couplings.push_back(make_pair(fact*it->second[ix].vector->norm(),
fact*it->second[ix].vector->norm()));
}
else
assert(false);
}
VVSLoopVertex::setCoupling(q2, part1, part2, part3);
}
norm(coupLast_);
}
void GenericHPPVertex::initializeVertex() {
// get the model
model_ = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
if(!model_) throw InitException();
// loop over all the vertices
unsigned int nv(model_->numberOfVertices());
for(unsigned int ib=0;ib<bosons_.size();++ib) {
for(unsigned int iv = 0; iv < nv; ++iv) {
// 3-point vertex with boson as incoming
if( model_->vertex(iv)->getNpoint()>3) continue;
if( !model_->vertex(iv)->isIncoming(bosons_[ib])) continue;
for(unsigned int il = 0; il < 3; ++il) {
tPDVector decaylist = model_->vertex(iv)->search(il, bosons_[ib]);
tPDVector::size_type nd = decaylist.size();
for( tPDVector::size_type i = 0; i < nd; i += 3 ) {
tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]);
if( pb->id() == bosons_[ib]->id() ) swap(pa, pb);
if( pc->id() == bosons_[ib]->id() ) swap(pa, pc);
// check coloured and particle antiparticle
if( pb->CC() != pc || !pb->charged() || !pc->charged())
continue;
// // scalar loop
if(pb->iSpin()==PDT::Spin0) {
SSSVertexPtr vertex = dynamic_ptr_cast<SSSVertexPtr>(model_->vertex(iv));
if(!vertex) continue;
map<cPDPtr,vector<Interaction> >::iterator it = vertices_.find(bosons_[ib]);
if(it!=vertices_.end()) {
it->second.push_back(Interaction(pb->id()>0?pb:pc,vertex,FFSVertexPtr(),VVSVertexPtr()));
}
else {
vertices_.insert(make_pair(bosons_[ib],
vector<Interaction>(1,Interaction(pb->id()>0?pb:pc,vertex,
FFSVertexPtr(),VVSVertexPtr()))));
}
}
// fermion loop
else if(pb->iSpin()==PDT::Spin1Half) {
FFSVertexPtr vertex = dynamic_ptr_cast<FFSVertexPtr>(model_->vertex(iv));
if(!vertex) continue;
map<cPDPtr,vector<Interaction> >::iterator it = vertices_.find(bosons_[ib]);
if(it!=vertices_.end()) {
it->second.push_back(Interaction(pb->id()>0?pb:pc,SSSVertexPtr(),vertex,VVSVertexPtr()));
}
else {
vertices_.insert(make_pair(bosons_[ib],
vector<Interaction>(1,Interaction(pb->id()>0?pb:pc,SSSVertexPtr(),
vertex,VVSVertexPtr()))));
}
}
// vector loop
else if(pb->iSpin()==PDT::Spin1) {
VVSVertexPtr vertex = dynamic_ptr_cast<VVSVertexPtr>(model_->vertex(iv));
if(!vertex) continue;
map<cPDPtr,vector<Interaction> >::iterator it = vertices_.find(bosons_[ib]);
if(it!=vertices_.end()) {
it->second.push_back(Interaction(pb->id()>0?pb:pc,SSSVertexPtr(),FFSVertexPtr(),vertex));
}
else {
vertices_.insert(make_pair(bosons_[ib],
vector<Interaction>(1,Interaction(pb->id()>0?pb:pc,SSSVertexPtr(),
FFSVertexPtr(),vertex))));
}
}
else
assert(false);
}
}
}
}
// set up now
setup_ = true;
}
diff --git a/Models/General/HardProcessConstructor.cc b/Models/General/HardProcessConstructor.cc
--- a/Models/General/HardProcessConstructor.cc
+++ b/Models/General/HardProcessConstructor.cc
@@ -1,813 +1,957 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the HardProcessConstructor class.
//
#include "HardProcessConstructor.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
void HardProcessConstructor::persistentOutput(PersistentOStream & os) const {
os << debug_ << subProcess_ << model_;
}
void HardProcessConstructor::persistentInput(PersistentIStream & is, int) {
is >> debug_ >> subProcess_ >> model_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeAbstractClass<HardProcessConstructor,Interfaced>
describeHerwigHardProcessConstructor("Herwig::HardProcessConstructor", "Herwig.so");
void HardProcessConstructor::Init() {
static ClassDocumentation<HardProcessConstructor> documentation
("Base class for implementation of the automatic generation of hard processes");
static Switch<HardProcessConstructor,bool> interfaceDebugME
("DebugME",
"Print comparison with analytical ME",
&HardProcessConstructor::debug_, false, false, false);
static SwitchOption interfaceDebugMEYes
(interfaceDebugME,
"Yes",
"Print the debug information",
true);
static SwitchOption interfaceDebugMENo
(interfaceDebugME,
"No",
"Do not print the debug information",
false);
}
void HardProcessConstructor::doinit() {
Interfaced::doinit();
EGPtr eg = generator();
model_ = dynamic_ptr_cast<HwSMPtr>(eg->standardModel());
if(!model_)
throw InitException() << "HardProcessConstructor:: doinit() - "
<< "The model pointer is null!"
<< Exception::abortnow;
if(!eg->eventHandler()) {
throw
InitException() << "HardProcessConstructor:: doinit() - "
<< "The eventHandler pointer was null therefore "
<< "could not get SubProcessHandler pointer "
<< Exception::abortnow;
}
string subProcessName =
eg->preinitInterface(eg->eventHandler(), "SubProcessHandlers", "get","");
subProcess_ = eg->getObject<SubProcessHandler>(subProcessName);
if(!subProcess_) {
ostringstream s;
s << "HardProcessConstructor:: doinit() - "
<< "There was an error getting the SubProcessHandler "
<< "from the current event handler. ";
generator()->logWarning( Exception(s.str(), Exception::warning) );
}
}
GeneralHardME::ColourStructure HardProcessConstructor::
colourFlow(const tcPDVector & extpart) const {
PDT::Colour ina = extpart[0]->iColour();
PDT::Colour inb = extpart[1]->iColour();
PDT::Colour outa = extpart[2]->iColour();
PDT::Colour outb = extpart[3]->iColour();
// incoming colour neutral
if(ina == PDT::Colour0 && inb == PDT::Colour0) {
if( outa == PDT::Colour0 && outb == PDT::Colour0 ) {
return GeneralHardME::Colour11to11;
}
else if( outa == PDT::Colour3 && outb == PDT::Colour3bar ) {
return GeneralHardME::Colour11to33bar;
}
else if( outa == PDT::Colour8 && outb == PDT::Colour8 ) {
return GeneralHardME::Colour11to88;
}
else
assert(false);
}
// incoming 3 3
else if(ina == PDT::Colour3 && inb == PDT::Colour3 ) {
if( outa == PDT::Colour3 && outb == PDT::Colour3 ) {
return GeneralHardME::Colour33to33;
}
else if( outa == PDT::Colour6 && outb == PDT::Colour0 ) {
return GeneralHardME::Colour33to61;
}
else if( outa == PDT::Colour0 && outb == PDT::Colour6 ) {
return GeneralHardME::Colour33to16;
}
else if ( outa == PDT::Colour0 && outb == PDT::Colour3bar) {
return GeneralHardME::Colour33to13bar;
}
else if ( outb == PDT::Colour0 && outa == PDT::Colour3bar) {
return GeneralHardME::Colour33to3bar1;
}
else if ( outa == PDT::Colour8 && outb == PDT::Colour3bar) {
return GeneralHardME::Colour33to83bar;
}
else if ( outb == PDT::Colour8 && outa == PDT::Colour3bar) {
return GeneralHardME::Colour33to3bar8;
}
else
assert(false);
}
// incoming 3bar 3bar
else if(ina == PDT::Colour3bar && inb == PDT::Colour3bar ) {
if( outa == PDT::Colour3bar && outb == PDT::Colour3bar ) {
return GeneralHardME::Colour3bar3barto3bar3bar;
}
else if( outa == PDT::Colour6bar && outb == PDT::Colour0) {
return GeneralHardME::Colour3bar3barto6bar1;
}
else if ( outa == PDT::Colour0 && outb == PDT::Colour6bar ) {
return GeneralHardME::Colour3bar3barto16bar;
}
else if ( outa == PDT::Colour0 && outb == PDT::Colour3) {
return GeneralHardME::Colour3bar3barto13;
}
else if ( outb == PDT::Colour0 && outa == PDT::Colour3) {
return GeneralHardME::Colour3bar3barto31;
}
else if ( outa == PDT::Colour8 && outb == PDT::Colour3) {
return GeneralHardME::Colour3bar3barto83;
}
else if ( outb == PDT::Colour8 && outa == PDT::Colour3) {
return GeneralHardME::Colour3bar3barto38;
}
else
assert(false);
}
// incoming 3 3bar
else if(ina == PDT::Colour3 && inb == PDT::Colour3bar ) {
if( outa == PDT::Colour0 && outb == PDT::Colour0 ) {
return GeneralHardME::Colour33barto11;
}
else if( outa == PDT::Colour3 && outb == PDT::Colour3bar ) {
return GeneralHardME::Colour33barto33bar;
}
else if( outa == PDT::Colour8 && outb == PDT::Colour8 ) {
return GeneralHardME::Colour33barto88;
}
else if( outa == PDT::Colour8 && outb == PDT::Colour0 ) {
return GeneralHardME::Colour33barto81;
}
else if( outa == PDT::Colour0 && outb == PDT::Colour8 ) {
return GeneralHardME::Colour33barto18;
}
else if( outa == PDT::Colour6 && outb == PDT::Colour6bar) {
return GeneralHardME::Colour33barto66bar;
}
else if( outa == PDT::Colour6bar && outb == PDT::Colour6) {
return GeneralHardME::Colour33barto6bar6;
}
else
assert(false);
}
// incoming 88
else if(ina == PDT::Colour8 && inb == PDT::Colour8 ) {
if( outa == PDT::Colour0 && outb == PDT::Colour0 ) {
return GeneralHardME::Colour88to11;
}
else if( outa == PDT::Colour3 && outb == PDT::Colour3bar ) {
return GeneralHardME::Colour88to33bar;
}
else if( outa == PDT::Colour8 && outb == PDT::Colour8 ) {
return GeneralHardME::Colour88to88;
}
else if( outa == PDT::Colour8 && outb == PDT::Colour0 ) {
return GeneralHardME::Colour88to81;
}
else if( outa == PDT::Colour0 && outb == PDT::Colour8 ) {
return GeneralHardME::Colour88to18;
}
else if( outa == PDT::Colour6 && outb == PDT::Colour6bar ) {
return GeneralHardME::Colour88to66bar;
}
else
assert(false);
}
// incoming 38
else if(ina == PDT::Colour3 && inb == PDT::Colour8 ) {
if(outa == PDT::Colour3 && outb == PDT::Colour0) {
return GeneralHardME::Colour38to31;
}
else if(outa == PDT::Colour0 && outb == PDT::Colour3) {
return GeneralHardME::Colour38to13;
}
else if(outa == PDT::Colour3 && outb == PDT::Colour8) {
return GeneralHardME::Colour38to38;
}
else if(outa == PDT::Colour8 && outb == PDT::Colour3) {
return GeneralHardME::Colour38to83;
}
else if(outa == PDT::Colour3bar && outb == PDT::Colour6){
return GeneralHardME::Colour38to3bar6;
}
else if(outa == PDT::Colour6 && outb == PDT::Colour3bar) {
return GeneralHardME::Colour38to63bar;
}
else if(outa == PDT::Colour3bar && outb == PDT::Colour3bar) {
return GeneralHardME::Colour38to3bar3bar;
}
else
assert(false);
}
// incoming 3bar8
else if(ina == PDT::Colour3bar && inb == PDT::Colour8 ) {
if(outa == PDT::Colour3bar && outb == PDT::Colour0 ) {
return GeneralHardME::Colour3bar8to3bar1;
}
else if(outa == PDT::Colour0 && outb == PDT::Colour3bar) {
return GeneralHardME::Colour3bar8to13bar;
}
else if(outa == PDT::Colour3bar && outb == PDT::Colour8 ) {
return GeneralHardME::Colour3bar8to3bar8;
}
else if(outa == PDT::Colour8 && outb == PDT::Colour3bar) {
return GeneralHardME::Colour3bar8to83bar;
}
else if(outa == PDT::Colour3 && outb == PDT::Colour3) {
return GeneralHardME::Colour3bar8to33;
}
else
assert(false);
}
// unknown colour flow
else
assert(false);
return GeneralHardME::UNDEFINED;
}
void HardProcessConstructor::fixFSOrder(HPDiagram & diag) {
tcPDPtr psa = getParticleData(diag.incoming.first);
tcPDPtr psb = getParticleData(diag.incoming.second);
tcPDPtr psc = getParticleData(diag.outgoing.first);
tcPDPtr psd = getParticleData(diag.outgoing.second);
//fix a spin order
if( psc->iSpin() < psd->iSpin() ) {
swap(diag.outgoing.first, diag.outgoing.second);
if(diag.channelType == HPDiagram::tChannel) {
diag.ordered.second = !diag.ordered.second;
}
return;
}
if( psc->iSpin() == psd->iSpin() &&
psc->id() < 0 && psd->id() > 0 ) {
swap(diag.outgoing.first, diag.outgoing.second);
if(diag.channelType == HPDiagram::tChannel) {
diag.ordered.second = !diag.ordered.second;
}
return;
}
}
void HardProcessConstructor::assignToCF(HPDiagram & diag) {
if(diag.channelType == HPDiagram::tChannel) {
if(diag.ordered.second) tChannelCF(diag);
else uChannelCF(diag);
}
else if(diag.channelType == HPDiagram::sChannel) {
sChannelCF(diag);
}
else if (diag.channelType == HPDiagram::fourPoint) {
fourPointCF(diag);
}
else
assert(false);
}
void HardProcessConstructor::tChannelCF(HPDiagram & diag) {
tcPDPtr ia = getParticleData(diag.incoming.first );
tcPDPtr ib = getParticleData(diag.incoming.second);
tcPDPtr oa = getParticleData(diag.outgoing.first );
tcPDPtr ob = getParticleData(diag.outgoing.second);
PDT::Colour ina = ia->iColour();
PDT::Colour inb = ib->iColour();
PDT::Colour outa = oa->iColour();
PDT::Colour outb = ob->iColour();
vector<CFPair> cfv(1, make_pair(0, 1.));
if(diag.intermediate->iColour() == PDT::Colour0) {
if(ina==PDT::Colour0) {
cfv[0] = make_pair(0, 1);
}
else if(ina==PDT::Colour3 || ina==PDT::Colour3bar) {
if( inb == PDT::Colour0 ) {
cfv[0] = make_pair(0, 1);
}
else if(inb==PDT::Colour3 || outb==PDT::Colour3bar) {
cfv[0] = make_pair(2, 1);
}
else if(inb==PDT::Colour8) {
cfv[0] = make_pair(2, 1);
}
}
else if(ina==PDT::Colour8) {
if( inb == PDT::Colour0 ) {
cfv[0] = make_pair(0, 1);
}
else if(inb==PDT::Colour3 || outb==PDT::Colour3bar) {
cfv[0] = make_pair(2, 1);
}
else if(inb==PDT::Colour8) {
- cfv[0] = make_pair(7, 1);
+ cfv[0] = make_pair(7, -1);
}
}
}
else if(diag.intermediate->iColour() == PDT::Colour8) {
if(ina==PDT::Colour8&&outa==PDT::Colour8&&
inb==PDT::Colour8&&outb==PDT::Colour8) {
cfv[0]=make_pair(2, 2.);
cfv.push_back(make_pair(3, -2.));
cfv.push_back(make_pair(1, -2.));
cfv.push_back(make_pair(4, 2.));
}
else if(ina==PDT::Colour8&&outa==PDT::Colour0&&
inb==PDT::Colour8&&outb==PDT::Colour8&&
- oa->iSpin()==PDT::Spin0) {
+ (oa->iSpin()==PDT::Spin0||oa->iSpin()==PDT::Spin1Half||
+ oa->iSpin()==PDT::Spin3Half)) {
cfv[0] = make_pair(0,-1);
}
else if(ina==PDT::Colour8&&outa==PDT::Colour8&&
inb==PDT::Colour8&&outb==PDT::Colour0&&
- ob->iSpin()==PDT::Spin0) {
+ (ob->iSpin()==PDT::Spin0||ob->iSpin()==PDT::Spin1Half||
+ ob->iSpin()==PDT::Spin3Half)) {
cfv[0] = make_pair(0,-1);
}
}
else if(diag.intermediate->iColour() == PDT::Colour3 ||
diag.intermediate->iColour() == PDT::Colour3bar) {
if(outa == PDT::Colour0 || outb == PDT::Colour0) {
- if( outa != PDT::Colour6 && outb != PDT::Colour6 &&
- outa != PDT::Colour6bar && outb != PDT::Colour6bar) {
+ if( outa == PDT::Colour6 || outb == PDT::Colour6 ||
+ outa == PDT::Colour6bar || outb == PDT::Colour6bar) {
+ cfv[0] = make_pair(0,0.5);
+ cfv.push_back(make_pair(1,0.5));
+ }
+ else if ((ina==PDT::Colour3 && inb == PDT::Colour3 &&
+ (outa == PDT::Colour3bar || outb == PDT::Colour3bar))||
+ (ina==PDT::Colour3bar && inb == PDT::Colour3bar &&
+ (outa == PDT::Colour3 || outb == PDT::Colour3 ))) {
cfv[0] = make_pair(0,1.);
}
else {
- cfv[0] = make_pair(0,0.5);
- cfv.push_back(make_pair(1,0.5));
+ cfv[0] = make_pair(0,1.);
}
}
else if(outa==PDT::Colour6 && outb==PDT::Colour3bar) {
cfv[0] = make_pair(4,1.);
cfv.push_back(make_pair(5,1.));
}
else if(outa==PDT::Colour6 && outb==PDT::Colour6bar) {
cfv[0] = make_pair(4, 1.);
for(unsigned int ix=5;ix<8;++ix)
cfv.push_back(make_pair(ix,1.));
}
else if(outa==PDT::Colour6 || outa ==PDT::Colour6bar ||
outb==PDT::Colour6 || outb ==PDT::Colour6bar ) {
assert(false);
}
else if(ina==PDT::Colour3 && inb==PDT::Colour3 ) {
if((outa==PDT::Colour0 && outb==PDT::Colour3bar)||
(outb==PDT::Colour0 && outa==PDT::Colour3bar))
cfv[0] = make_pair(0,1.);
else if((outa==PDT::Colour8 && outb==PDT::Colour3bar)||
- (outb==PDT::Colour8 && outa==PDT::Colour3bar))
+ (outb==PDT::Colour8 && outa==PDT::Colour3bar)) {
cfv[0] = make_pair(1,1.);
+ }
}
else if(ina==PDT::Colour3bar && inb==PDT::Colour3bar ) {
if((outa==PDT::Colour0 && outb==PDT::Colour3)||
(outb==PDT::Colour0 && outa==PDT::Colour3))
cfv[0] = make_pair(0,1.);
else if((outa==PDT::Colour8 && outb==PDT::Colour3)||
- (outb==PDT::Colour8 && outa==PDT::Colour3))
- cfv[0] = make_pair(1,1.);
+ (outb==PDT::Colour8 && outa==PDT::Colour3)) {
+ double sign = diag.intermediate->iSpin()==PDT::Spin0 ? -1. : 1.;
+ cfv[0] = make_pair(1,sign);
+ }
}
else if((ina==PDT::Colour3 && inb==PDT::Colour8) ||
(ina==PDT::Colour3bar && inb==PDT::Colour8) ||
(inb==PDT::Colour3 && ina==PDT::Colour8) ||
(inb==PDT::Colour3bar && ina==PDT::Colour8) ) {
if((outa==PDT::Colour3 && outb==PDT::Colour3 ) ||
(outa==PDT::Colour3bar && outb==PDT::Colour3bar)) {
cfv[0] = make_pair(1,1.);
}
}
}
else if(diag.intermediate->iColour() == PDT::Colour6 ||
diag.intermediate->iColour() == PDT::Colour6bar) {
if(ina==PDT::Colour8 && inb==PDT::Colour8) {
cfv[0] = make_pair(0, 1.);
for(unsigned int ix=1;ix<4;++ix)
cfv.push_back(make_pair(ix,1.));
for(unsigned int ix=4;ix<8;++ix)
cfv.push_back(make_pair(ix,1.));
}
else if(outa==PDT::Colour3bar && outb==PDT::Colour6) {
cfv[0] = make_pair(0,1.);
for(unsigned int ix=1;ix<4;++ix)
cfv.push_back(make_pair(ix,1.));
}
else if(outa==PDT::Colour6 && outb==PDT::Colour3bar) {
cfv[0] = make_pair(4,1.);
cfv.push_back(make_pair(5,1.));
}
}
diag.colourFlow = cfv;
}
void HardProcessConstructor::uChannelCF(HPDiagram & diag) {
+ tcPDPtr ia = getParticleData(diag.incoming.first );
+ tcPDPtr ib = getParticleData(diag.incoming.second);
+ tcPDPtr oa = getParticleData(diag.outgoing.first );
+ tcPDPtr ob = getParticleData(diag.outgoing.second);
+ PDT::Colour ina = ia->iColour();
+ PDT::Colour inb = ib->iColour();
+ PDT::Colour outa = oa->iColour();
+ PDT::Colour outb = ob->iColour();
PDT::Colour offshell = diag.intermediate->iColour();
- PDT::Colour ina = getParticleData(diag.incoming.first )->iColour();
- PDT::Colour inb = getParticleData(diag.incoming.second)->iColour();
- PDT::Colour outa = getParticleData(diag.outgoing.first )->iColour();
- PDT::Colour outb = getParticleData(diag.outgoing.second)->iColour();
vector<CFPair> cfv(1, make_pair(1, 1.));
if(offshell == PDT::Colour8) {
if(outa == PDT::Colour0 &&
outb == PDT::Colour0) {
cfv[0].first = 0;
}
else if( outa != outb ) {
if(outa == PDT::Colour0 ||
outb == PDT::Colour0) {
cfv[0].first = 0;
}
else if(ina == PDT::Colour3 && inb == PDT::Colour8 &&
outb == PDT::Colour3 && outa == PDT::Colour8) {
tPDPtr off = diag.intermediate;
if(off->CC()) off=off->CC();
if(off->iSpin()!=PDT::Spin1Half ||
diag.vertices.second->allowed(off->id(),diag.outgoing.first,diag.incoming.second)) {
cfv[0].first = 0;
cfv.push_back(make_pair(1, -1.));
}
else {
cfv[0].first = 1;
cfv.push_back(make_pair(0, -1.));
}
}
else if(ina == PDT::Colour3bar && inb == PDT::Colour8 &&
outb == PDT::Colour3bar && outa == PDT::Colour8) {
tPDPtr off = diag.intermediate;
if(off->CC()) off=off->CC();
if(off->iSpin()!=PDT::Spin1Half ||
diag.vertices.second->allowed(diag.outgoing.first,off->id(),diag.incoming.second)) {
cfv[0].first = 0;
cfv.push_back(make_pair(1, -1.));
}
else {
cfv[0].first = 1;
cfv.push_back(make_pair(0, -1.));
}
}
else {
cfv[0].first = 0;
cfv.push_back(make_pair(1, -1.));
}
}
else if(outa==PDT::Colour8&&ina==PDT::Colour8) {
cfv[0]=make_pair(4, 2.);
cfv.push_back(make_pair(5, -2.));
cfv.push_back(make_pair(0, -2.));
cfv.push_back(make_pair(2, 2.));
}
}
else if(offshell == PDT::Colour3 || offshell == PDT::Colour3bar) {
if( outa == PDT::Colour0 || outb == PDT::Colour0 ) {
- if( outa != PDT::Colour6 && outb != PDT::Colour6 &&
- outa != PDT::Colour6bar && outb != PDT::Colour6bar) {
- cfv[0] = make_pair(0,1.);
+ if( outa == PDT::Colour6 || outb == PDT::Colour6 ||
+ outa == PDT::Colour6bar || outb == PDT::Colour6bar) {
+ cfv[0] = make_pair(0,0.5);
+ cfv.push_back(make_pair(1,0.5));
+ }
+ else if ((ina==PDT::Colour3 && inb == PDT::Colour3 &&
+ (outa == PDT::Colour3bar || outb == PDT::Colour3bar))||
+ (ina==PDT::Colour3bar && inb == PDT::Colour3bar &&
+ (outa == PDT::Colour3 || outb == PDT::Colour3 ))) {
+ double sign = diag.intermediate->iSpin()==PDT::Spin0 ? -1. : 1.;
+ cfv[0] = make_pair(0,sign);
}
else {
- cfv[0] = make_pair(0,0.5);
- cfv.push_back(make_pair(1,0.5));
+ cfv[0] = make_pair(0,1.);
}
}
else if(outa==PDT::Colour3bar && outb==PDT::Colour6) {
cfv[0] = make_pair(4,1.);
cfv.push_back(make_pair(5,1.));
}
else if(outa==PDT::Colour6 && outb==PDT::Colour3bar) {
cfv[0] = make_pair(0,1.);
for(int ix=0; ix<4;++ix)
cfv.push_back(make_pair(ix,1.));
}
else if(outa==PDT::Colour6bar && outb==PDT::Colour6) {
cfv[0] = make_pair(4,1.);
for(int ix=5; ix<8;++ix)
cfv.push_back(make_pair(ix,1.));
}
else if(ina==PDT::Colour0 && inb==PDT::Colour0) {
cfv[0] = make_pair(0,1.);
}
else if(ina==PDT::Colour3 && inb==PDT::Colour3 ) {
if((outa==PDT::Colour0 && outb==PDT::Colour3bar)||
(outb==PDT::Colour0 && outa==PDT::Colour3bar))
cfv[0] = make_pair(0,1.);
else if((outa==PDT::Colour8 && outb==PDT::Colour3bar)||
- (outb==PDT::Colour8 && outa==PDT::Colour3bar))
- cfv[0] = make_pair(2,1.);
+ (outb==PDT::Colour8 && outa==PDT::Colour3bar)) {
+ double sign = diag.intermediate->iSpin()==PDT::Spin0 ? -1. : 1.;
+ cfv[0] = make_pair(2,sign);
+ }
}
else if(ina==PDT::Colour3bar && inb==PDT::Colour3bar ) {
if((outa==PDT::Colour0 && outb==PDT::Colour3)||
(outb==PDT::Colour0 && outa==PDT::Colour3))
cfv[0] = make_pair(0,1.);
else if((outa==PDT::Colour8 && outb==PDT::Colour3)||
- (outb==PDT::Colour8 && outa==PDT::Colour3))
+ (outb==PDT::Colour8 && outa==PDT::Colour3)) {
cfv[0] = make_pair(2,1.);
+ }
}
else if(((ina==PDT::Colour3 && inb==PDT::Colour8) ||
(ina==PDT::Colour3bar && inb==PDT::Colour8) ||
(inb==PDT::Colour3 && ina==PDT::Colour8) ||
(inb==PDT::Colour3bar && ina==PDT::Colour8)) &&
((outa==PDT::Colour3 && outb==PDT::Colour3 ) ||
(outa==PDT::Colour3bar && outb==PDT::Colour3bar))) {
cfv[0] = make_pair(2, 1.);
}
else if(( ina==PDT::Colour3 && inb==PDT::Colour3bar &&
outa==PDT::Colour3 && outb==PDT::Colour3bar)) {
cfv[0] = make_pair(2, 1.);
cfv.push_back(make_pair(3,-1.));
}
}
else if( offshell == PDT::Colour0 ) {
if(ina==PDT::Colour0) {
cfv[0] = make_pair(0, 1);
}
else if(ina==PDT::Colour3 || ina==PDT::Colour3bar) {
if( inb == PDT::Colour0 ) {
cfv[0] = make_pair(0, 1);
}
- else if(inb==PDT::Colour3 || outb==PDT::Colour3bar) {
+ else if(inb==PDT::Colour3 || inb==PDT::Colour3bar) {
cfv[0] = make_pair(3, 1);
}
else if(inb==PDT::Colour8) {
cfv[0] = make_pair(2, 1);
}
}
else if(ina==PDT::Colour8) {
if( inb == PDT::Colour0 ) {
cfv[0] = make_pair(0, 1);
}
else if(inb==PDT::Colour3 || outb==PDT::Colour3bar) {
cfv[0] = make_pair(2, 1);
}
else if(inb==PDT::Colour8) {
- cfv[0] = make_pair(8, 1);
+ cfv[0] = make_pair(8, -1);
}
}
}
else if(diag.intermediate->iColour() == PDT::Colour6 ||
diag.intermediate->iColour() == PDT::Colour6bar) {
if(ina==PDT::Colour8 && inb==PDT::Colour8) {
cfv[0] = make_pair(0, 1.);
for(unsigned int ix=1;ix<4;++ix)
cfv.push_back(make_pair(ix,1.));
for(unsigned int ix=8;ix<12;++ix)
cfv.push_back(make_pair(ix,1.));
}
else if(outa==PDT::Colour3bar && outa==PDT::Colour6) {
cfv[0] = make_pair(4, 1.);
cfv.push_back(make_pair(5,1.));
}
else if(outa==PDT::Colour6 && outa==PDT::Colour3bar) {
cfv[0] = make_pair(0, 1.);
for(unsigned int ix=1;ix<4;++ix)
cfv.push_back(make_pair(ix,1.));
}
}
diag.colourFlow = cfv;
}
void HardProcessConstructor::sChannelCF(HPDiagram & diag) {
tcPDPtr pa = getParticleData(diag.incoming.first);
tcPDPtr pb = getParticleData(diag.incoming.second);
PDT::Colour ina = pa->iColour();
PDT::Colour inb = pb->iColour();
PDT::Colour offshell = diag.intermediate->iColour();
tcPDPtr pc = getParticleData(diag.outgoing.first);
tcPDPtr pd = getParticleData(diag.outgoing.second);
PDT::Colour outa = pc->iColour();
PDT::Colour outb = pd->iColour();
vector<CFPair> cfv(1);
if(offshell == PDT::Colour8) {
if(ina == PDT::Colour0 || inb == PDT::Colour0 ||
outa == PDT::Colour0 || outb == PDT::Colour0) {
cfv[0] = make_pair(0, 1);
}
else {
bool incol = ina == PDT::Colour8 && inb == PDT::Colour8;
bool outcol = outa == PDT::Colour8 && outb == PDT::Colour8;
bool intrip = ina == PDT::Colour3 && inb == PDT::Colour3bar;
bool outtrip = outa == PDT::Colour3 && outb == PDT::Colour3bar;
bool outsex = outa == PDT::Colour6 && outb == PDT::Colour6bar;
bool outsexb = outa == PDT::Colour6bar && outb == PDT::Colour6;
if(incol || outcol) {
// Require an additional minus sign for a scalar/fermion
// 33bar final state due to the way the vertex rules are defined.
int prefact(1);
if( ((pc->iSpin() == PDT::Spin1Half && pd->iSpin() == PDT::Spin1Half) ||
(pc->iSpin() == PDT::Spin0 && pd->iSpin() == PDT::Spin0 )) &&
(outa == PDT::Colour3 && outb == PDT::Colour3bar) )
prefact = -1;
if(incol && outcol) {
cfv[0] = make_pair(0, -2.);
cfv.push_back(make_pair(1, 2.));
cfv.push_back(make_pair(3, 2.));
cfv.push_back(make_pair(5, -2.));
}
else if(incol && outsex) {
cfv[0].first = 4;
cfv[0].second = prefact;
for(unsigned int ix=1;ix<4;++ix)
cfv.push_back(make_pair(4+ix, prefact));
for(unsigned int ix=0;ix<4;++ix)
cfv.push_back(make_pair(8+ix,-prefact));
}
else {
cfv[0].first = 0;
cfv[0].second = -prefact;
cfv.push_back(make_pair(1, prefact));
}
}
else if( ( intrip && !outtrip ) ||
( !intrip && outtrip ) ) {
if(!outsex)
cfv[0] = make_pair(0, 1);
else {
cfv[0] = make_pair(0, 1.);
for(unsigned int ix=0;ix<3;++ix)
cfv.push_back(make_pair(ix+1, 1.));
}
}
else if((intrip && outsex) || (intrip && outsexb)) {
cfv[0] = make_pair(0,1.);
for(int ix=1; ix<4; ++ix)
cfv.push_back(make_pair(ix,1.));
}
else
cfv[0] = make_pair(1, 1);
}
}
else if(offshell == PDT::Colour0) {
if( ina == PDT::Colour0 ) {
cfv[0] = make_pair(0, 1);
}
else if(ina==PDT::Colour3 || ina==PDT::Colour3bar) {
if( outa == PDT::Colour0 ) {
cfv[0] = make_pair(0, 1);
}
else if(outa==PDT::Colour3 || outa==PDT::Colour3bar) {
cfv[0] = make_pair(3, 1);
}
else if(outa==PDT::Colour8) {
cfv[0] = make_pair(2, 1);
}
else if(outa==PDT::Colour6 || outa==PDT::Colour6bar) {
cfv[0] = make_pair(8, 1.);
cfv.push_back(make_pair(9,1.));
}
else
assert(false);
}
else if(ina==PDT::Colour8) {
if( outa == PDT::Colour0 ) {
cfv[0] = make_pair(0, 1);
}
else if(outa==PDT::Colour3 || outb==PDT::Colour3bar) {
cfv[0] = make_pair(2, 1);
}
else if(outa==PDT::Colour8) {
cfv[0] = make_pair(6, 1);
}
}
}
else if(offshell == PDT::Colour3 || offshell == PDT::Colour3bar) {
if(outa == PDT::Colour6 || outa == PDT::Colour6bar ||
outb == PDT::Colour6bar || outb == PDT::Colour6) {
cfv[0] = make_pair(6, 1.);
cfv.push_back(make_pair(7,1.));
}
else if((ina == PDT::Colour3 && inb == PDT::Colour3) ||
(ina == PDT::Colour3bar && inb == PDT::Colour3bar)) {
if((outa == PDT::Colour3 && outb == PDT::Colour3 ) ||
(outa == PDT::Colour3bar && outb == PDT::Colour3bar)) {
cfv[0] = make_pair(2, 1.);
cfv.push_back(make_pair(3,-1.));
}
else
cfv[0] = make_pair(0,1.);
}
else if(((ina==PDT::Colour3 && inb==PDT::Colour8) ||
(ina==PDT::Colour3bar && inb==PDT::Colour8) ||
(inb==PDT::Colour3 && ina==PDT::Colour8) ||
(inb==PDT::Colour3bar && ina==PDT::Colour8) ) &&
((outa==PDT::Colour3 && outb==PDT::Colour3 ) ||
(outa==PDT::Colour3bar && outb==PDT::Colour3bar))) {
cfv[0] = make_pair(0,1.);
}
else {
if(outa == PDT::Colour0 || outb == PDT::Colour0)
cfv[0] = make_pair(0, 1);
else
cfv[0] = make_pair(1, 1);
}
}
else if( offshell == PDT::Colour6 || offshell == PDT::Colour6bar) {
if((ina == PDT::Colour3 && inb == PDT::Colour3 &&
outa == PDT::Colour3 && outb == PDT::Colour3 ) ||
(ina == PDT::Colour3bar && inb == PDT::Colour3bar &&
outa == PDT::Colour3bar && outb == PDT::Colour3bar)) {
cfv[0] = make_pair(2,0.5);
cfv.push_back(make_pair(3,0.5));
}
else if((ina == PDT::Colour3 && inb == PDT::Colour3 &&
((outa == PDT::Colour6 && outb == PDT::Colour0)||
(outb == PDT::Colour6 && outa == PDT::Colour0))) ||
(ina == PDT::Colour3bar && inb == PDT::Colour3bar &&
((outa == PDT::Colour6bar && outb == PDT::Colour0)||
(outb == PDT::Colour6bar && outa == PDT::Colour0)))) {
cfv[0] = make_pair(0,0.5);
cfv.push_back(make_pair(1,0.5));
}
else
assert(false);
}
else {
if(outa == PDT::Colour0 || outb == PDT::Colour0)
cfv[0] = make_pair(0, 1);
else
cfv[0] = make_pair(1, 1);
}
diag.colourFlow = cfv;
}
void HardProcessConstructor::fourPointCF(HPDiagram & diag) {
+ using namespace ThePEG::Helicity;
// count the colours
- unsigned int noct(0),ntri(0),nsng(0),nsex(0);
+ unsigned int noct(0),ntri(0),nsng(0),nsex(0),nf(0);
+ vector<tcPDPtr> particles;
for(unsigned int ix=0;ix<4;++ix) {
- PDT::Colour col = getParticleData(diag.ids[ix])->iColour();
+ particles.push_back(getParticleData(diag.ids[ix]));
+ PDT::Colour col = particles.back()->iColour();
if(col==PDT::Colour0) ++nsng;
else if(col==PDT::Colour3||col==PDT::Colour3bar) ++ntri;
else if(col==PDT::Colour8) ++noct;
else if(col==PDT::Colour6||col==PDT::Colour6bar) ++nsex;
+ if(particles.back()->iSpin()==2) nf+=1;
}
if(nsng==4 || (ntri==2&&nsng==2) ||
(noct==3 && nsng==1) ||
- (ntri==2 && noct==1 && nsng==1) ) {
+ (ntri==2 && noct==1 && nsng==1) ||
+ (noct == 2 && nsng == 2) ) {
vector<CFPair> cfv(1,make_pair(0,1));
diag.colourFlow = cfv;
}
else if(noct==4) {
// flows for SSVV, VVVV is handled in me class
vector<CFPair> cfv(6);
cfv[0] = make_pair(0, -2.);
cfv[1] = make_pair(1, -2.);
cfv[2] = make_pair(2, +4.);
cfv[3] = make_pair(3, -2.);
cfv[4] = make_pair(4, +4.);
cfv[5] = make_pair(5, -2.);
diag.colourFlow = cfv;
}
else if(ntri==2&&noct==2) {
vector<CFPair> cfv(2);
cfv[0] = make_pair(0, 1);
cfv[1] = make_pair(1, 1);
+ if(nf==2) cfv[1].second = -1.;
diag.colourFlow = cfv;
}
else if(nsex==2&&noct==2) {
vector<CFPair> cfv;
for(unsigned int ix=0;ix<4;++ix)
cfv.push_back(make_pair(ix ,2.));
for(unsigned int ix=0;ix<8;++ix)
cfv.push_back(make_pair(4+ix,1.));
diag.colourFlow = cfv;
}
- else
+ else if(ntri==4) {
+ // get the order from the vertex
+ vector<long> temp;
+ for(unsigned int ix=0;ix<4;++ix) {
+ temp = diag.vertices.first->search(ix,diag.outgoing.first);
+ if(!temp.empty()) break;
+ }
+ // compute the mapping
+ vector<long> ids;
+ ids.push_back( particles[0]->CC() ? -diag.incoming.first : diag.incoming.first );
+ ids.push_back( particles[1]->CC() ? -diag.incoming.second : diag.incoming.second);
+ ids.push_back( diag.outgoing.first );
+ ids.push_back( diag.outgoing.second);
+ vector<unsigned int> order = {0,1,2,3};
+ vector<bool> matched(4,false);
+ for(unsigned int ix=0;ix<temp.size();++ix) {
+ for(unsigned int iy=0;iy<ids.size();++iy) {
+ if(matched[iy]) continue;
+ if(temp[ix]==ids[iy]) {
+ matched[iy] = true;
+ order[ix]=iy;
+ break;
+ }
+ }
+ }
+ // 3 3 -> 3 3
+ if((particles[0]->iColour()==PDT::Colour3 &&
+ particles[1]->iColour()==PDT::Colour3) ||
+ (particles[0]->iColour()==PDT::Colour3bar &&
+ particles[1]->iColour()==PDT::Colour3bar) ) {
+ if(diag.vertices.first->colourStructure()==ColourStructure::SU3I12I34) {
+ if( (order[0]==0 && order[1]==2) || (order[2]==0 && order[3]==2) ||
+ (order[0]==2 && order[1]==0) || (order[2]==2 && order[3]==0))
+ diag.colourFlow = vector<CFPair>(1,make_pair(2,1.));
+ else
+ diag.colourFlow = vector<CFPair>(1,make_pair(3,1.));
+ }
+ else if(diag.vertices.first->colourStructure()==ColourStructure::SU3I14I23) {
+ if( (order[0]==0 && order[3]==2) || (order[1]==0 && order[2]==2) ||
+ (order[0]==2 && order[3]==0) || (order[1]==2 && order[2]==0))
+ diag.colourFlow = vector<CFPair>(1,make_pair(2,1.));
+ else
+ diag.colourFlow = vector<CFPair>(1,make_pair(3,1.));
+ }
+ else if(diag.vertices.first->colourStructure()==ColourStructure::SU3T21T43) {
+ if( (order[1]==0 && order[0]==2) || (order[3]==0 && order[2]==2) ||
+ (order[1]==2 && order[0]==0) || (order[3]==2 && order[2]==0))
+ diag.colourFlow = vector<CFPair>(1,make_pair(0,1.));
+ else
+ diag.colourFlow = vector<CFPair>(1,make_pair(1,1.));
+ }
+ else if(diag.vertices.first->colourStructure()==ColourStructure::SU3T23T41) {
+ if( (order[1]==0 && order[2]==2) || (order[3]==0 && order[0]==2) ||
+ (order[1]==2 && order[2]==0) || (order[3]==2 && order[0]==0))
+ diag.colourFlow = vector<CFPair>(1,make_pair(0,1.));
+ else
+ diag.colourFlow = vector<CFPair>(1,make_pair(1,1.));
+ }
+ else
+ assert(false);
+ }
+ else if((particles[0]->iColour()==PDT::Colour3 &&
+ particles[1]->iColour()==PDT::Colour3bar) |
+ (particles[0]->iColour()==PDT::Colour3bar &&
+ particles[1]->iColour()==PDT::Colour3)) {
+ if(diag.vertices.first->colourStructure()==ColourStructure::SU3I12I34) {
+ if( (order[0]==0 && order[1]==1) || (order[2]==0 && order[3]==0) ||
+ (order[0]==1 && order[1]==0) || (order[2]==1 && order[3]==1))
+ diag.colourFlow = vector<CFPair>(1,make_pair(3,1.));
+ else
+ diag.colourFlow = vector<CFPair>(1,make_pair(2,1.));
+ }
+ else if(diag.vertices.first->colourStructure()==ColourStructure::SU3I14I23) {
+ if( (order[0]==0 && order[3]==1) || (order[0]==2 && order[3]==3) ||
+ (order[0]==1 && order[3]==0) || (order[0]==3 && order[3]==2))
+ diag.colourFlow = vector<CFPair>(1,make_pair(3,1.));
+ else
+ diag.colourFlow = vector<CFPair>(1,make_pair(2,1.));
+ }
+ else if(diag.vertices.first->colourStructure()==ColourStructure::SU3T21T43) {
+ if( (order[1]==0 && order[0]==1) || (order[3]==0 && order[2]==1) ||
+ (order[1]==1 && order[0]==0) || (order[3]==1 && order[2]==0))
+ diag.colourFlow = vector<CFPair>(1,make_pair(1,1.));
+ else
+ diag.colourFlow = vector<CFPair>(1,make_pair(0,1.));
+ }
+ else if(diag.vertices.first->colourStructure()==ColourStructure::SU3T23T41) {
+ if( (order[1]==0 && order[2]==1) || (order[1]==1 && order[2]==0) ||
+ (order[1]==3 && order[2]==2) || (order[1]==2 && order[2]==3))
+ diag.colourFlow = vector<CFPair>(1,make_pair(1,1.));
+ else
+ diag.colourFlow = vector<CFPair>(1,make_pair(2,1.));
+ }
+ else
+ assert(false);
+ }
+ else {
+ assert(false);
+ }
+ }
+ else {
assert(false);
+ }
}
namespace {
// Helper functor for find_if in duplicate function.
class SameDiagramAs {
public:
SameDiagramAs(const HPDiagram & diag) : a(diag) {}
bool operator()(const HPDiagram & b) const {
return a == b;
}
private:
HPDiagram a;
};
}
bool HardProcessConstructor::duplicate(const HPDiagram & diag,
const HPDVector & group) const {
//find if a duplicate diagram exists
HPDVector::const_iterator it =
find_if(group.begin(), group.end(), SameDiagramAs(diag));
return it != group.end();
}
+
+bool HardProcessConstructor::checkOrder(const HPDiagram & diag) const {
+ for(map<string,pair<unsigned int,int> >::const_iterator it=model_->couplings().begin();
+ it!=model_->couplings().end();++it) {
+ int order=0;
+ if(diag.vertices.first ) order += diag.vertices.first ->orderInCoupling(it->second.first);
+ if(diag.vertices.second&&diag.vertices.first->getNpoint()==3)
+ order += diag.vertices.second->orderInCoupling(it->second.first);
+ if(order>it->second.second) return false;
+ }
+ return true;
+}
diff --git a/Models/General/HardProcessConstructor.h b/Models/General/HardProcessConstructor.h
--- a/Models/General/HardProcessConstructor.h
+++ b/Models/General/HardProcessConstructor.h
@@ -1,211 +1,216 @@
// -*- C++ -*-
#ifndef HERWIG_HardProcessConstructor_H
#define HERWIG_HardProcessConstructor_H
//
// This is the declaration of the HardProcessConstructor class.
//
#include "ThePEG/Interface/Interfaced.h"
#include "HPDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Handlers/SubProcessHandler.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/StandardEventHandler.h"
#include "Herwig/MatrixElement/General/GeneralHardME.h"
#include "HardProcessConstructor.fh"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the HardProcessConstructor class.
*
* @see \ref HardProcessConstructorInterfaces "The interfaces"
* defined for HardProcessConstructor.
*/
class HardProcessConstructor: public Interfaced {
public:
/** Vector of HPDiagrams. */
typedef vector<HPDiagram> HPDVector;
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
HardProcessConstructor() : debug_(false) {}
//@}
/**
* The main function to create diagrams etc for the processes
*/
virtual void constructDiagrams() = 0;
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** Functions to set up colour flows and matrix elements. */
//@{
/**
* Determine whether the ordering of the outgoing states is the same
* as the ordering in the matrix elements
* @param diag The diagram to question
*/
void fixFSOrder(HPDiagram & diag);
/**
* Assign a diagram to the appropriate colour flow(s).
* @param diag The diagram to assign
*/
void assignToCF(HPDiagram & diag);
/**
* Assign a $s$-channel diagram to the appropriate colour flow(s).
* @param diag The diagram to assign
*/
void sChannelCF(HPDiagram & diag);
/**
* Assign a $t$-channel diagram to the appropriate colour flow(s).
* @param diag The diagram to assign
*/
void tChannelCF(HPDiagram & diag);
/**
* Assign a $u$-channel diagram to the appropriate colour flow(s).
* @param diag The diagram to assign
*/
void uChannelCF(HPDiagram & diag);
/**
* Assign a $u$-channel diagram to the appropriate colour flow(s).
* @param diag The diagram to assign
*/
void fourPointCF(HPDiagram & diag);
//@}
/**
* Pointer to the model being used
*/
tHwSMPtr model() const {return model_;}
/**
* Pointer to the sub process handler
*/
tSubHdlPtr subProcess() const {return subProcess_;}
/**
* Whether to print the debug information with the matrix
* element. This is here solely so it can be passed to
* a matrix element that is created here.
*/
bool debug() const {return debug_;}
/**
* Get the correct colour factor matrix.
* @param extpart Vector of external ParticleData pointers
*/
GeneralHardME::ColourStructure colourFlow(const tcPDVector & extpart) const;
/**
* Search for a diagram that has already been created
* @param diagram The diagram to search for
* @param group The group of diagrams to search through
*/
bool duplicate(const HPDiagram & diagram,
const HPDVector & group) const;
+ /**
+ * check the order of a diagram
+ */
+ bool checkOrder(const HPDiagram & diag) 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.
*/
HardProcessConstructor & operator=(const HardProcessConstructor &);
private:
/**
* Pointer to the model being used
*/
tHwSMPtr model_;
/**
* Pointer to the sub process handler
*/
tSubHdlPtr subProcess_;
/**
* Whether to print the debug information with the matrix
* element. This is here solely so it can be passed to
* a matrix element that is created here.
*/
bool debug_;
};
namespace HPC_helper {
// Helper functor for find_if in duplicate function.
class SameIncomingAs {
public:
SameIncomingAs(tPDPair in) : a(in.first->id()), b(in.second->id()) {}
bool operator()(tPDPair ppair) const {
long id1(ppair.first->id()), id2(ppair.second->id());
return ( id1 == a && id2 == b ) || ( id1 == b && id2 == a );
}
private:
long a, b;
};
inline bool duplicateIncoming(tPDPair ppair,const vector<tPDPair> &incPairs) {
vector<tPDPair>::const_iterator it =
find_if( incPairs.begin(), incPairs.end(), SameIncomingAs(ppair) );
return it != incPairs.end();
}
}
}
#endif /* HERWIG_HardProcessConstructor_H */
diff --git a/Models/General/ModelGenerator.cc b/Models/General/ModelGenerator.cc
--- a/Models/General/ModelGenerator.cc
+++ b/Models/General/ModelGenerator.cc
@@ -1,556 +1,555 @@
// -*- C++ -*-
//
// ModelGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ModelGenerator class.
//
#include "ModelGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "BSMWidthGenerator.h"
#include "Herwig/PDT/GenericMassGenerator.h"
#include "Herwig/Decay/DecayIntegrator.h"
#include "ThePEG/Repository/BaseRepository.h"
using namespace Herwig;
IBPtr ModelGenerator::clone() const {
return new_ptr(*this);
}
IBPtr ModelGenerator::fullclone() const {
return new_ptr(*this);
}
void ModelGenerator::persistentOutput(PersistentOStream & os) const {
os << hardProcessConstructors_ << _theDecayConstructor << particles_
<< offshell_ << Offsel_ << BRnorm_ << twoBodyOnly_ << howOffShell_
<< Npoints_ << Iorder_ << BWshape_ << brMin_ << decayOutput_;
}
void ModelGenerator::persistentInput(PersistentIStream & is, int) {
is >> hardProcessConstructors_ >> _theDecayConstructor >> particles_
>> offshell_ >> Offsel_ >> BRnorm_ >> twoBodyOnly_ >> howOffShell_
>> Npoints_ >> Iorder_ >> BWshape_ >> brMin_ >> decayOutput_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<ModelGenerator,Interfaced>
describeThePEGModelGenerator("Herwig::ModelGenerator", "Herwig.so");
void ModelGenerator::Init() {
static ClassDocumentation<ModelGenerator> documentation
("This class controls the the use of BSM physics.",
"BSM physics was produced using the algorithm of "
"\\cite{Gigg:2007cr,Gigg:2008yc}",
"\\bibitem{Gigg:2007cr} M.~Gigg and P.~Richardson, \n"
"Eur.\\ Phys.\\ J.\\ C {\\bf 51} (2007) 989.\n"
"%%CITATION = EPHJA,C51,989;%%\n"
" %\\cite{Gigg:2008yc}\n"
"\\bibitem{Gigg:2008yc}\n"
" M.~A.~Gigg and P.~Richardson,\n"
" %``Simulation of Finite Width Effects in Physics Beyond the Standard Model,''\n"
" arXiv:0805.3037 [hep-ph].\n"
" %%CITATION = ARXIV:0805.3037;%%\n"
);
static RefVector<ModelGenerator,HardProcessConstructor>
interfaceHardProcessConstructors
("HardProcessConstructors",
"The objects to construct hard processes",
&ModelGenerator::hardProcessConstructors_, -1,
false, false, true, false, false);
static Reference<ModelGenerator,Herwig::DecayConstructor>
interfaceDecayConstructor
("DecayConstructor",
"Pointer to DecayConstructor helper class",
&ModelGenerator::_theDecayConstructor, false, false, true, false);
static RefVector<ModelGenerator,ThePEG::ParticleData> interfaceModelParticles
("DecayParticles",
"ParticleData pointers to the particles requiring spin correlation "
"decayers. If decay modes do not exist they will also be created.",
&ModelGenerator::particles_, -1, false, false, true, false);
static RefVector<ModelGenerator,ParticleData> interfaceOffshell
("Offshell",
"The particles to treat as off-shell",
&ModelGenerator::offshell_, -1, false, false, true, false);
static Switch<ModelGenerator,int> interfaceWhichOffshell
("WhichOffshell",
"A switch to determine which particles to create mass and width "
"generators for.",
&ModelGenerator::Offsel_, 0, false, false);
static SwitchOption interfaceWhichOffshellSelected
(interfaceWhichOffshell,
"Selected",
"Only create mass and width generators for the particles specified",
0);
static SwitchOption interfaceWhichOffshellAll
(interfaceWhichOffshell,
"All",
"Treat all particles specified in the DecayParticles "
"list as off-shell",
1);
static Switch<ModelGenerator,bool> interfaceBRNormalize
("BRNormalize",
"Whether to normalize the partial widths to BR*total width for an "
"on-shell particle",
&ModelGenerator::BRnorm_, true, false, false);
static SwitchOption interfaceBRNormalizeNormalize
(interfaceBRNormalize,
"Yes",
"Normalize the partial widths",
true);
static SwitchOption interfaceBRNormalizeNoNormalize
(interfaceBRNormalize,
"No",
"Do not normalize the partial widths",
false);
static Parameter<ModelGenerator,int> interfacePoints
("InterpolationPoints",
"Number of points to use for interpolation tables when needed",
&ModelGenerator::Npoints_, 10, 5, 1000,
false, false, true);
static Parameter<ModelGenerator,unsigned int>
interfaceInterpolationOrder
("InterpolationOrder", "The interpolation order for the tables",
&ModelGenerator::Iorder_, 1, 1, 5,
false, false, Interface::limited);
static Switch<ModelGenerator,int> interfaceBreitWignerShape
("BreitWignerShape",
"Controls the shape of the mass distribution generated",
&ModelGenerator::BWshape_, 0, false, false);
static SwitchOption interfaceBreitWignerShapeDefault
(interfaceBreitWignerShape,
"Default",
"Running width with q in numerator and denominator width factor",
0);
static SwitchOption interfaceBreitWignerShapeFixedWidth
(interfaceBreitWignerShape,
"FixedWidth",
"Use a fixed width",
1);
static SwitchOption interfaceBreitWignerShapeNoq
(interfaceBreitWignerShape,
"Noq",
"Use M rather than q in the numerator and denominator width factor",
2);
static SwitchOption interfaceBreitWignerShapeNoNumerator
(interfaceBreitWignerShape,
"NoNumerator",
"Neglect the numerator factors",
3);
static Switch<ModelGenerator,bool> interfaceTwoBodyOnly
("TwoBodyOnly",
"Whether to use only two-body or all modes in the running width calculation",
&ModelGenerator::twoBodyOnly_, false, false, false);
static SwitchOption interfaceTwoBodyOnlyYes
(interfaceTwoBodyOnly,
"Yes",
"Only use two-body modes",
true);
static SwitchOption interfaceTwoBodyOnlyNo
(interfaceTwoBodyOnly,
"No",
"Use all modes",
false);
static Parameter<ModelGenerator,double> interfaceMinimumBR
("MinimumBR",
"The minimum branching fraction to include",
&ModelGenerator::brMin_, 1e-6, 0.0, 1.0,
false, false, Interface::limited);
static Switch<ModelGenerator,unsigned int> interfaceDecayOutput
("DecayOutput",
"Option to control the output of the decay mode information",
&ModelGenerator::decayOutput_, 1, false, false);
static SwitchOption interfaceDecayOutputNone
(interfaceDecayOutput,
"None",
"No output",
0);
static SwitchOption interfaceDecayOutputPlain
(interfaceDecayOutput,
"Plain",
"Default plain text output",
1);
static SwitchOption interfaceDecayOutputSLHA
(interfaceDecayOutput,
"SLHA",
"Output in the Susy Les Houches Accord format",
2);
static Parameter<ModelGenerator,double> interfaceMinimumWidthFraction
("MinimumWidthFraction",
"Minimum fraction of the particle's mass the width can be"
" for the off-shell treatment.",
&ModelGenerator::minWidth_, 1e-6, 1e-15, 1.,
false, false, Interface::limited);
static Parameter<ModelGenerator,double> interfaceHowMuchOffShell
("HowMuchOffShell",
"The multiple of the particle's width by which it is allowed to be off-shell",
&ModelGenerator::howOffShell_, 5., 0.0, 100.,
false, false, Interface::limited);
}
namespace {
/// Helper function for sorting by mass
inline bool massIsLess(tcPDPtr a, tcPDPtr b) {
return a->mass() < b->mass();
}
// Helper function to find minimum possible mass of a particle
inline Energy minimumMass(tcPDPtr parent) {
Energy output(Constants::MaxEnergy);
for(set<tDMPtr>::const_iterator dit = parent->decayModes().begin();
dit != parent->decayModes().end(); ++dit) {
Energy outMass(ZERO);
for(unsigned int ix=0;ix<(**dit).orderedProducts().size();++ix) {
outMass += (**dit).orderedProducts()[ix]->massMin();
}
output = min(output,outMass);
}
return output;
}
}
void ModelGenerator::doinit() {
useMe();
Interfaced::doinit();
// make sure the model is initialized
Ptr<Herwig::StandardModel>::pointer model
= dynamic_ptr_cast<Ptr<Herwig::StandardModel>::pointer>(generator()->standardModel());
model->init();
// and the vertices
for(size_t iv = 0; iv < model->numberOfVertices(); ++iv)
model->vertex(iv)->init();
// uniq and sort DecayParticles list by mass
set<PDPtr> tmp(particles_.begin(),particles_.end());
particles_.assign(tmp.begin(),tmp.end());
sort(particles_.begin(),particles_.end(),massIsLess);
//create decayers and decaymodes (if necessary)
if( _theDecayConstructor ) {
_theDecayConstructor->init();
_theDecayConstructor->createDecayers(particles_,brMin_);
}
// write out decays with spin correlations
ostream & os = CurrentGenerator::current().misc();
ofstream ofs;
if ( decayOutput_ > 1 ) {
string filename
= CurrentGenerator::current().filename() + "-BR.spc";
ofs.open(filename.c_str());
}
-
if(decayOutput_!=0) {
if(decayOutput_==1) {
os << "# The decay modes listed below will have spin\n"
<< "# correlations included when they are generated.\n#\n#";
}
else {
ofs << "# Herwig decay tables in SUSY Les Houches accord format\n";
ofs << "Block DCINFO # Program information\n";
ofs << "1 Herwig # Decay Calculator\n";
ofs << "2 " << generator()->strategy()->versionstring()
<< " # Version number\n";
}
}
//create mass and width generators for the requested particles
set<PDPtr> offShell;
if( Offsel_ == 0 ) offShell = set<PDPtr>(offshell_.begin() ,offshell_.end() );
else offShell = set<PDPtr>(particles_.begin(),particles_.end());
for(PDVector::iterator pit = particles_.begin();
pit != particles_.end(); ++pit) {
tPDPtr parent = *pit;
// Check decays for ones where quarks cannot be put on constituent
// mass-shell
checkDecays(parent);
parent->reset();
// Now switch off the modes if needed
for(DecaySet::const_iterator it=parent->decayModes().begin();
it!=parent->decayModes().end();++it) {
if( _theDecayConstructor->disableDecayMode((**it).tag()) ) {
DMPtr mode = *it;
generator()->preinitInterface(mode, "Active", "set", "No");
if(mode->CC()) {
DMPtr CCmode = mode->CC();
generator()->preinitInterface(CCmode, "Active", "set", "No");
}
}
}
parent->update();
if( parent->CC() ) parent->CC()->synchronize();
if( parent->decaySelector().empty() ) {
parent->stable(true);
parent->width(ZERO);
parent->widthCut(ZERO);
parent->massGenerator(tGenericMassGeneratorPtr());
parent->widthGenerator(tGenericWidthGeneratorPtr());
}
else {
if(parent->mass()*minWidth_>parent->width()) {
parent->massGenerator(tGenericMassGeneratorPtr());
parent->widthGenerator(tGenericWidthGeneratorPtr());
}
else {
if( offShell.find(*pit) != offShell.end() ) {
createWidthGenerator(*pit);
}
else {
parent->massGenerator(tGenericMassGeneratorPtr());
parent->widthGenerator(tGenericWidthGeneratorPtr());
}
}
}
if( parent->massGenerator() ) {
Energy minMass = minimumMass(parent);
Energy offShellNess = howOffShell_*parent->width();
if(minMass>parent->mass()-offShellNess) {
offShellNess = parent->mass()-minMass;
}
parent->widthCut(offShellNess);
parent->massGenerator()->reset();
if(decayOutput_==1)
os << "# " <<parent->PDGName() << " will be considered off-shell.\n#\n";
}
if( parent->widthGenerator() ) parent->widthGenerator()->reset();
}
// loop again to initialise mass and width generators
// switch off modes and write output
for(PDVector::iterator pit = particles_.begin();
pit != particles_.end(); ++pit) {
tPDPtr parent = *pit;
if(parent->widthGenerator())
parent->widthGenerator()->init();
if(parent->massGenerator())
parent->massGenerator()->init();
// output the modes if needed
if( !parent->decaySelector().empty() ) {
if ( decayOutput_ == 2 )
writeDecayModes(ofs, parent);
else
writeDecayModes(os, parent);
}
}
//Now construct hard processes given that we know which
//objects have running widths
for(unsigned int ix=0;ix<hardProcessConstructors_.size();++ix) {
hardProcessConstructors_[ix]->init();
hardProcessConstructors_[ix]->constructDiagrams();
}
}
void ModelGenerator::checkDecays(PDPtr parent) {
if( parent->stable() ) {
if(parent->coloured())
cerr << "Warning: No decays for coloured particle " << parent->PDGName() << "\n\n"
<< "have been calcluated in BSM model.\n"
<< "This may cause problems in the hadronization phase.\n"
<< "You may have forgotten to switch on the decay mode calculation using\n"
<< " set TwoBodyDC:CreateDecayModes Yes\n"
<< " set ThreeBodyDC:CreateDecayModes Yes\n"
<< " set WeakDecayConstructor:CreateDecayModes Yes\n"
<< "or the decays of this particle are missing from your\n"
<< "input spectrum and decay file in the SLHA format.\n\n";
return;
}
DecaySet::iterator dit = parent->decayModes().begin();
DecaySet::iterator dend = parent->decayModes().end();
Energy oldwidth(parent->width()), newwidth(ZERO);
bool rescalebrat(false);
double brsum(0.);
for(; dit != dend; ++dit ) {
if( !(**dit).on() ) continue;
Energy release((**dit).parent()->mass());
tPDVector::const_iterator pit = (**dit).orderedProducts().begin();
tPDVector::const_iterator pend =(**dit).orderedProducts().end();
for( ; pit != pend; ++pit ) {
release -= (**pit).constituentMass();
}
if( (**dit).brat() < brMin_ || release < ZERO ) {
if( release < ZERO )
cerr << "Warning: The shower cannot be generated using this decay "
<< (**dit).tag() << " because it is too close to threshold.\nIt "
<< "will be switched off and the branching fractions of the "
<< "remaining modes rescaled.\n";
rescalebrat = true;
generator()->preinitInterface(*dit, "Active", "set", "No");
generator()->preinitInterface(*dit, "BranchingRatio",
"set", "0.0");
DecayIntegratorPtr decayer = dynamic_ptr_cast<DecayIntegratorPtr>((**dit).decayer());
if(decayer) {
generator()->preinitInterface(decayer->fullName(), "Initialize", "set","0");
}
}
else {
brsum += (**dit).brat();
newwidth += (**dit).brat()*oldwidth;
}
}
// if no modes left set stable
if(newwidth==ZERO) {
parent->stable(true);
parent->width(ZERO);
parent->widthCut(ZERO);
parent->massGenerator(tGenericMassGeneratorPtr());
parent->widthGenerator(tGenericWidthGeneratorPtr());
}
// otherwise rescale if needed
else if( ( rescalebrat || abs(brsum - 1.) > 1e-12 ) && !parent->decayModes().empty()) {
dit = parent->decayModes().begin();
dend = parent->decayModes().end();
double factor = oldwidth/newwidth;
brsum = 0.;
for( ; dit != dend; ++dit ) {
if( !(**dit).on() ) continue;
double newbrat = ((**dit).brat())*factor;
brsum += newbrat;
ostringstream brf;
brf << setprecision(13) << newbrat;
generator()->preinitInterface(*dit, "BranchingRatio",
"set", brf.str());
}
parent->width(newwidth);
if( newwidth > ZERO ) parent->cTau(hbarc/newwidth);
}
}
namespace {
struct DecayModeOrdering {
bool operator()(tcDMPtr m1, tcDMPtr m2) {
if(m1->brat()!=m2->brat()) {
return m1->brat()>m2->brat();
}
else {
if(m1->products().size()==m2->products().size()) {
ParticleMSet::const_iterator it1=m1->products().begin();
ParticleMSet::const_iterator it2=m2->products().begin();
do {
if((**it1).id()!=(**it2).id()) {
return (**it1).id()>(**it2).id();
}
++it1;
++it2;
}
while(it1!=m1->products().end()&&
it2!=m2->products().end());
assert(false);
}
else
return m1->products().size()<m2->products().size();
}
return false;
}
};
}
void ModelGenerator::writeDecayModes(ostream & os, tcPDPtr parent) const {
if(decayOutput_==0) return;
set<tcDMPtr,DecayModeOrdering> modes(parent->decayModes().begin(),
parent->decayModes().end());
if(decayOutput_==1) {
os << " Parent: " << parent->PDGName() << " Mass (GeV): "
<< parent->mass()/GeV << " Total Width (GeV): "
<< parent->width()/GeV << endl;
os << std::left << std::setw(40) << '#'
<< std::left << std::setw(20) << "Partial Width/GeV"
<< std::left << std::setw(20) << "BR" << "Yes/No\n";
for(set<tcDMPtr,DecayModeOrdering>::iterator dit=modes.begin();
dit!=modes.end();++dit)
os << std::left << std::setw(40) << (**dit).tag()
<< std::left << std::setw(20) << (**dit).brat()*parent->width()/GeV
<< std::left << std::setw(20) << (**dit).brat()
<< ((**dit).on() ? "Yes" : "No" ) << '\n';
os << "#\n#";
}
else if(decayOutput_==2) {
os << "# \t PDG \t Width\n";
os << "DECAY\t" << parent->id() << "\t" << parent->width()/GeV << "\t # " << parent->PDGName() << "\n";
for(set<tcDMPtr,DecayModeOrdering>::iterator dit=modes.begin();
dit!=modes.end();++dit) {
os << "\t" << std::left << std::setw(10)
<< (**dit).brat() << "\t" << (**dit).orderedProducts().size()
<< "\t";
for(unsigned int ix=0;ix<(**dit).orderedProducts().size();++ix)
os << std::right << std::setw(10)
<< (**dit).orderedProducts()[ix]->id() ;
for(unsigned int ix=(**dit).orderedProducts().size();ix<4;++ix)
os << "\t";
os << "# " << (**dit).tag() << "\n";
}
}
}
void ModelGenerator::createWidthGenerator(tPDPtr p) {
string wn = p->fullName() + string("-WGen");
string mn = p->fullName() + string("-MGen");
GenericMassGeneratorPtr mgen = dynamic_ptr_cast<GenericMassGeneratorPtr>
(generator()->preinitCreate("Herwig::GenericMassGenerator", mn));
BSMWidthGeneratorPtr wgen = dynamic_ptr_cast<BSMWidthGeneratorPtr>
(generator()->preinitCreate("Herwig::BSMWidthGenerator", wn));
//set the particle interface
mgen->particle(p);
wgen->particle(p);
//set the generator interfaces in the ParticleData object
generator()->preinitInterface(p, "Mass_generator","set", mn);
generator()->preinitInterface(p, "Width_generator","set", wn);
//allow the branching fraction of this particle type to vary
p->variableRatio(true);
if( p->CC() ) p->CC()->variableRatio(true);
//initialize the generators
generator()->preinitInterface(mgen, "Initialize", "set", "Yes");
generator()->preinitInterface(wgen, "Initialize", "set", "Yes");
string norm = BRnorm_ ? "Yes" : "No";
generator()->preinitInterface(wgen, "BRNormalize", "set", norm);
string twob = twoBodyOnly_ ? "Yes" : "No";
generator()->preinitInterface(wgen, "TwoBodyOnly", "set", twob);
ostringstream os;
os << Npoints_;
generator()->preinitInterface(wgen, "Points", "set", os.str());
os.str("");
os << Iorder_;
generator()->preinitInterface(wgen, "InterpolationOrder", "set",
os.str());
os.str("");
os << BWshape_;
generator()->preinitInterface(mgen, "BreitWignerShape", "set",
os.str());
}
diff --git a/Models/General/NBodyDecayConstructorBase.h b/Models/General/NBodyDecayConstructorBase.h
--- a/Models/General/NBodyDecayConstructorBase.h
+++ b/Models/General/NBodyDecayConstructorBase.h
@@ -1,340 +1,340 @@
// -*- C++ -*-
//
// NBodyDecayConstructorBase.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_NBodyDecayConstructorBase_H
#define HERWIG_NBodyDecayConstructorBase_H
//
// This is the declaration of the NBodyDecayConstructorBase class.
//
#include "ThePEG/Interface/Interfaced.h"
#include "ThePEG/Utilities/Exception.h"
#include "ThePEG/PDT/ParticleData.h"
#include "NBodyDecayConstructorBase.fh"
#include "PrototypeVertex.h"
#include "DecayConstructor.fh"
namespace Herwig {
using namespace ThePEG;
/**
* This is the base class for NBodyDecayConstructors. An N-body
* decay constructor should inherit from this and implement the
* DecayList virtual funtcion to create the decays and decayers.
*
* @see \ref NBodyDecayConstructorBaseInterfaces "The interfaces"
* defined for NBodyDecayConstructor.
*/
class NBodyDecayConstructorBase: public Interfaced {
public:
/**
* The default constructor.
*/
NBodyDecayConstructorBase() :
init_(true),iteration_(1), points_(1000), info_(false),
createModes_(true), removeOnShell_(1), excludeEffective_(true),
minReleaseFraction_(1e-3), maxBoson_(1), maxList_(1),
includeTopOnShell_(false ), removeFlavourChangingVertices_(false),
removeSmallVertices_(false), minVertexNorm_(1e-8)
{}
/**
* Function used to determine allowed decaymodes, to be implemented
* in derived class.
* @param particles vector of ParticleData pointers containing
* particles in model
*/
virtual void DecayList(const set<PDPtr> & particles);
/**
* Number of outgoing lines. Required for correct ordering.
*/
virtual unsigned int numBodies() const = 0;
/**
* Set the pointer to the DecayConstrcutor
*/
void decayConstructor(tDecayConstructorPtr d) {
decayConstructor_ = d;
}
/**
* Remove flavour changing vertices ?
*/
bool removeFlavourChangingVertices() const {
return removeFlavourChangingVertices_;
}
/**
* Remove small vertices ?
*/
bool removeSmallVertices() const {
return removeSmallVertices_;
}
/**
* Minimum norm for vertex removal
*/
double minVertexNorm() const {
return minVertexNorm_;
}
protected:
/**
* Method to set up the decay mode, should be overidden in inheriting class
*/
virtual void createDecayMode(vector<NBDiagram> & mode,
bool possibleOnShell,
double symfac);
/**
* Set the branching ratio of this mode. This requires
* calculating a new width for the decaying particle and reweighting
* the current branching fractions.
* @param dm The decaymode for which to set the branching ratio
* @param pwidth The calculated width of the mode
*/
void setBranchingRatio(tDMPtr dm, Energy pwidth);
/**
* Set the interfaces of the decayers depending on the flags stored.
* @param name Fullname of the decayer in the EventGenerator
* including the path
*/
void setDecayerInterfaces(string name) const;
/**
* Whether to initialize decayers or not
*/
bool initialize() const { return init_; }
/**
* Number of iterations if initializing (default 1)
*/
int iteration() const { return iteration_; }
/**
* Number of points to do in initialization
*/
int points() const { return points_; }
/**
* Whether to output information on the decayers
*/
bool info() const { return info_; }
/**
* Whether to create the DecayModes as well as the Decayer objects
*/
bool createDecayModes() const { return createModes_; }
/**
* Maximum number of electroweak gauge bosons
*/
unsigned int maximumGaugeBosons() const { return maxBoson_;}
/**
* Maximum number of particles from the list whose decays we are calculating
*/
unsigned int maximumList() const { return maxList_;}
/**
* Minimum energy release fraction
*/
double minimumReleaseFraction() const {return minReleaseFraction_;}
/**
* Get the pointer to the DecayConstructor object
*/
tDecayConstructorPtr decayConstructor() const {
return decayConstructor_;
}
/**
* Option for on-shell particles
*/
unsigned int removeOnShell() const { return removeOnShell_; }
/**
* Check if a vertex is excluded
*/
bool excluded(VertexBasePtr vertex) const {
// skip an effective vertex
if( excludeEffective_ &&
- int(vertex->orderInGs() + vertex->orderInGem()) != int(vertex->getNpoint())-2)
+ vertex->orderInAllCouplings() != int(vertex->getNpoint())-2)
return true;
// check if explicitly forbidden
return excludedVerticesSet_.find(vertex)!=excludedVerticesSet_.end();
}
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();
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
NBodyDecayConstructorBase & operator=(const NBodyDecayConstructorBase &);
private:
/**
* Whether to initialize decayers or not
*/
bool init_;
/**
* Number of iterations if initializing (default 1)
*/
int iteration_;
/**
* Number of points to do in initialization
*/
int points_;
/**
* Whether to output information on the decayers
*/
bool info_;
/**
* Whether to create the DecayModes as well as the Decayer objects
*/
bool createModes_;
/**
* Whether or not to remove on-shell diagrams
*/
unsigned int removeOnShell_;
/**
* Excluded Vertices
*/
vector<VertexBasePtr> excludedVerticesVector_;
/**
* Excluded Vertices
*/
set<VertexBasePtr> excludedVerticesSet_;
/**
* Excluded Particles
*/
vector<PDPtr> excludedParticlesVector_;
/**
* Excluded Particles
*/
set<PDPtr> excludedParticlesSet_;
/**
* Whether or not to exclude effective vertices
*/
bool excludeEffective_;
/**
* A pointer to the DecayConstructor object
*/
tDecayConstructorPtr decayConstructor_;
/**
* The minimum energy release for a three-body decay as a
* fraction of the parent mass
*/
double minReleaseFraction_;
/**
* Maximum number of EW gauge bosons
*/
unsigned int maxBoson_;
/**
* Maximum number of particles from the decaying particle list
*/
unsigned int maxList_;
/**
* Include on-shell for \f$t\to b W\f$
*/
bool includeTopOnShell_;
/**
* Remove flavour changing vertices ?
*/
bool removeFlavourChangingVertices_;
/**
* Remove small vertices ?
*/
bool removeSmallVertices_;
/**
* Minimum norm for vertex removal
*/
double minVertexNorm_;
};
/** An Exception class that can be used by all inheriting classes to
* indicate a setup problem. */
class NBodyDecayConstructorError : public Exception {
public:
NBodyDecayConstructorError() : Exception() {}
NBodyDecayConstructorError(const string & str,
Severity sev) : Exception(str,sev)
{}
};
}
#endif /* HERWIG_NBodyDecayConstructorBase_H */
diff --git a/Models/General/ResonantProcessConstructor.cc b/Models/General/ResonantProcessConstructor.cc
--- a/Models/General/ResonantProcessConstructor.cc
+++ b/Models/General/ResonantProcessConstructor.cc
@@ -1,390 +1,390 @@
// -*- C++ -*-
//
// ResonantProcessConstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ResonantProcessConstructor class.
//
#include "ResonantProcessConstructor.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
using namespace Herwig;
IBPtr ResonantProcessConstructor::clone() const {
return new_ptr(*this);
}
IBPtr ResonantProcessConstructor::fullclone() const {
return new_ptr(*this);
}
void ResonantProcessConstructor::persistentOutput(PersistentOStream & os) const {
os << incoming_ << intermediates_ << outgoing_
<< processOption_ << scaleChoice_ << scaleFactor_;
}
void ResonantProcessConstructor::persistentInput(PersistentIStream & is, int) {
is >> incoming_ >> intermediates_ >> outgoing_
>> processOption_ >> scaleChoice_ >> scaleFactor_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ResonantProcessConstructor,HardProcessConstructor>
describeHerwigResonantProcessConstructor("Herwig::ResonantProcessConstructor", "Herwig.so");
void ResonantProcessConstructor::Init() {
static ClassDocumentation<ResonantProcessConstructor> documentation
("This class is designed solely to contruct resonant processes using"
"a provided set of intermediate particles");
static RefVector<ResonantProcessConstructor, ParticleData> interfaceOffshell
("Intermediates",
"A vector of offshell particles for resonant diagrams",
&ResonantProcessConstructor::intermediates_, -1, false, false, true,
false);
static RefVector<ResonantProcessConstructor, ParticleData> interfaceIncoming
("Incoming",
"A vector of incoming particles for resonant diagrams",
&ResonantProcessConstructor::incoming_, -1, false, false, true,
false);
static RefVector<ResonantProcessConstructor, ParticleData> interfaceOutgoing
("Outgoing",
"A vector of outgoing particles for resonant diagrams",
&ResonantProcessConstructor::outgoing_, -1, false, false, true,
false);
static Switch<ResonantProcessConstructor,unsigned int> interfaceProcesses
("Processes",
"Whether to generate inclusive or exclusive processes",
&ResonantProcessConstructor::processOption_, 0, false, false);
static SwitchOption interfaceProcessesSingleParticleInclusive
(interfaceProcesses,
"SingleParticleInclusive",
"Require at least one particle from the list of outgoing particles"
" in the hard process",
0);
static SwitchOption interfaceProcessesTwoParticleInclusive
(interfaceProcesses,
"TwoParticleInclusive",
"Require that both the particles in the hard processes are in the"
" list of outgoing particles",
1);
static SwitchOption interfaceProcessesExclusive
(interfaceProcesses,
"Exclusive",
"Require that both the particles in the hard processes are in the"
" list of outgoing particles in every hard process",
2);
static SwitchOption interfaceProcessesInclusive
(interfaceProcesses,
"Inclusive",
"Generate all modes which are allowed for the on-shell intermediate particle",
3);
static SwitchOption interfaceProcessesVeryExclusive
(interfaceProcesses,
"VeryExclusive",
"Require that both the incoming and outgoing particles in the hard processes are in the"
" list of outgoing particles in every hard process",
4);
static Switch<ResonantProcessConstructor,unsigned int> interfaceScaleChoice
("ScaleChoice",
"&ResonantProcessConstructor::scaleChoice_",
&ResonantProcessConstructor::scaleChoice_, 1, false, false);
static SwitchOption interfaceScaleChoicesHat
(interfaceScaleChoice,
"sHat",
"Always use sHat",
1);
static SwitchOption interfaceScaleChoiceTransverseMass
(interfaceScaleChoice,
"TransverseMass",
"Always use the transverse mass",
2);
static SwitchOption interfaceScaleChoiceGeometicMean
(interfaceScaleChoice,
"MaxMT",
"Use the maximum of m^2+p_T^2 for the two particles",
3);
static Parameter<ResonantProcessConstructor,double> interfaceScaleFactor
("ScaleFactor",
"The prefactor used in the scale calculation. The scale used is"
" sHat multiplied by this prefactor",
&ResonantProcessConstructor::scaleFactor_, 1.0, 0.0, 10.0,
false, false, Interface::limited);
}
void ResonantProcessConstructor::doinit() {
HardProcessConstructor::doinit();
if((processOption_==2 || processOption_==4) &&
outgoing_.size()!=2)
throw InitException()
<< "Exclusive processes require exactly"
<< " two outgoing particles but " << outgoing_.size()
<< "have been inserted in ResonantProcessConstructor::doinit()."
<< Exception::runerror;
if(processOption_==4 && incoming_.size()!=2)
throw InitException()
<< "Exclusive processes require exactly"
<< " two incoming particles but " << incoming_.size()
<< "have been inserted in ResonantProcessConstructor::doinit()."
<< Exception::runerror;
}
void ResonantProcessConstructor::constructDiagrams() {
size_t ninc = incoming_.size() , ninter = intermediates_.size();
if(ninc == 0 || ninter == 0 || !subProcess() ) return;
// find the incoming particle pairs
vector<tPDPair> incPairs;
for(PDVector::size_type i = 0; i < ninc; ++i) {
for(PDVector::size_type j = 0; j < ninc; ++j) {
tPDPair inc = make_pair(incoming_[i], incoming_[j]);
if( (inc.first->iSpin() > inc.second->iSpin()) ||
(inc.first->iSpin() == inc.second->iSpin() &&
inc.first->id() < inc.second->id()) )
swap(inc.first, inc.second);
if( !HPC_helper::duplicateIncoming(inc,incPairs) ) {
incPairs.push_back(inc);
}
}
}
size_t nvertices = model()->numberOfVertices();
//To construct resonant diagrams loop over the incoming particles, intermediates
//and vertices to find allowed diagrams. Need to exclude the diagrams that have
//the intermediate as an external particle as well
for(vector<tcPDPair>::size_type is = 0; is < incPairs.size(); ++is) {
tPDPair ppi = incPairs[is];
for(vector<PDPtr>::size_type ik = 0; ik < ninter ; ++ik) {
long ipart = intermediates_[ik]->id();
for(size_t iv = 0; iv < nvertices; ++iv) {
VBPtr vertex = model()->vertex(iv);
if(vertex->getNpoint() > 3) continue;
long part1 = ppi.first->CC() ? -ppi.first->id() : ppi.first->id();
long part2 = ppi.second->CC() ? -ppi.second->id() : ppi.second->id();
if(vertex->allowed(part1, part2, ipart) ||
vertex->allowed(part1, ipart, part2) ||
vertex->allowed(part2, part1, ipart) ||
vertex->allowed(part2, ipart, part1) ||
vertex->allowed(ipart, part1, part2) ||
vertex->allowed(ipart, part2, part1) ) {
constructVertex2(make_pair(ppi.first->id(), ppi.second->id()), vertex,
intermediates_[ik]);
}
}
}
}
//Create matrix element for each process
const HPDVector::size_type ndiags = diagrams_.size();
for(HPDVector::size_type ix = 0; ix < ndiags; ++ix)
createMatrixElement(diagrams_[ix]);
}
void ResonantProcessConstructor::
constructVertex2(IDPair in, VertexBasePtr vertex,
PDPtr partc) {
//We have the left hand part of the diagram, just need all the possibilities
//for the RHS
size_t nvertices = model()->numberOfVertices();
if(processOption_!=3) {
for(size_t io = 0; io < outgoing_.size(); ++io) {
tcPDPtr outa = outgoing_[io];
for(size_t iv = 0; iv < nvertices; ++iv) {
VBPtr vertex2 = model()->vertex(iv);
if(vertex2->getNpoint() > 3) continue;
tPDSet outb = search(vertex2, partc->id(), incoming, outa->id(), outgoing,
outgoing);
for(tPDSet::const_iterator ita = outb.begin(); ita != outb.end(); ++ita)
makeResonantDiagram(in, partc, outa->id(),(**ita).id(),
make_pair(vertex, vertex2));
}
}
}
else {
long idRes = !partc->CC() ? partc->id() : partc->CC()->id();
for(size_t iv = 0; iv < nvertices; ++iv) {
VBPtr vertex2 = model()->vertex(iv);
if(vertex2->getNpoint() > 3) continue;
for(unsigned int ix = 0;ix < 3; ++ix) {
vector<long> pdlist = vertex2->search(ix, idRes);
for(unsigned int iy=0;iy<pdlist.size();iy+=3) {
long out1 = ix==0 ? pdlist.at(iy+1) : pdlist.at(iy );
long out2 = ix==2 ? pdlist.at(iy+1) : pdlist.at(iy+2);
if(partc->mass() < getParticleData(out1)->mass() +
getParticleData(out2)->mass()) continue;
makeResonantDiagram(in, partc, out1, out2,
make_pair(vertex, vertex2));
}
}
}
}
}
void ResonantProcessConstructor::
makeResonantDiagram(IDPair in, PDPtr offshell, long outa, long outb,
VBPair vertpair) {
assert(vertpair.first && vertpair.second);
if( abs(outa) == abs(offshell->id()) ||
abs(outb) == abs(offshell->id())) return;
HPDiagram newdiag(in,make_pair(outa,outb));
newdiag.intermediate = offshell;
newdiag.vertices = vertpair;
newdiag.channelType = HPDiagram::sChannel;
fixFSOrder(newdiag);
assignToCF(newdiag);
if(duplicate(newdiag,diagrams_)) return;
// if inclusive enforce the exclusivity
if(processOption_==1) {
PDVector::const_iterator loc =
std::find(outgoing_.begin(),outgoing_.end(),
getParticleData(newdiag.outgoing. first));
if(loc==outgoing_.end()) return;
loc =
std::find(outgoing_.begin(),outgoing_.end(),
getParticleData(newdiag.outgoing.second));
if(loc==outgoing_.end()) return;
}
else if(processOption_==2 || processOption_==4 ) {
if(!((newdiag.outgoing. first==outgoing_[0]->id()&&
newdiag.outgoing.second==outgoing_[1]->id())||
(newdiag.outgoing. first==outgoing_[1]->id()&&
newdiag.outgoing.second==outgoing_[0]->id())))
return;
if(processOption_==4) {
if(!((newdiag.incoming. first==incoming_[0]->id()&&
newdiag.incoming.second==incoming_[1]->id())||
(newdiag.incoming. first==incoming_[1]->id()&&
newdiag.incoming.second==incoming_[0]->id())))
return;
}
}
// add to the list
- diagrams_.push_back(newdiag);
+ if(checkOrder(newdiag)) diagrams_.push_back(newdiag);
}
set<tPDPtr>
ResonantProcessConstructor::search(VBPtr vertex, long part1, direction d1,
long part2, direction d2, direction d3) {
if(d1 == incoming && getParticleData(part1)->CC()) part1 = -part1;
if(d2 == incoming && getParticleData(part2)->CC()) part2 = -part2;
vector<long> ext;
tPDSet third;
for(unsigned int ix = 0;ix < 3; ++ix) {
vector<long> pdlist = vertex->search(ix, part1);
ext.insert(ext.end(), pdlist.begin(), pdlist.end());
}
for(unsigned int ix = 0; ix < ext.size(); ix += 3) {
long id0 = ext.at(ix);
long id1 = ext.at(ix+1);
long id2 = ext.at(ix+2);
int pos;
if((id0 == part1 && id1 == part2) ||
(id0 == part2 && id1 == part1))
pos = ix + 2;
else if((id0 == part1 && id2 == part2) ||
(id0 == part2 && id2 == part1))
pos = ix + 1;
else if((id1 == part1 && id2 == part2) ||
(id1 == part2 && id2 == part1))
pos = ix;
else
pos = -1;
if(pos >= 0) {
tPDPtr p = getParticleData(ext[pos]);
if(d3 == incoming && p->CC()) p = p->CC();
third.insert(p);
}
}
return third;
}
IDPair ResonantProcessConstructor::
find(long part, const vector<PDPtr> & out) const {
vector<PDPtr>::size_type iloc(0);
bool found(false);
do {
if(out[iloc]->id() == part) found = true;
else ++iloc;
}
while(found == false && iloc < out.size());
//found offshell
IDPair outids;
if(iloc == 0)
outids = make_pair(out[1]->id(), out[2]->id());
else if(iloc == 1)
outids = make_pair(out[0]->id(), out[2]->id());
else
outids = make_pair(out[0]->id(), out[1]->id());
return outids;
}
void ResonantProcessConstructor::
createMatrixElement(const HPDiagram & diag) const {
vector<tcPDPtr> extpart(4);
extpart[0] = getParticleData(diag.incoming.first);
extpart[1] = getParticleData(diag.incoming.second);
extpart[2] = getParticleData(diag.outgoing.first);
extpart[3] = getParticleData(diag.outgoing.second);
string objectname ("/Herwig/MatrixElements/");
string classname = MEClassname(extpart, diag.intermediate, objectname);
GeneralHardMEPtr matrixElement = dynamic_ptr_cast<GeneralHardMEPtr>
(generator()->preinitCreate(classname, objectname));
if( !matrixElement ) {
throw RPConstructorError()
<< "ResonantProcessConstructor::createMatrixElement "
<< "- No matrix element object could be created for "
<< "the process "
<< extpart[0]->PDGName() << " " << extpart[0]->iSpin() << ","
<< extpart[1]->PDGName() << " " << extpart[1]->iSpin() << "->"
<< extpart[2]->PDGName() << " " << extpart[2]->iSpin() << ","
<< extpart[3]->PDGName() << " " << extpart[3]->iSpin()
<< ". Constructed class name: \"" << classname << "\"\n"
<< Exception::warning;
return;
}
matrixElement->setProcessInfo(HPDVector(1, diag),
colourFlow(extpart), debug(),scaleChoice_-1,scaleFactor_);
generator()->preinitInterface(subProcess(), "MatrixElements",
subProcess()->MEs().size(),
"insert", matrixElement->fullName());
}
string ResonantProcessConstructor::
MEClassname(const vector<tcPDPtr> & extpart, tcPDPtr inter,
string & objname) const {
string classname("Herwig::ME");
for(vector<tcPDPtr>::size_type ix = 0; ix < extpart.size(); ++ix) {
if(ix == 2) classname += "2";
if(extpart[ix]->iSpin() == PDT::Spin0) classname += "s";
else if(extpart[ix]->iSpin() == PDT::Spin1) classname += "v";
else if(extpart[ix]->iSpin() == PDT::Spin1Half) classname += "f";
else if(extpart[ix]->iSpin() == PDT::Spin2) classname += "t";
else
throw RPConstructorError()
<< "MEClassname() : Encountered an unknown spin for "
<< extpart[ix]->PDGName() << " while constructing MatrixElement "
<< "classname " << extpart[ix]->iSpin() << Exception::warning;
}
objname += "ME" + extpart[0]->PDGName() + extpart[1]->PDGName() + "2"
+ inter->PDGName() + "2"
+ extpart[2]->PDGName() + extpart[3]->PDGName();
return classname;
}
diff --git a/Models/General/ThreeBodyDecayConstructor.cc b/Models/General/ThreeBodyDecayConstructor.cc
--- a/Models/General/ThreeBodyDecayConstructor.cc
+++ b/Models/General/ThreeBodyDecayConstructor.cc
@@ -1,373 +1,374 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ThreeBodyDecayConstructor class.
//
#include "ThreeBodyDecayConstructor.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Utilities/Debug.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "Herwig/Decay/General/GeneralThreeBodyDecayer.h"
#include "Herwig/Decay/DecayPhaseSpaceMode.h"
#include "Herwig/PDT/ThreeBodyAllOnCalculator.h"
#include "ThePEG/PDT/StandardMatchers.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Utilities/Throw.h"
#include "DecayConstructor.h"
#include "WeakCurrentDecayConstructor.h"
using namespace Herwig;
IBPtr ThreeBodyDecayConstructor::clone() const {
return new_ptr(*this);
}
IBPtr ThreeBodyDecayConstructor::fullclone() const {
return new_ptr(*this);
}
void ThreeBodyDecayConstructor::persistentOutput(PersistentOStream & os) const {
os << interOpt_ << widthOpt_ << intOpt_ << relErr_
<< includeIntermediatePhotons_;
}
void ThreeBodyDecayConstructor::persistentInput(PersistentIStream & is, int) {
is >> interOpt_ >> widthOpt_ >> intOpt_ >> relErr_
>> includeIntermediatePhotons_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ThreeBodyDecayConstructor,NBodyDecayConstructorBase>
describeHerwigThreeBodyDecayConstructor("Herwig::ThreeBodyDecayConstructor", "Herwig.so");
void ThreeBodyDecayConstructor::Init() {
static ClassDocumentation<ThreeBodyDecayConstructor> documentation
("The ThreeBodyDecayConstructor class constructs the three body decay modes");
static Switch<ThreeBodyDecayConstructor,bool> interfaceIncludeIntermediatePhotons
("IncludeIntermediatePhotons",
"Whether or not ot allow intermediate photons",
&ThreeBodyDecayConstructor::includeIntermediatePhotons_, false, false, false);
static SwitchOption interfaceIncludeIntermediatePhotonsYes
(interfaceIncludeIntermediatePhotons,
"Yes",
"Include them",
true);
static SwitchOption interfaceIncludeIntermediatePhotonsNo
(interfaceIncludeIntermediatePhotons,
"No",
"Don't include them",
false);
static Switch<ThreeBodyDecayConstructor,unsigned int> interfaceWidthOption
("WidthOption",
"Option for the treatment of the widths of the intermediates",
&ThreeBodyDecayConstructor::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<ThreeBodyDecayConstructor,unsigned int> interfaceIntermediateOption
("IntermediateOption",
"Option for the inclusion of intermediates in the event",
&ThreeBodyDecayConstructor::interOpt_, 0, false, false);
static SwitchOption interfaceIntermediateOptionAlways
(interfaceIntermediateOption,
"Always",
"Always include the intermediates",
1);
static SwitchOption interfaceIntermediateOptionNever
(interfaceIntermediateOption,
"Never",
"Never include the intermediates",
2);
static SwitchOption interfaceIntermediateOptionOnlyIfOnShell
(interfaceIntermediateOption,
"OnlyIfOnShell",
"Only if there are on-shell diagrams",
0);
static Switch<ThreeBodyDecayConstructor,unsigned int> interfaceIntegrationOption
("IntegrationOption",
"Option for the integration of the partial width",
&ThreeBodyDecayConstructor::intOpt_, 1, false, false);
static SwitchOption interfaceIntegrationOptionAllPoles
(interfaceIntegrationOption,
"AllPoles",
"Include all potential poles",
0);
static SwitchOption interfaceIntegrationOptionShallowestPole
(interfaceIntegrationOption,
"ShallowestPole",
"Only include the shallowest pole",
1);
static Parameter<ThreeBodyDecayConstructor,double> interfaceRelativeError
("RelativeError",
"The relative error for the GQ integration",
&ThreeBodyDecayConstructor::relErr_, 1e-2, 1e-10, 1.,
false, false, Interface::limited);
}
void ThreeBodyDecayConstructor::DecayList(const set<PDPtr> & particles) {
if( particles.empty() ) return;
// special for weak decays
for(unsigned int ix=0;ix<decayConstructor()->decayConstructors().size();++ix) {
Ptr<Herwig::WeakCurrentDecayConstructor>::pointer
weak = dynamic_ptr_cast<Ptr<Herwig::WeakCurrentDecayConstructor>::pointer >
(decayConstructor()->decayConstructors()[ix]);
if(!weak) continue;
weakMassCut_ = max(weakMassCut_,weak->massCut());
}
NBodyDecayConstructorBase::DecayList(particles);
}
GeneralThreeBodyDecayerPtr ThreeBodyDecayConstructor::
createDecayer(vector<TBDiagram> & diagrams, bool inter,
double symfac) const {
if(diagrams.empty()) return GeneralThreeBodyDecayerPtr();
// extract the external particles for the process
PDPtr incoming = getParticleData(diagrams[0].incoming);
// outgoing particles
OrderedParticles outgoing;
outgoing.insert(getParticleData(diagrams[0].outgoing ));
outgoing.insert(getParticleData(diagrams[0].outgoingPair.first ));
outgoing.insert(getParticleData(diagrams[0].outgoingPair.second));
// get the object name
string objectname ("/Herwig/Decays/");
string classname = DecayerClassName(incoming, outgoing, objectname);
if(classname=="") return GeneralThreeBodyDecayerPtr();
// create the object
GeneralThreeBodyDecayerPtr decayer =
dynamic_ptr_cast<GeneralThreeBodyDecayerPtr>
(generator()->preinitCreate(classname, objectname));
// set up the decayer and return if doesn't work
vector<PDPtr> outVector(outgoing.begin(),outgoing.end());
if(!decayer->setDecayInfo(incoming,outVector,diagrams,symfac))
return GeneralThreeBodyDecayerPtr();
// set decayer options from base class
setDecayerInterfaces(objectname);
// options for partial width integration
ostringstream value;
value << intOpt_;
generator()->preinitInterface(objectname, "PartialWidthIntegration", "set",
value.str());
value.str("");
value << relErr_;
generator()->preinitInterface(objectname, "RelativeError", "set",
value.str());
// set the width option
value.str("");
value << widthOpt_;
generator()->preinitInterface(objectname, "WidthOption", "set", value.str());
// set the intermediates option
value.str("");
value << inter;
generator()->preinitInterface(objectname, "GenerateIntermediates", "set",
value.str());
// initialize the decayer
decayer->init();
// return the decayer
return decayer;
}
string ThreeBodyDecayConstructor::
DecayerClassName(tcPDPtr incoming, const OrderedParticles & outgoing,
string & objname) const {
string classname("Herwig::");
// spins of the outgoing particles
unsigned int ns(0),nf(0),nv(0);
objname += incoming->PDGName() + "2";
for(OrderedParticles::const_iterator it=outgoing.begin();
it!=outgoing.end();++it) {
if ((**it).iSpin()==PDT::Spin0 ) ++ns;
else if((**it).iSpin()==PDT::Spin1Half) ++nf;
else if((**it).iSpin()==PDT::Spin1 ) ++nv;
objname += (**it).PDGName();
}
objname += "Decayer";
if(incoming->iSpin()==PDT::Spin0) {
if(ns==1&&nf==2) classname += "StoSFFDecayer";
else if(nf==2&&nv==1) classname += "StoFFVDecayer";
else classname = "";
}
else if(incoming->iSpin()==PDT::Spin1Half) {
if(nf==3) classname += "FtoFFFDecayer";
else if(nf==1&&nv==2) classname += "FtoFVVDecayer";
else classname = "";
}
else if(incoming->iSpin()==PDT::Spin1) {
if(nf==2&&nv==1) classname += "VtoFFVDecayer";
else classname = "";
}
else {
classname="";
}
return classname;
}
void ThreeBodyDecayConstructor::
createDecayMode(vector<NBDiagram> & mode,
bool possibleOnShell,
double symfac) {
// convert the diagrams from the general to the three body structure
vector<TBDiagram> diagrams;
for(unsigned int iy=0;iy<mode.size();++iy) {
diagrams.push_back(TBDiagram(mode[iy]));
// determine the type
- diagrams.back().channelType = TBDiagram::Channel(mode[iy].channelType[0]-1);
+ diagrams.back().channelType = diagrams.back().intermediate ?
+ TBDiagram::Channel(mode[iy].channelType[0]-1) : TBDiagram::fourPoint;
// remove weak processes simulated using the weak current
if(weakMassCut_>ZERO && diagrams.back().intermediate &&
abs(diagrams.back().intermediate->id())==ParticleID::Wplus) {
Energy deltaM =
getParticleData(diagrams.back().incoming)->mass() -
getParticleData(diagrams.back().outgoing)->mass();
if(deltaM<weakMassCut_) diagrams.pop_back();
}
// remove intermediate photons
else if(!includeIntermediatePhotons_ &&
diagrams.back().intermediate &&
abs(diagrams.back().intermediate->id())==ParticleID::gamma)
diagrams.pop_back();
}
if(diagrams.empty()) return;
// check if possible on-shell internal particles
bool inter = interOpt_ == 1 || (interOpt_ == 0 && possibleOnShell);
// incoming particle
tPDPtr inpart = getParticleData(diagrams[0].incoming);
// outgoing particles
OrderedParticles outgoing;
outgoing.insert(getParticleData(diagrams[0].outgoing));
outgoing.insert(getParticleData(diagrams[0].outgoingPair.first ));
outgoing.insert(getParticleData(diagrams[0].outgoingPair.second));
// sort out ordering and labeling of diagrams
vector<PDPtr> outVector(outgoing.begin(),outgoing.end());
for(unsigned int ix=0;ix<diagrams.size();++ix) {
if( ( diagrams[ix].channelType == TBDiagram::channel23 &&
outVector[1]->id() != diagrams[ix].outgoingPair.first) ||
( diagrams[ix].channelType == TBDiagram::channel13 &&
outVector[0]->id() != diagrams[ix].outgoingPair.first) ||
( diagrams[ix].channelType == TBDiagram::channel12 &&
outVector[0]->id() != diagrams[ix].outgoingPair.first) )
swap(diagrams[ix].outgoingPair.first, diagrams[ix].outgoingPair.second);
}
// construct the tag for the decay mode
string tag = inpart->name() + "->";
unsigned int iprod=0;
for(OrderedParticles::const_iterator it = outgoing.begin();
it != outgoing.end(); ++it) {
++iprod;
tag += (**it).name();
if(iprod != 3) tag += ",";
}
tag += ";";
tDMPtr dm = generator()->findDecayMode(tag);
// create mode if needed
if( createDecayModes() && (!dm || inpart->id() == ParticleID::h0) ) {
// create the decayer
GeneralThreeBodyDecayerPtr decayer = createDecayer(diagrams,inter,symfac);
if(!decayer) {
if(Debug::level > 1 ) generator()->log() << "Can't create the decayer for "
<< tag << " so mode not created\n";
return;
}
tDMPtr ndm = generator()->preinitCreateDecayMode(tag);
if(ndm) {
generator()->preinitInterface(ndm, "Decayer", "set",
decayer->fullName());
generator()->preinitInterface(ndm, "Active", "set", "Yes");
if(!ndm->decayer()) {
generator()->log() << "Can't set the decayer for "
<< tag << " so mode not created \n";
return;
}
OrderedParticles::const_iterator pit=outgoing.begin();
tPDPtr pa = *pit; ++pit;
tPDPtr pb = *pit; ++pit;
tPDPtr pc = *pit;
Energy width =
decayer->partialWidth(make_pair(inpart,inpart->mass()),
make_pair(pa,pa->mass()) ,
make_pair(pb,pb->mass()) ,
make_pair(pc,pc->mass()));
if ( Debug::level > 1 )
generator()->log() << "Partial width is: " << width / GeV << " GeV\n";
setBranchingRatio(ndm, width);
if(ndm->brat()<decayConstructor()->minimumBR()) {
generator()->preinitInterface(decayer->fullName(),
"Initialize", "set","0");
}
// incoming particle is now unstable
inpart->stable(false);
if(Debug::level > 1 ) {
generator()->log() << "Calculated partial width for mode "
<< tag << " is " << width/GeV << "\n";
}
}
else
throw NBodyDecayConstructorError()
<< "ThreeBodyDecayConstructor::createDecayMode - Needed to create "
<< "new decaymode but one could not be created for the tag "
<< tag << Exception::warning;
}
else if( dm ) {
if(dm->brat()<decayConstructor()->minimumBR()) {
return;
}
if((dm->decayer()->fullName()).find("Mambo") != string::npos) {
// create the decayer
GeneralThreeBodyDecayerPtr decayer = createDecayer(diagrams,inter,symfac);
if(decayer) {
generator()->preinitInterface(dm, "Decayer", "set",
decayer->fullName());
// check not zero
OrderedParticles::const_iterator pit=outgoing.begin();
tPDPtr pa = *pit; ++pit;
tPDPtr pb = *pit; ++pit;
tPDPtr pc = *pit;
Energy width =
decayer->partialWidth(make_pair(inpart,inpart->mass()),
make_pair(pa,pa->mass()) ,
make_pair(pb,pb->mass()) ,
make_pair(pc,pc->mass()));
if(width/(dm->brat()*inpart->width())<1e-10) {
string message = "Herwig calculation of the partial width for the decay mode "
+ inpart->PDGName() + " -> " + pa->PDGName() + " " + pb->PDGName() + " " + pc->PDGName()
+ " is zero.\n This will cause problems with the calculation of"
+ " spin correlations.\n It is probably due to inconsistent parameters"
+ " and decay modes being passed to Herwig via the SLHA file.\n"
+ " Zeroing the branching ratio for this mode.";
setBranchingRatio(dm,ZERO);
generator()->logWarning(NBodyDecayConstructorError(message,Exception::warning));
}
}
// incoming particle is now unstable
inpart->stable(false);
}
}
//update CC mode if it exists
if( inpart->CC() ) inpart->CC()->synchronize();
}
diff --git a/Models/General/TwoBodyDecay.h b/Models/General/TwoBodyDecay.h
--- a/Models/General/TwoBodyDecay.h
+++ b/Models/General/TwoBodyDecay.h
@@ -1,80 +1,89 @@
// -*- C++ -*-
//
// TwoBodyDecay.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_TwoBodyDecay_H
#define HERWIG_TwoBodyDecay_H
//
// This is the declaration of the TwoBodyDecay struct.
//
namespace Herwig {
using namespace ThePEG;
using Helicity::tVertexBasePtr;
/**
* Struct for the prototype of a two-body decay mode
*/
struct TwoBodyDecay {
public:
/**
* Constructor
* @param pa Decaying particle
* @param pb First decay product
* @param pc Second decay product
*/
TwoBodyDecay(tPDPtr pa, tPDPtr pb, tPDPtr pc,
tVertexBasePtr vertex) : parent_(pa), vertex_(vertex) {
ParticleOrdering order;
if( order(pb, pc) ) {
children_.first = pb;
children_.second = pc;
}
else {
children_.first = pc;
children_.second = pb;
}
}
/**
* The parent
*/
tPDPtr parent_;
/**
* The children
*/
tPDPair children_;
/**
* Vertex
*/
tVertexBasePtr vertex_;
private:
TwoBodyDecay();
};
/**
* Test whether one TwoBodyDecay is less than another
*/
inline bool operator<(const TwoBodyDecay & x, const TwoBodyDecay & y) {
if(x.parent_->id()!=y.parent_->id())
return x.parent_->id()<y.parent_->id();
if(x.children_.first->id()!=y.children_.first->id())
return x.children_.first->id() < y.children_.first->id();
if(x.children_.second->id()!=y.children_.second->id())
return x.children_.second->id() < y.children_.second->id();
- return x.vertex_<y.vertex_;
+ return false;
+}
+inline bool operator==(const TwoBodyDecay & x, const TwoBodyDecay & y) {
+ if(x.parent_->id()!=y.parent_->id())
+ return false;
+ if(x.children_.first->id()!=y.children_.first->id())
+ return false;
+ if(x.children_.second->id()!=y.children_.second->id())
+ return false;
+ return true;
}
}
#endif /* HERWIG_TwoBodyDecay_H */
diff --git a/Models/General/TwoBodyDecayConstructor.cc b/Models/General/TwoBodyDecayConstructor.cc
--- a/Models/General/TwoBodyDecayConstructor.cc
+++ b/Models/General/TwoBodyDecayConstructor.cc
@@ -1,422 +1,432 @@
// -*- C++ -*-
//
// TwoBodyDecayConstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TwoBodyDecayConstructor class.
//
#include "TwoBodyDecayConstructor.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Switch.h"
#include "Herwig/Decay/General/GeneralTwoBodyDecayer.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "DecayConstructor.h"
#include "ThePEG/Utilities/Throw.h"
#include "ThePEG/Utilities/EnumIO.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractVSSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractVVTVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractFFTVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractSSTVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractSSSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractRFSVertex.fh"
#include "ThePEG/Helicity/Vertex/AbstractRFVVertex.fh"
using namespace Herwig;
using ThePEG::Helicity::VertexBasePtr;
IBPtr TwoBodyDecayConstructor::clone() const {
return new_ptr(*this);
}
IBPtr TwoBodyDecayConstructor::fullclone() const {
return new_ptr(*this);
}
void TwoBodyDecayConstructor::persistentOutput(PersistentOStream & os) const {
os << alphaQCD_ << alphaQED_ << oenum(inter_);
}
void TwoBodyDecayConstructor::persistentInput(PersistentIStream & is, int) {
is >> alphaQCD_ >> alphaQED_>> ienum(inter_);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TwoBodyDecayConstructor,NBodyDecayConstructorBase>
describeHerwigTwoBodyDecayConstructor("Herwig::TwoBodyDecayConstructor", "Herwig.so");
void TwoBodyDecayConstructor::Init() {
static ClassDocumentation<TwoBodyDecayConstructor> documentation
("The TwoBodyDecayConstructor implements to creation of 2 body decaymodes "
"and decayers that do not already exist for the given set of vertices.");
static Reference<TwoBodyDecayConstructor,ShowerAlpha> interfaceShowerAlphaQCD
("AlphaQCD",
"The coupling for QCD corrections",
&TwoBodyDecayConstructor::alphaQCD_, false, false, true, false, false);
static Reference<TwoBodyDecayConstructor,ShowerAlpha> interfaceShowerAlphaQED
("AlphaQED",
"The coupling for QED corrections",
&TwoBodyDecayConstructor::alphaQED_, false, false, true, false, false);
static Switch<TwoBodyDecayConstructor,ShowerInteraction> interfaceInteractions
("Interactions",
"which interactions to include for the hard corrections",
&TwoBodyDecayConstructor::inter_, ShowerInteraction::QCD, false, false);
static SwitchOption interfaceInteractionsQCD
(interfaceInteractions,
"QCD",
"QCD Only",
ShowerInteraction::QCD);
static SwitchOption interfaceInteractionsQED
(interfaceInteractions,
"QED",
"QED only",
ShowerInteraction::QED);
static SwitchOption interfaceInteractionsQCDandQED
(interfaceInteractions,
"QCDandQED",
"Both QCD and QED",
ShowerInteraction::QEDQCD);
}
void TwoBodyDecayConstructor::DecayList(const set<PDPtr> & particles) {
if( particles.empty() ) return;
tHwSMPtr model = dynamic_ptr_cast<tHwSMPtr>(generator()->standardModel());
unsigned int nv(model->numberOfVertices());
for(set<PDPtr>::const_iterator ip=particles.begin();
ip!=particles.end();++ip) {
tPDPtr parent = *ip;
if ( Debug::level > 0 )
Repository::cout() << "Constructing 2-body decays for "
<< parent->PDGName() << '\n';
+ multiset<TwoBodyDecay> decays;
for(unsigned int iv = 0; iv < nv; ++iv) {
if(excluded(model->vertex(iv)) ||
model->vertex(iv)->getNpoint()>3) continue;
- for(unsigned int il = 0; il < 3; ++il) {
- set<TwoBodyDecay> decays =
- createModes(parent, model->vertex(iv), il);
- if( !decays.empty() ) createDecayMode(decays);
- }
+ for(unsigned int il = 0; il < 3; ++il)
+ createModes(parent, model->vertex(iv), il,decays);
}
+ if( !decays.empty() ) createDecayMode(decays);
}
}
-set<TwoBodyDecay> TwoBodyDecayConstructor::
+void TwoBodyDecayConstructor::
createModes(tPDPtr inpart, VertexBasePtr vertex,
- unsigned int list) {
+ unsigned int list, multiset<TwoBodyDecay> & modes) {
if( !vertex->isIncoming(inpart) || vertex->getNpoint() != 3 )
- return set<TwoBodyDecay>();
+ return;
Energy m1(inpart->mass());
tPDPtr ccpart = inpart->CC() ? inpart->CC() : inpart;
long id = ccpart->id();
tPDVector decaylist = vertex->search(list, ccpart);
- set<TwoBodyDecay> decays;
tPDVector::size_type nd = decaylist.size();
for( tPDVector::size_type i = 0; i < nd; i += 3 ) {
tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]);
if( pb->id() == id ) swap(pa, pb);
if( pc->id() == id ) swap(pa, pc);
//allowed on-shell decay?
if( m1 <= pb->mass() + pc->mass() ) continue;
//vertices are defined with all particles incoming
- decays.insert( TwoBodyDecay(inpart,pb, pc, vertex) );
+ modes.insert( TwoBodyDecay(inpart,pb, pc, vertex) );
}
- return decays;
}
-GeneralTwoBodyDecayerPtr TwoBodyDecayConstructor::createDecayer(TwoBodyDecay decay) {
+GeneralTwoBodyDecayerPtr
+TwoBodyDecayConstructor::createDecayer(TwoBodyDecay decay,
+ vector<VertexBasePtr> vertices) {
string name;
using namespace Helicity::VertexType;
PDT::Spin in = decay.parent_->iSpin();
// PDT::Spin out1 = decay.children_.first ->iSpin();
PDT::Spin out2 = decay.children_.second->iSpin();
switch(decay.vertex_->getName()) {
case FFV :
if(in == PDT::Spin1Half) {
name = "FFVDecayer";
if(out2==PDT::Spin1Half)
swap(decay.children_.first,decay.children_.second);
}
else {
name = "VFFDecayer";
}
break;
case FFS :
if(in == PDT::Spin1Half) {
name = "FFSDecayer";
if(out2==PDT::Spin1Half)
swap(decay.children_.first,decay.children_.second);
}
else {
name = "SFFDecayer";
}
break;
case VVS :
if(in == PDT::Spin1) {
name = "VVSDecayer";
if(out2==PDT::Spin1)
swap(decay.children_.first,decay.children_.second);
}
else {
name = "SVVDecayer";
}
break;
case VSS :
if(in == PDT::Spin1) {
name = "VSSDecayer";
}
else {
name = "SSVDecayer";
if(out2==PDT::Spin0)
swap(decay.children_.first,decay.children_.second);
}
break;
case VVT :
name = in==PDT::Spin2 ? "TVVDecayer" : "Unknown";
break;
case FFT :
name = in==PDT::Spin2 ? "TFFDecayer" : "Unknown";
break;
case SST :
name = in==PDT::Spin2 ? "TSSDecayer" : "Unknown";
break;
case SSS :
name = "SSSDecayer";
break;
case VVV :
name = "VVVDecayer";
break;
case RFS :
if(in==PDT::Spin1Half) {
name = "FRSDecayer";
if(out2==PDT::Spin3Half)
swap(decay.children_.first,decay.children_.second);
}
else if(in==PDT::Spin0) {
name = "SRFDecayer";
if(out2==PDT::Spin3Half)
swap(decay.children_.first,decay.children_.second);
}
else {
name = "Unknown";
}
break;
case RFV :
if(in==PDT::Spin1Half) {
name = "FRVDecayer";
if(out2==PDT::Spin3Half)
swap(decay.children_.first,decay.children_.second);
}
else
name = "Unknown";
break;
default : Throw<NBodyDecayConstructorError>()
<< "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. "
<< "Decay is " << decay.parent_->PDGName() << " -> "
<< decay.children_.first ->PDGName() << " "
<< decay.children_.second->PDGName() << Exception::runerror;
}
if(name=="Unknown")
Throw<NBodyDecayConstructorError>()
<< "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. "
<< "Decay is " << decay.parent_->PDGName() << " -> "
<< decay.children_.first ->PDGName() << " "
<< decay.children_.second->PDGName() << Exception::runerror;
ostringstream fullname;
fullname << "/Herwig/Decays/" << name << "_" << decay.parent_->PDGName()
<< "_" << decay.children_.first ->PDGName()
<< "_" << decay.children_.second->PDGName();
string classname = "Herwig::" + name;
GeneralTwoBodyDecayerPtr decayer;
decayer = dynamic_ptr_cast<GeneralTwoBodyDecayerPtr>
(generator()->preinitCreate(classname,fullname.str()));
if(!decayer)
Throw<NBodyDecayConstructorError>()
<< "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. "
<< "Decay is " << decay.parent_->PDGName() << " -> "
<< decay.children_.first ->PDGName() << " "
<< decay.children_.second->PDGName() << Exception::runerror;
// set the strong coupling for radiation
generator()->preinitInterface(decayer, "AlphaS" , "set", alphaQCD_->fullName());
// set the EM coupling for radiation
generator()->preinitInterface(decayer, "AlphaEM", "set", alphaQED_->fullName());
// set the type of interactions for the correction
if(inter_==ShowerInteraction::QCD)
generator()->preinitInterface(decayer, "Interactions", "set", "QCD");
else if(inter_==ShowerInteraction::QED)
generator()->preinitInterface(decayer, "Interactions", "set", "QED");
else
generator()->preinitInterface(decayer, "Interactions", "set", "QCDandQED");
// get the vertices for radiation from the external legs
map<ShowerInteraction,VertexBasePtr> inRad,fourRad;
vector<map<ShowerInteraction,VertexBasePtr> > outRad(2);
vector<ShowerInteraction> itemp={ShowerInteraction::QCD,ShowerInteraction::QED};
for(auto & inter : itemp) {
inRad[inter] = radiationVertex(decay.parent_,inter);
outRad[0][inter] = radiationVertex(decay.children_.first ,inter);
outRad[1][inter] = radiationVertex(decay.children_.second,inter);
// get any contributing 4 point vertices
fourRad[inter] = radiationVertex(decay.parent_,inter, decay.children_);
}
// set info on decay
- decayer->setDecayInfo(decay.parent_,decay.children_,decay.vertex_,
+ decayer->setDecayInfo(decay.parent_,decay.children_,vertices,
inRad,outRad,fourRad);
// initialised the decayer
setDecayerInterfaces(fullname.str());
decayer->init();
return decayer;
}
void TwoBodyDecayConstructor::
-createDecayMode(set<TwoBodyDecay> & decays) {
+createDecayMode(multiset<TwoBodyDecay> & decays) {
tPDPtr inpart = decays.begin()->parent_;
- set<TwoBodyDecay>::iterator dend = decays.end();
- for( set<TwoBodyDecay>::iterator dit = decays.begin();
- dit != dend; ++dit ) {
- tPDPtr pb((*dit).children_.first), pc((*dit).children_.second);
+ for( multiset<TwoBodyDecay>::iterator dit = decays.begin();
+ dit != decays.end(); ) {
+ TwoBodyDecay mode = *dit;
+ // get all the moees with the same in and outgoing particles
+ pair<multiset<TwoBodyDecay>::iterator,
+ multiset<TwoBodyDecay>::iterator> range = decays.equal_range(mode);
+ // construct the decay mode
+ tPDPtr pb((mode).children_.first), pc((mode).children_.second);
string tag = inpart->name() + "->" + pb->name() + "," +
pc->name() + ";";
// Does it exist already ?
tDMPtr dm = generator()->findDecayMode(tag);
+ // find the vertices
+ vector<VertexBasePtr> vertices;
+ for ( multiset<TwoBodyDecay>::iterator dit2 = range.first;
+ dit2 != range.second; ++dit2) {
+ vertices.push_back(dit2->vertex_);
+ }
+ dit=range.second;
// now create DecayMode objects that do not already exist
if( createDecayModes() && (!dm || inpart->id() == ParticleID::h0) ) {
tDMPtr ndm = generator()->preinitCreateDecayMode(tag);
if(ndm) {
inpart->stable(false);
- GeneralTwoBodyDecayerPtr decayer=createDecayer(*dit);
+ GeneralTwoBodyDecayerPtr decayer=createDecayer(mode,vertices);
if(!decayer) continue;
generator()->preinitInterface(ndm, "Decayer", "set",
decayer->fullName());
generator()->preinitInterface(ndm, "Active", "set", "Yes");
Energy width =
decayer->partialWidth(make_pair(inpart,inpart->mass()),
make_pair(pb,pb->mass()) ,
make_pair(pc,pc->mass()));
setBranchingRatio(ndm, width);
if(width==ZERO || ndm->brat()<decayConstructor()->minimumBR()) {
generator()->preinitInterface(decayer->fullName(),
"Initialize", "set","0");
}
}
else
Throw<NBodyDecayConstructorError>()
<< "TwoBodyDecayConstructor::createDecayMode - Needed to create "
<< "new decaymode but one could not be created for the tag "
<< tag << Exception::warning;
}
else if( dm ) {
if(dm->brat()<decayConstructor()->minimumBR()) {
continue;
}
if((dm->decayer()->fullName()).find("Mambo") != string::npos) {
inpart->stable(false);
- GeneralTwoBodyDecayerPtr decayer=createDecayer(*dit);
+ GeneralTwoBodyDecayerPtr decayer=createDecayer(mode,vertices);
if(!decayer) continue;
generator()->preinitInterface(dm, "Decayer", "set",
decayer->fullName());
Energy width =
decayer->partialWidth(make_pair(inpart,inpart->mass()),
make_pair(pb,pb->mass()) ,
make_pair(pc,pc->mass()));
if(width/(dm->brat()*inpart->width())<1e-10) {
string message = "Herwig calculation of the partial width for the decay mode "
+ inpart->PDGName() + " -> " + pb->PDGName() + " " + pc->PDGName()
+ " is zero.\n This will cause problems with the calculation of"
+ " spin correlations.\n It is probably due to inconsistent parameters"
+ " and decay modes being passed to Herwig via the SLHA file.\n"
+ " Zeroing the branching ratio for this mode.";
setBranchingRatio(dm,ZERO);
generator()->logWarning(NBodyDecayConstructorError(message,Exception::warning));
}
}
}
}
// update CC mode if it exists
if( inpart->CC() ) inpart->CC()->synchronize();
}
VertexBasePtr TwoBodyDecayConstructor::radiationVertex(tPDPtr particle,
ShowerInteraction inter,
tPDPair children) {
tHwSMPtr model = dynamic_ptr_cast<tHwSMPtr>(generator()->standardModel());
map<tPDPtr,VertexBasePtr>::iterator rit = radiationVertices_[inter].find(particle);
tPDPtr cc = particle->CC() ? particle->CC() : particle;
if(children==tPDPair() && rit!=radiationVertices_[inter].end()) return rit->second;
unsigned int nv(model->numberOfVertices());
long bosonID = inter==ShowerInteraction::QCD ? ParticleID::g : ParticleID::gamma;
tPDPtr gluon = getParticleData(bosonID);
// look for radiation vertices for incoming and outgoing particles
for(unsigned int iv=0;iv<nv;++iv) {
VertexBasePtr vertex = model->vertex(iv);
// look for 3 point vertices
if (children==tPDPair()){
if( !vertex->isIncoming(particle) || vertex->getNpoint() != 3 ||
!vertex->isOutgoing(particle) || !vertex->isOutgoing(gluon)) continue;
for(unsigned int list=0;list<3;++list) {
tPDVector decaylist = vertex->search(list, particle);
for( tPDVector::size_type i = 0; i < decaylist.size(); i += 3 ) {
tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]);
if( pb->id() == bosonID ) swap(pa, pb);
if( pc->id() == bosonID ) swap(pa, pc);
if( pb->id() != particle->id()) swap(pb, pc);
if( pa->id() != bosonID) continue;
if( pb != particle) continue;
if( pc != cc) continue;
radiationVertices_[inter][particle] = vertex;
return vertex;
}
}
}
// look for 4 point vertex including a gluon
else {
if( !vertex->isIncoming(particle) || vertex->getNpoint()!=4 ||
!vertex->isOutgoing(children.first) || !vertex->isOutgoing(children.second) ||
!vertex->isOutgoing(gluon)) continue;
for(unsigned int list=0;list<4;++list) {
tPDVector decaylist = vertex->search(list, particle);
for( tPDVector::size_type i = 0; i < decaylist.size(); i += 4 ) {
tPDPtr pa(decaylist[i]), pb(decaylist[i+1]), pc(decaylist[i+2]), pd(decaylist[i+3]);
// order so that a = g, b = parent
if( pb->id() == bosonID ) swap(pa, pb);
if( pc->id() == bosonID ) swap(pa, pc);
if( pd->id() == bosonID ) swap(pa, pd);
if( pc->id() == particle->id()) swap(pb, pc);
if( pd->id() == particle->id()) swap(pb, pd);
if( pa->id() != bosonID) continue;
if( pb->id() != particle->id()) continue;
if( !((abs(pd->id()) == abs(children. first->id()) &&
abs(pc->id()) == abs(children.second->id())) ||
(abs(pc->id()) == abs(children. first->id()) &&
abs(pd->id()) == abs(children.second->id()))))
continue;
return vertex;
}
}
}
}
return VertexBasePtr();
}
diff --git a/Models/General/TwoBodyDecayConstructor.h b/Models/General/TwoBodyDecayConstructor.h
--- a/Models/General/TwoBodyDecayConstructor.h
+++ b/Models/General/TwoBodyDecayConstructor.h
@@ -1,175 +1,177 @@
// -*- C++ -*-
//
// TwoBodyDecayConstructor.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_TwoBodyDecayConstructor_H
#define HERWIG_TwoBodyDecayConstructor_H
//
// This is the declaration of the TwoBodyDecayConstructor class.
//
#include "NBodyDecayConstructorBase.h"
#include "ThePEG/Helicity/Vertex/VertexBase.h"
#include "Herwig/Decay/General/GeneralTwoBodyDecayer.fh"
#include "Herwig/Shower/ShowerAlpha.h"
#include "TwoBodyDecay.h"
namespace Herwig {
using namespace ThePEG;
using Helicity::VertexBasePtr;
using Helicity::tVertexBasePtr;
/**
* The TwoBodyDecayConstructor class inherits from the dummy base class
* NBodyDecayConstructorBase and implements the necessary functions in
* order to create the 2 body decay modes for a given set of vertices
* stored in a Model class.
*
* @see \ref TwoBodyDecayConstructorInterfaces "The interfaces"
* defined for TwoBodyDecayConstructor.
* @see NBodyDecayConstructor
**/
class TwoBodyDecayConstructor: public NBodyDecayConstructorBase {
public:
/**
* The default constructor.
*/
TwoBodyDecayConstructor() : inter_(ShowerInteraction::QEDQCD) {
radiationVertices_[ShowerInteraction::QCD] = map<tPDPtr,VertexBasePtr>();
radiationVertices_[ShowerInteraction::QED] = map<tPDPtr,VertexBasePtr>();
}
/**
* Function used to determine allowed decaymodes
*@param part vector of ParticleData pointers containing particles in model
*/
virtual void DecayList(const set<PDPtr> & part);
/**
* Number of outgoing lines. Required for correct ordering.
*/
virtual unsigned int numBodies() const { return 2; }
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
TwoBodyDecayConstructor & operator=(const TwoBodyDecayConstructor &);
private:
/** @name Functions to create decayers and decaymodes. */
//@{
/**
* Function to create decays
* @param inpart Incoming particle
* @param vert The vertex to create decays for
* @param ilist Which list to search
* @param iv Row number in _theExistingDecayers member
* @return A vector a decay modes
*/
- set<TwoBodyDecay> createModes(tPDPtr inpart, VertexBasePtr vert,
- unsigned int ilist);
+ void createModes(tPDPtr inpart, VertexBasePtr vert,
+ unsigned int ilist,
+ multiset<TwoBodyDecay> & modes);
/**
* Function to create decayer for specific vertex
* @param decay decay mode for this decay
* member variable
*/
- GeneralTwoBodyDecayerPtr createDecayer(TwoBodyDecay decay);
+ GeneralTwoBodyDecayerPtr createDecayer(TwoBodyDecay decay,
+ vector<VertexBasePtr> );
/**
* Create decay mode(s) from given part and decay modes
* @param decays The vector of decay modes
* @param decayer The decayer responsible for this decay
*/
- void createDecayMode(set<TwoBodyDecay> & decays);
+ void createDecayMode(multiset<TwoBodyDecay> & decays);
//@}
/**
* Get the vertex for QED/QCD radiation
*/
VertexBasePtr radiationVertex(tPDPtr particle,ShowerInteraction inter,
tPDPair children = tPDPair ());
private:
/**
* Map of particles and the vertices which generate their QCD
* radiation
*/
map<ShowerInteraction,map<tPDPtr,VertexBasePtr> > radiationVertices_;
/**
* Default choice for the strong coupling object for hard QCD radiation
*/
ShowerAlphaPtr alphaQCD_;
/**
* Default choice for the strong coupling object for hard QED radiation
*/
ShowerAlphaPtr alphaQED_;
/**
* Which type of corrections to the decays to include
*/
ShowerInteraction inter_;
};
}
#endif /* HERWIG_TwoBodyDecayConstructor_H */
diff --git a/Models/General/TwoToTwoProcessConstructor.cc b/Models/General/TwoToTwoProcessConstructor.cc
--- a/Models/General/TwoToTwoProcessConstructor.cc
+++ b/Models/General/TwoToTwoProcessConstructor.cc
@@ -1,641 +1,644 @@
// -*- C++ -*-
//
// TwoToTwoProcessConstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TwoToTwoProcessConstructor class.
//
#include "TwoToTwoProcessConstructor.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include <sstream>
using std::stringstream;
using namespace Herwig;
TwoToTwoProcessConstructor::TwoToTwoProcessConstructor() :
Nout_(0), nv_(0), allDiagrams_(true),
processOption_(0), scaleChoice_(0), scaleFactor_(1.)
{}
IBPtr TwoToTwoProcessConstructor::clone() const {
return new_ptr(*this);
}
IBPtr TwoToTwoProcessConstructor::fullclone() const {
return new_ptr(*this);
}
void TwoToTwoProcessConstructor::doinit() {
HardProcessConstructor::doinit();
if((processOption_==2 || processOption_==4) &&
outgoing_.size()!=2)
throw InitException()
<< "Exclusive processes require exactly"
<< " two outgoing particles but " << outgoing_.size()
<< "have been inserted in TwoToTwoProcessConstructor::doinit()."
<< Exception::runerror;
if(processOption_==4 && incoming_.size()!=2)
throw InitException()
<< "Exclusive processes require exactly"
<< " two incoming particles but " << incoming_.size()
<< "have been inserted in TwoToTwoProcessConstructor::doinit()."
<< Exception::runerror;
Nout_ = outgoing_.size();
PDVector::size_type ninc = incoming_.size();
// exit if nothing to do
if(Nout_==0||ninc==0) return;
//create vector of initial-state pairs
for(PDVector::size_type i = 0; i < ninc; ++i) {
for(PDVector::size_type j = 0; j < ninc; ++j) {
tPDPair inc = make_pair(incoming_[i], incoming_[j]);
if( (inc.first->iSpin() > inc.second->iSpin()) ||
(inc.first->iSpin() == inc.second->iSpin() &&
inc.first->id() < inc.second->id()) )
swap(inc.first, inc.second);
if( !HPC_helper::duplicateIncoming(inc,incPairs_) ) {
incPairs_.push_back(inc);
}
}
}
// excluded vertices
excludedVertexSet_ =
set<VertexBasePtr>(excludedVertexVector_.begin(),
excludedVertexVector_.end());
}
void TwoToTwoProcessConstructor::persistentOutput(PersistentOStream & os) const {
os << vertices_ << incoming_ << outgoing_
<< allDiagrams_ << processOption_
<< scaleChoice_ << scaleFactor_ << excluded_ << excludedExternal_
<< excludedVertexVector_ << excludedVertexSet_;
}
void TwoToTwoProcessConstructor::persistentInput(PersistentIStream & is, int) {
is >> vertices_ >> incoming_ >> outgoing_
>> allDiagrams_ >> processOption_
>> scaleChoice_ >> scaleFactor_ >> excluded_ >> excludedExternal_
>> excludedVertexVector_ >> excludedVertexSet_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TwoToTwoProcessConstructor,HardProcessConstructor>
describeHerwigTwoToTwoProcessConstructor("Herwig::TwoToTwoProcessConstructor", "Herwig.so");
void TwoToTwoProcessConstructor::Init() {
static ClassDocumentation<TwoToTwoProcessConstructor> documentation
("TwoToTwoProcessConstructor constructs the possible diagrams for "
"a process given the external particles");
static RefVector<TwoToTwoProcessConstructor,ThePEG::ParticleData> interfaceIn
("Incoming",
"Pointers to incoming particles",
&TwoToTwoProcessConstructor::incoming_, -1, false, false, true, false);
static RefVector<TwoToTwoProcessConstructor,ThePEG::ParticleData> interfaceOut
("Outgoing",
"Pointers to incoming particles",
&TwoToTwoProcessConstructor::outgoing_, -1, false, false, true, false);
static Switch<TwoToTwoProcessConstructor,bool> interfaceIncludeAllDiagrams
("IncludeEW",
"Switch to decide which diagrams to include in ME calc.",
&TwoToTwoProcessConstructor::allDiagrams_, true, false, false);
static SwitchOption interfaceIncludeAllDiagramsNo
(interfaceIncludeAllDiagrams,
"No",
"Only include QCD diagrams",
false);
static SwitchOption interfaceIncludeAllDiagramsYes
(interfaceIncludeAllDiagrams,
"Yes",
"Include EW+QCD.",
true);
static Switch<TwoToTwoProcessConstructor,unsigned int> interfaceProcesses
("Processes",
"Whether to generate inclusive or exclusive processes",
&TwoToTwoProcessConstructor::processOption_, 0, false, false);
static SwitchOption interfaceProcessesSingleParticleInclusive
(interfaceProcesses,
"SingleParticleInclusive",
"Require at least one particle from the list of outgoing particles"
" in the hard process",
0);
static SwitchOption interfaceProcessesTwoParticleInclusive
(interfaceProcesses,
"TwoParticleInclusive",
"Require that both the particles in the hard processes are in the"
" list of outgoing particles",
1);
static SwitchOption interfaceProcessesExclusive
(interfaceProcesses,
"Exclusive",
"Require that both the particles in the hard processes are in the"
" list of outgoing particles in every hard process",
2);
static SwitchOption interfaceProcessesVeryExclusive
(interfaceProcesses,
"VeryExclusive",
"Require that both the incoming and outgoing particles in the hard processes are in the"
" list of outgoing particles in every hard process",
4);
static Switch<TwoToTwoProcessConstructor,unsigned int> interfaceScaleChoice
("ScaleChoice",
"&TwoToTwoProcessConstructor::scaleChoice_",
&TwoToTwoProcessConstructor::scaleChoice_, 0, false, false);
static SwitchOption interfaceScaleChoiceDefault
(interfaceScaleChoice,
"Default",
"Use if sHat if intermediates all colour neutral, otherwise the transverse mass",
0);
static SwitchOption interfaceScaleChoicesHat
(interfaceScaleChoice,
"sHat",
"Always use sHat",
1);
static SwitchOption interfaceScaleChoiceTransverseMass
(interfaceScaleChoice,
"TransverseMass",
"Always use the transverse mass",
2);
static SwitchOption interfaceScaleChoiceGeometicMean
(interfaceScaleChoice,
"MaxMT",
"Use the maximum of m^2+p_T^2 for the two particles",
3);
static Parameter<TwoToTwoProcessConstructor,double> interfaceScaleFactor
("ScaleFactor",
"The prefactor used in the scale calculation. The scale used is"
" that defined by scaleChoice multiplied by this prefactor",
&TwoToTwoProcessConstructor::scaleFactor_, 1.0, 0.0, 10.0,
false, false, Interface::limited);
static RefVector<TwoToTwoProcessConstructor,ThePEG::ParticleData> interfaceExcluded
("Excluded",
"Particles which are not allowed as intermediates",
&TwoToTwoProcessConstructor::excluded_, -1, false, false, true, false, false);
static RefVector<TwoToTwoProcessConstructor,ParticleData> interfaceExcludedExternal
("ExcludedExternal",
"Particles which are not allowed as outgoing particles",
&TwoToTwoProcessConstructor::excludedExternal_, -1,
false, false, true, false, false);
static RefVector<TwoToTwoProcessConstructor,VertexBase> interfaceExcludedVertices
("ExcludedVertices",
"Vertices which are not included in the 2 -> 2 scatterings",
&TwoToTwoProcessConstructor::excludedVertexVector_, -1, false, false, true, true, false);
}
void TwoToTwoProcessConstructor::constructDiagrams() {
if(incPairs_.empty() || outgoing_.empty() || !subProcess() ) return;
nv_ = model()->numberOfVertices();
//make sure vertices are initialised
for(unsigned int ix = 0; ix < nv_; ++ix ) {
VertexBasePtr vertex = model()->vertex(ix);
if(excludedVertexSet_.find(vertex) !=
excludedVertexSet_.end()) continue;
vertices_.push_back(vertex);
}
nv_ = vertices_.size();
//Create necessary diagrams
vector<tcPDPair>::size_type is;
PDVector::size_type os;
for(is = 0; is < incPairs_.size(); ++is) {
tPDPair ppi = incPairs_[is];
for(os = 0; os < Nout_; ++os) {
long fs = outgoing_[os]->id();
for(size_t iv = 0; iv < nv_; ++iv) {
tVertexBasePtr vertexA = vertices_[iv];
-
//This skips an effective vertex and the EW ones if
// we only want the strong diagrams
if( !allDiagrams_ && vertexA->orderInGs() == 0 )
continue;
if(vertexA->getNpoint() == 3) {
//scattering diagrams
createTChannels(ppi, fs, vertexA);
//resonance diagrams
if( vertexA->isIncoming(ppi.first) &&
vertexA->isIncoming(ppi.second) )
createSChannels(ppi, fs, vertexA);
}
- else
+ else {
makeFourPointDiagrams(ppi.first->id(), ppi.second->id(),
fs, vertexA);
+ }
}
}
}
// need to find all of the diagrams that relate to the same process
// first insert them into a map which uses the '<' operator
// to sort the diagrams
multiset<HPDiagram> grouped;
HPDVector::iterator dit = processes_.begin();
HPDVector::iterator dend = processes_.end();
for( ; dit != dend; ++dit) {
grouped.insert(*dit);
}
assert( processes_.size() == grouped.size() );
processes_.clear();
typedef multiset<HPDiagram>::const_iterator set_iter;
set_iter it = grouped.begin(), iend = grouped.end();
while( it != iend ) {
pair<set_iter,set_iter> range = grouped.equal_range(*it);
set_iter itb = range.first;
HPDVector process;
for( ; itb != range.second; ++itb ) {
process.push_back(*itb);
}
// if inclusive enforce the exclusivity
if(processOption_==2 || processOption_==4) {
if(!((process[0].outgoing. first==outgoing_[0]->id()&&
process[0].outgoing.second==outgoing_[1]->id())||
(process[0].outgoing. first==outgoing_[1]->id()&&
process[0].outgoing.second==outgoing_[0]->id()))) {
process.clear();
it = range.second;
continue;
}
if(processOption_==4) {
if(!((process[0].incoming. first==incoming_[0]->id()&&
process[0].incoming.second==incoming_[1]->id())||
(process[0].incoming. first==incoming_[1]->id()&&
process[0].incoming.second==incoming_[0]->id()))) {
process.clear();
it = range.second;
continue;
}
}
}
// check no zero width s-channel intermediates
for( dit=process.begin(); dit != process.end(); ++dit) {
tPDPtr out1 = getParticleData(dit->outgoing.first );
tPDPtr out2 = getParticleData(dit->outgoing.second);
if(dit->channelType == HPDiagram::sChannel &&
dit->intermediate->width()==ZERO &&
dit->intermediate->mass() > out1->mass()+ out2->mass()) {
tPDPtr in1 = getParticleData(dit->incoming.first );
tPDPtr in2 = getParticleData(dit->incoming.second);
throw Exception() << "Process with zero width resonant intermediates\n"
<< dit->intermediate->PDGName()
<< " can be on-shell in the process "
<< in1 ->PDGName() << " " << in2->PDGName() << " -> "
<< out1->PDGName() << " " << out2->PDGName()
<< " but has zero width.\nEither set the width, enable "
<< "calculation of its decays, and hence the width,\n"
<< "or disable it as a potential intermediate using\n"
<< "insert " << fullName() << ":Excluded 0 "
<< dit->intermediate->fullName() << "\n---\n"
<< Exception::runerror;
}
}
if(find(excludedExternal_.begin(),excludedExternal_.end(),
getParticleData(process[0].outgoing. first))!=excludedExternal_.end()) {
process.clear();
it = range.second;
continue;
}
if(find(excludedExternal_.begin(),excludedExternal_.end(),
getParticleData(process[0].outgoing.second))!=excludedExternal_.end()) {
process.clear();
it = range.second;
continue;
}
// finally if the process is allow assign the colour flows
for(unsigned int ix=0;ix<process.size();++ix) assignToCF(process[ix]);
// create the matrix element
createMatrixElement(process);
process.clear();
it = range.second;
}
}
void TwoToTwoProcessConstructor::
createSChannels(tcPDPair inpp, long fs, tVertexBasePtr vertex) {
//Have 2 incoming particle and a vertex, find the possible offshell
//particles
pair<long,long> inc = make_pair(inpp.first->id(), inpp.second->id());
tPDSet offshells = search(vertex, inpp.first->id(), incoming,
inpp.second->id(), incoming, outgoing);
tPDSet::const_iterator it;
for(it = offshells.begin(); it != offshells.end(); ++it) {
if(find(excluded_.begin(),excluded_.end(),*it)!=excluded_.end()) continue;
for(size_t iv = 0; iv < nv_; ++iv) {
tVertexBasePtr vertexB = vertices_[iv];
if( vertexB->getNpoint() != 3) continue;
if( !allDiagrams_ && vertexB->orderInGs() == 0 ) continue;
tPDSet final;
if( vertexB->isOutgoing(getParticleData(fs)) &&
vertexB->isIncoming(*it) )
final = search(vertexB, (*it)->id(), incoming, fs,
outgoing, outgoing);
//Now make diagrams
if(!final.empty())
makeDiagrams(inc, fs, final, *it, HPDiagram::sChannel,
make_pair(vertex, vertexB), make_pair(true,true));
}
}
}
void TwoToTwoProcessConstructor::
createTChannels(tPDPair inpp, long fs, tVertexBasePtr vertex) {
pair<long,long> inc = make_pair(inpp.first->id(), inpp.second->id());
//first try a with c
tPDSet offshells = search(vertex, inpp.first->id(), incoming, fs,
outgoing, outgoing);
tPDSet::const_iterator it;
for(it = offshells.begin(); it != offshells.end(); ++it) {
if(find(excluded_.begin(),excluded_.end(),*it)!=excluded_.end()) continue;
for(size_t iv = 0; iv < nv_; ++iv) {
tVertexBasePtr vertexB = vertices_[iv];
if( vertexB->getNpoint() != 3 ) continue;
if( !allDiagrams_ && vertexB->orderInGs() == 0 ) continue;
tPDSet final;
if( vertexB->isIncoming(inpp.second) )
final = search(vertexB, inc.second, incoming, (*it)->id(),
incoming, outgoing);
if( !final.empty() )
makeDiagrams(inc, fs, final, *it, HPDiagram::tChannel,
make_pair(vertex, vertexB), make_pair(true,true));
}
}
//now try b with c
offshells = search(vertex, inpp.second->id(), incoming, fs,
outgoing, incoming);
for(it = offshells.begin(); it != offshells.end(); ++it) {
if(find(excluded_.begin(),excluded_.end(),*it)!=excluded_.end()) continue;
for(size_t iv = 0; iv < nv_; ++iv) {
tVertexBasePtr vertexB = vertices_[iv];
if( vertexB->getNpoint() != 3 ) continue;
if( !allDiagrams_ && vertexB->orderInGs() == 0 ) continue;
tPDSet final;
if( vertexB->isIncoming(inpp.first) )
final = search(vertexB, inc.first, incoming, (*it)->id(),
outgoing, outgoing);
if( !final.empty() )
makeDiagrams(inc, fs, final, *it, HPDiagram::tChannel,
make_pair(vertexB, vertex), make_pair(true, false));
}
}
}
void TwoToTwoProcessConstructor::makeFourPointDiagrams(long parta, long partb,
long partc, VBPtr vert) {
if(processOption_>=1) {
PDVector::const_iterator loc = find(outgoing_.begin(),outgoing_.end(),
getParticleData(partc));
if(loc==outgoing_.end()) return;
}
tPDSet ext = search(vert, parta, incoming, partb,incoming, partc, outgoing);
if( ext.empty() ) return;
IDPair in(parta, partb);
for(tPDSet::const_iterator iter=ext.begin(); iter!=ext.end();
++iter) {
if(processOption_>=1) {
PDVector::const_iterator loc = find(outgoing_.begin(),outgoing_.end(),
*iter);
if(loc==outgoing_.end()) continue;
}
HPDiagram nhp(in,make_pair(partc, (*iter)->id()));
nhp.vertices = make_pair(vert, vert);
nhp.channelType = HPDiagram::fourPoint;
fixFSOrder(nhp);
+ if(!checkOrder(nhp)) continue;
if( !duplicate(nhp, processes_) ) processes_.push_back(nhp);
}
}
void
TwoToTwoProcessConstructor::makeDiagrams(IDPair in, long out1, const tPDSet & out2,
PDPtr inter, HPDiagram::Channel chan,
VBPair vertexpair, BPair cross) {
if(processOption_>=1) {
PDVector::const_iterator loc = find(outgoing_.begin(),outgoing_.end(),
getParticleData(out1));
if(loc==outgoing_.end()) return;
}
for(tPDSet::const_iterator it = out2.begin(); it != out2.end(); ++it) {
if(processOption_>=1) {
PDVector::const_iterator loc = find(outgoing_.begin(),outgoing_.end(),
*it);
if(loc==outgoing_.end()) continue;
}
HPDiagram nhp( in,make_pair(out1, (*it)->id()) );
nhp.intermediate = inter;
nhp.vertices = vertexpair;
nhp.channelType = chan;
nhp.ordered = cross;
fixFSOrder(nhp);
+ if(!checkOrder(nhp)) continue;
if( !duplicate(nhp, processes_) ) processes_.push_back(nhp);
}
}
set<tPDPtr>
TwoToTwoProcessConstructor::search(VBPtr vertex, long part1, direction d1,
long part2, direction d2, direction d3) {
if(vertex->getNpoint() != 3) return tPDSet();
if(d1 == incoming && getParticleData(part1)->CC()) part1 = -part1;
if(d2 == incoming && getParticleData(part2)->CC()) part2 = -part2;
vector<long> ext;
tPDSet third;
for(unsigned int ix = 0;ix < 3; ++ix) {
vector<long> pdlist = vertex->search(ix, part1);
ext.insert(ext.end(), pdlist.begin(), pdlist.end());
}
for(unsigned int ix = 0; ix < ext.size(); ix += 3) {
long id0 = ext.at(ix);
long id1 = ext.at(ix+1);
long id2 = ext.at(ix+2);
int pos;
if((id0 == part1 && id1 == part2) ||
(id0 == part2 && id1 == part1))
pos = ix + 2;
else if((id0 == part1 && id2 == part2) ||
(id0 == part2 && id2 == part1))
pos = ix + 1;
else if((id1 == part1 && id2 == part2) ||
(id1 == part2 && id2 == part1))
pos = ix;
else
pos = -1;
if(pos >= 0) {
tPDPtr p = getParticleData(ext[pos]);
if(d3 == incoming && p->CC()) p = p->CC();
third.insert(p);
}
}
return third;
}
set<tPDPtr>
TwoToTwoProcessConstructor::search(VBPtr vertex,
long part1, direction d1,
long part2, direction d2,
long part3, direction d3,
direction d4) {
if(vertex->getNpoint() != 4) return tPDSet();
if(d1 == incoming && getParticleData(part1)->CC()) part1 = -part1;
if(d2 == incoming && getParticleData(part2)->CC()) part2 = -part2;
if(d3 == incoming && getParticleData(part3)->CC()) part3 = -part3;
vector<long> ext;
tPDSet fourth;
for(unsigned int ix = 0;ix < 4; ++ix) {
vector<long> pdlist = vertex->search(ix, part1);
ext.insert(ext.end(), pdlist.begin(), pdlist.end());
}
for(unsigned int ix = 0;ix < ext.size(); ix += 4) {
long id0 = ext.at(ix); long id1 = ext.at(ix + 1);
long id2 = ext.at(ix + 2); long id3 = ext.at(ix + 3);
int pos;
if((id0 == part1 && id1 == part2 && id2 == part3) ||
(id0 == part1 && id1 == part3 && id2 == part2) ||
(id0 == part2 && id1 == part1 && id2 == part3) ||
(id0 == part2 && id1 == part3 && id2 == part1) ||
(id0 == part3 && id1 == part1 && id2 == part2) ||
(id0 == part3 && id1 == part2 && id2 == part1))
pos = ix + 3;
else if((id0 == part1 && id1 == part2 && id3 == part3) ||
(id0 == part1 && id1 == part3 && id3 == part2) ||
(id0 == part2 && id1 == part1 && id3 == part3) ||
(id0 == part2 && id1 == part3 && id3 == part1) ||
(id0 == part3 && id1 == part1 && id3 == part2) ||
(id0 == part3 && id1 == part2 && id3 == part1))
pos = ix + 2;
else if((id0 == part1 && id2 == part2 && id3 == part3) ||
(id0 == part1 && id2 == part3 && id3 == part2) ||
(id0 == part2 && id2 == part1 && id3 == part3) ||
(id0 == part2 && id2 == part3 && id3 == part1) ||
(id0 == part3 && id2 == part1 && id3 == part2) ||
(id0 == part3 && id2 == part2 && id3 == part1))
pos = ix + 1;
else if((id1 == part1 && id2 == part2 && id3 == part3) ||
(id1 == part1 && id2 == part3 && id3 == part2) ||
(id1 == part2 && id2 == part1 && id3 == part3) ||
(id1 == part2 && id2 == part3 && id3 == part1) ||
(id1 == part3 && id2 == part1 && id3 == part2) ||
(id1 == part3 && id2 == part2 && id3 == part1))
pos = ix;
else
pos = -1;
if(pos >= 0) {
tPDPtr p = getParticleData(ext[pos]);
if(d4 == incoming && p->CC())
p = p->CC();
fourth.insert(p);
}
}
return fourth;
}
void
TwoToTwoProcessConstructor::createMatrixElement(const HPDVector & process) const {
if ( process.empty() ) return;
// external particles
tcPDVector extpart(4);
extpart[0] = getParticleData(process[0].incoming.first);
extpart[1] = getParticleData(process[0].incoming.second);
extpart[2] = getParticleData(process[0].outgoing.first);
extpart[3] = getParticleData(process[0].outgoing.second);
// create the object
string objectname ("/Herwig/MatrixElements/");
string classname = MEClassname(extpart, objectname);
GeneralHardMEPtr matrixElement = dynamic_ptr_cast<GeneralHardMEPtr>
(generator()->preinitCreate(classname, objectname));
if( !matrixElement ) {
std::stringstream message;
message << "TwoToTwoProcessConstructor::createMatrixElement "
<< "- No matrix element object could be created for "
<< "the process "
<< extpart[0]->PDGName() << " " << extpart[0]->iSpin() << ","
<< extpart[1]->PDGName() << " " << extpart[1]->iSpin() << "->"
<< extpart[2]->PDGName() << " " << extpart[2]->iSpin() << ","
<< extpart[3]->PDGName() << " " << extpart[3]->iSpin()
<< ". Constructed class name: \"" << classname << "\"";
generator()->logWarning(TwoToTwoProcessConstructorError(message.str(),Exception::warning));
return;
}
// choice for the scale
unsigned int scale;
if(scaleChoice_==0) {
// check coloured initial and final state
bool inColour = ( extpart[0]->coloured() ||
extpart[1]->coloured());
bool outColour = ( extpart[2]->coloured() ||
extpart[3]->coloured());
if(inColour&&outColour) {
bool coloured = false;
for(unsigned int ix=0;ix<process.size();++ix) {
if(process[ix].intermediate&&
process[ix].intermediate->coloured()) {
coloured = true;
break;
}
}
scale = coloured ? 1 : 0;
}
else {
scale = 0;
}
}
else {
scale = scaleChoice_-1;
}
// set the information
matrixElement->setProcessInfo(process, colourFlow(extpart),
debug(), scale, scaleFactor_);
// insert it
generator()->preinitInterface(subProcess(), "MatrixElements",
subProcess()->MEs().size(),
"insert", matrixElement->fullName());
}
string TwoToTwoProcessConstructor::MEClassname(const vector<tcPDPtr> & extpart,
string & objname) const {
string classname("Herwig::ME");
for(vector<tcPDPtr>::size_type ix = 0; ix < extpart.size(); ++ix) {
if(ix == 2) classname += "2";
if(extpart[ix]->iSpin() == PDT::Spin0) classname += "s";
else if(extpart[ix]->iSpin() == PDT::Spin1) classname += "v";
else if(extpart[ix]->iSpin() == PDT::Spin1Half) classname += "f";
+ else if(extpart[ix]->iSpin() == PDT::Spin3Half) classname += "r";
else if(extpart[ix]->iSpin() == PDT::Spin2) classname += "t";
else {
std::stringstream message;
message << "MEClassname() : Encountered an unknown spin for "
<< extpart[ix]->PDGName() << " while constructing MatrixElement "
<< "classname " << extpart[ix]->iSpin();
generator()->logWarning(TwoToTwoProcessConstructorError(message.str(),Exception::warning));
}
}
objname += "ME" + extpart[0]->PDGName() + extpart[1]->PDGName() + "2"
+ extpart[2]->PDGName() + extpart[3]->PDGName();
return classname;
}
diff --git a/Models/LH/LHFFGVertex.cc b/Models/LH/LHFFGVertex.cc
--- a/Models/LH/LHFFGVertex.cc
+++ b/Models/LH/LHFFGVertex.cc
@@ -1,53 +1,54 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHFFGVertex class.
//
#include "LHFFGVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/StandardModel/StandardModelBase.h"
using namespace Herwig;
// Static variable needed for the type description system in ThePEG.
DescribeNoPIOClass<LHFFGVertex,FFVVertex>
describeHerwigLHFFGVertex("Herwig::LHFFGVertex", "HwLHModel.so");
void LHFFGVertex::Init() {
static ClassDocumentation<LHFFGVertex> documentation
("The LHFFGVertex class implements the coupling of the quarks"
" to the gluon in the Little Higgs model");
}
// coupling for FFG vertex
void LHFFGVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr,tcPDPtr) {
// check allowed
int iferm=abs(a->id());
assert((iferm>=1 && iferm<=6) || iferm==8);
// first the overall normalisation
if(q2!=_q2last) {
_couplast = -strongCoupling(q2);
_q2last=q2;
}
norm(_couplast);
left(1.);
right(1.);
}
void LHFFGVertex::doinit() {
// PDG codes for the particles
for(int ix=1;ix<7;++ix) {
addToList(-ix, ix, 21);
}
addToList(-8, 8, 21);
FFVVertex::doinit();
}
LHFFGVertex::LHFFGVertex() : _couplast(0.), _q2last(0.*GeV2) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TFUND);
}
diff --git a/Models/LH/LHFFHVertex.cc b/Models/LH/LHFFHVertex.cc
--- a/Models/LH/LHFFHVertex.cc
+++ b/Models/LH/LHFFHVertex.cc
@@ -1,288 +1,289 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHFFHVertex class.
//
#include "LHFFHVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
void LHFFHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(_coup,1./GeV) << _model;
}
void LHFFHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(_coup,1./GeV) >> _model;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHFFHVertex,FFSVertex>
describeHerwigLHFFHVertex("Herwig::LHFFHVertex", "HwLHModel.so");
void LHFFHVertex::Init() {
static ClassDocumentation<LHFFHVertex> documentation
("The LHFFHVertex class implements the interaction of the fermions"
" and the Higgs bosons in the Little Higgs model");
}
LHFFHVertex::LHFFHVertex()
: _q2last(0.*GeV2) {
orderInGem(1);
orderInGs(0);
_masslast[0] = 0.*GeV;
_masslast[1] = 0.*GeV;
_idlast[0] = 0;
_idlast[1] = 0;
+ colourStructure(ColourStructure::DELTA);
}
void LHFFHVertex::doinit() {
// SM like higgs
for (int ix=1;ix<=6;++ix) {
addToList( -ix, ix, 25);
}
addToList( -6, 8, 25);
addToList( -8, 6, 25);
addToList( -8, 8, 25);
for(int ix=11;ix<16;ix+=2) {
addToList( -ix, ix, 25);
}
// phi0
for (int ix=1;ix<=6;++ix) {
addToList( -ix, ix, 35);
}
addToList( -6, 8, 35);
addToList( -8, 6, 35);
for(int ix=11;ix<16;ix+=2) {
addToList( -ix, ix, 35);
}
// phiP
for (int ix=1;ix<=6;++ix) {
addToList( -ix, ix, 36);
}
addToList( -6, 8, 36);
addToList( -8, 6, 36);
for(int ix=11;ix<16;ix+=2) {
addToList( -ix, ix, 36);
}
// phi +/-
for(int ix=1;ix<6;ix+=2) {
addToList( -ix-1, ix, 37);
addToList( -ix , ix+1, -37);
}
addToList( -8 , 5, 37);
addToList( -5 , 8, -37);
for(int ix=11;ix<16;ix+=2) {
addToList( -ix-1, ix, 37);
addToList( -ix , ix+1, -37);
}
_model =
dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!_model) throw InitException() << "Must be using the LHModel "
<< " in LHFFPVertex::doinit()"
<< Exception::runerror;
_coup.resize(11);
Energy v = _model->vev();
double s0 = _model->sinTheta0();
double sP = _model->sinThetaP();
double sPlus = _model->sinThetaPlus();
double s02 = sqr(s0);
double vf = _model->vev()/_model->f();
double xL = sqr(_model->lambda1())/(sqr(_model->lambda1())+sqr(_model->lambda2()));
double xR = sqr(_model->lambda1())/sqrt(sqr(_model->lambda1())+sqr(_model->lambda2()));
Energy mT = getParticleData(8)->mass();
// lightest higgs couplings
// coupling of light SM fermions
_coup[0] = (1.-0.5*s02+vf*s0/sqrt(2.)-2./3.*sqr(vf))/v;
// couplings to top quark
_coup[1] = (1.-0.5*s02+vf*s0/sqrt(2.)-2./3.*sqr(vf)+sqr(vf)*xL*(1.+xL))/v;
// couplings to the T quark
_coup[2] =-xR*(1.+xL)*vf/mT;
// couplings to tT
_coup[3] = xR/mT;
_coup[4] = vf/v*(1.+xL);
// phi 0
// light particles
_coup[5] = sqrt(0.5)/v*(vf-sqrt(2.)*s0);
// mixed
_coup[6] = sqrt(0.5)/v*(vf-sqrt(2.)*s0)*_model->lambda1()/_model->lambda2();
// phi P
_coup[7] = Complex(0.,1.)*sqrt(0.5)/v*(vf-sqrt(2.)*sP);
_coup[8] = Complex(0.,1.)*sqrt(0.5)/v*(vf-sqrt(2.)*sP)*_model->lambda1()/_model->lambda2();
// phi +/-
_coup[9] = -sqrt(0.5)/v*(vf-2.*sPlus);
_coup[9] = -sqrt(0.5)/v*(vf-2.*sPlus)*_model->lambda1()/_model->lambda2();
FFSVertex::doinit();
}
void LHFFHVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b, tcPDPtr c) {
int iferm=abs(a->id());
int ianti=abs(b->id());
// left and right couplings set to one
left (1.);
right(1.);
// first the overall normalisation
if(q2!=_q2last||_idlast[0]!=iferm||_idlast[1]!=ianti) {
_q2last = q2;
_idlast[0] = iferm;
if(_idlast[0]==8) _idlast[0]=6;
assert((_idlast[0]>=1 && _idlast[0]<=6 ) ||
(_idlast[0]>=11 && _idlast[0]<=16));
if(iferm==_idlast[0])
_masslast[0] = _model->mass(q2,a);
else
_masslast[0] = _model->mass(q2,getParticleData(ParticleID::t));
_idlast[1] = ianti;
if(_idlast[1]==8) _idlast[1]=6;
assert((_idlast[1]>=1 && _idlast[1]<=6 ) ||
(_idlast[1]>=11 && _idlast[1]<=16));
if(_idlast[0]!=_idlast[1]) {
if(ianti==_idlast[1])
_masslast[1] = _model->mass(q2,a);
else
_masslast[1] = _model->mass(q2,getParticleData(ParticleID::t));
}
else {
_masslast[1] = _masslast[0];
}
}
// SM like higgs
if(c->id()==ParticleID::h0) {
if(iferm==ianti) {
if((iferm>=1 && iferm<=5 ) ||
(iferm>=11 && iferm<=16)) {
norm(-Complex(_coup[0]*_masslast[0]));
}
else if(iferm==6) {
norm(-Complex(_coup[1]*_masslast[0]));
}
else if(iferm==8) {
norm(-Complex(_coup[2]*a->mass()));
}
else assert(false);
}
else {
assert( (iferm == 6 && ianti == 8 ) ||
(ianti == 6 && iferm == 8 ));
Complex cleft,cright;
if(iferm==6) {
cleft = -_coup[3]*b->mass();
cright = -_coup[4]*_masslast[0];
}
else {
cleft = -_coup[3]*a->mass();
cright = -_coup[4]*_masslast[0];
}
if(b->id()==ParticleID::tbar || c->id()==ParticleID::tbar) {
cright = conj(cleft);
cleft = 0.;
}
left (cleft );
right(cright);
norm(1.);
}
}
else if(c->id()==ParticleID::H0) {
if(iferm==ianti) {
if((iferm>=1 && iferm<=6 ) ||
(iferm>=11 && iferm<=16)) {
norm(-Complex(_coup[5]*_masslast[0]));
}
else assert(false);
}
else {
assert( (iferm == 6 && ianti == 8 ) ||
(iferm == 8 && ianti == 6 ) );
Complex cleft = Complex(_coup[6]*_masslast[0]);
Complex cright = 0.;
if(b->id()==ParticleID::tbar || c->id()==ParticleID::tbar) {
cright = conj(cleft);
cleft = 0.;
}
left (cleft );
right(cright);
norm(1.);
}
}
else if(c->id()==ParticleID::A0) {
left(-1.);
right(1.);
if(iferm==ianti) {
if((iferm>=1 && iferm<=6 ) ||
(iferm>=11 && iferm<=16)) {
if(iferm%2==0)
norm(-Complex( _coup[7]*_masslast[0]));
else
norm(-Complex(-_coup[7]*_masslast[0]));
}
else assert(false);
}
else {
assert( (iferm == 6 && ianti == 8 ) ||
(iferm == 8 && ianti == 6 ));
Complex cleft = Complex(_coup[8]*_masslast[0]);
Complex cright = 0.;
if(b->id()==ParticleID::tbar || c->id()==ParticleID::tbar) {
cright = conj(cleft);
cleft = 0.;
}
left (cleft );
right(cright);
norm(1.);
}
}
else if(c->id()==ParticleID::Hplus) {
norm(1.);
Complex cleft(0.),cright(0.);
if(iferm%2==0) {
if(iferm==ParticleID::t) {
cleft = _masslast[0]*_coup[ 9];
}
else {
cleft = _masslast[0]*_coup[10];
cright = _masslast[1]*_coup[10];
}
}
else {
if(ianti==ParticleID::t) {
cleft = _masslast[1]*_coup[ 9];
}
else {
cleft = _masslast[1]*_coup[10];
cright = _masslast[0]*_coup[10];
}
}
left ( cleft);
right(cright);
}
else if(c->id()==ParticleID::Hminus) {
norm(1.);
Complex cleft(0.),cright(0.);
if(iferm%2==0) {
if(iferm==ParticleID::t) {
cright = _masslast[0]*_coup[ 9];
}
else {
cright = _masslast[0]*_coup[10];
cleft = _masslast[1]*_coup[10];
}
}
else {
if(ianti==ParticleID::t) {
cright = _masslast[1]*_coup[ 9];
}
else {
cright = _masslast[1]*_coup[10];
cleft = _masslast[0]*_coup[10];
}
}
left ( cleft);
right(cright);
}
}
diff --git a/Models/LH/LHFFPVertex.cc b/Models/LH/LHFFPVertex.cc
--- a/Models/LH/LHFFPVertex.cc
+++ b/Models/LH/LHFFPVertex.cc
@@ -1,156 +1,157 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHFFPVertex class.
//
#include "LHFFPVertex.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
LHFFPVertex::LHFFPVertex()
: _couplast(0.), _q2last(-1.*GeV2) {
// order in strong and em coupling
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void LHFFPVertex::persistentOutput(PersistentOStream & os) const {
os << _charge << _gl << _gr;
}
void LHFFPVertex::persistentInput(PersistentIStream & is, int) {
is >> _charge >> _gl >> _gr;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHFFPVertex,FFVVertex>
describeHerwigLHFFPVertex("Herwig::LHFFPVertex", "HwLHModel.so");
void LHFFPVertex::Init() {
static ClassDocumentation<LHFFPVertex> documentation
("The LHFFPVertex class implements the couplings of the fermions to"
" the photon and A_H in the Little Higgs model");
}
void LHFFPVertex::doinit() {
// the quarks
for(int ix=1;ix<7;++ix) {
addToList(-ix, ix, 22);
addToList(-ix, ix, 32);
}
addToList( -8, 8, 22);
addToList( -8, 8, 32);
addToList( -6, 8, 32);
addToList( -8, 6, 32);
// the leptons
for(int ix=11;ix<17;++ix) {
if(ix%2!=0) addToList(-ix, ix, 22);
addToList(-ix, ix, 32);
}
FFVVertex::doinit();
cLHModelPtr model =
dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must be using the LHModel "
<< " in LHFFPVertex::doinit()"
<< Exception::runerror;
// charges
_charge.resize(17);
for(int ix=1;ix<4;++ix) {
_charge[2*ix-1] = model->ed();
_charge[2*ix ] = model->eu();
_charge[2*ix+9 ] = model->ee();
_charge[2*ix+10] = model->enu();
}
_charge[8] = model->eu();
// couplings for the heavy photon taken from table IX
double cw = sqrt(1.-sin2ThetaW());
double xL = sqr(model->lambda1())/(sqr(model->lambda1())+sqr(model->lambda2()));
double cp2 = sqr(model->cosThetaPrime());
double yu = -0.4;
double ye = 0.6;
// prefactor after removal of -e
double pre = -0.5/cw/model->cosThetaPrime()/model->sinThetaPrime();
// down type quarks
double gvd = pre*(2.*yu+11./15.+cp2/6);
double gad = pre*(-0.2+0.5*cp2);
// up type quarks
double gvu = pre*(2.*yu+17./15.-5./6.*cp2);
double gau = pre*( 0.2-0.5*cp2);
// charged leptons
double gve = pre*(2.*ye-9./5.+1.5*cp2);
double gae = pre*(-0.2+0.5*cp2);
// neutrinos
double gvv = pre*(-0.2+0.5*cp2);
double gav = pre*( 0.2-0.5*cp2);
// light top
double gvtll = pre*(2.*yu+17./15.-5./6.*cp2-0.2*xL);
double gatll = pre*(0.2-0.5*cp2-0.2*xL);
// mixed top
double gvtlh = pre*0.2*model->lambda1()*model->lambda2()/
(sqr(model->lambda1())+sqr(model->lambda2()));
double gatlh = gvtlh;
// heavy top
double gvthh = pre*(2.*yu+14./15.-4./3.*cp2+0.2*xL);
double gathh = pre*0.2*xL;
_gl.resize(17);
_gr.resize(17);
for(unsigned int ix=1;ix<4;++ix) {
_gr[2*ix-1] = gvd+gad;
_gl[2*ix-1] = gvd-gad;
_gr[2*ix ] = gvu+gau;
_gl[2*ix ] = gvu-gau;
_gr[2*ix+9 ] = gve+gae;
_gl[2*ix+9 ] = gve-gae;
_gr[2*ix+10] = gvv+gav;
_gl[2*ix+10] = gvv-gav;
}
// light top
_gr[6] = gvtll+gatll;
_gl[6] = gvtll-gatll;
// mixed top
_gr[7] = gvtlh+gatlh;
_gl[7] = gvtlh-gatlh;
// heavy top
_gr[8] = gvthh+gathh;
_gl[8] = gvthh-gathh;
}
// coupling for FFP vertex
void LHFFPVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b, tcPDPtr c) {
int iferm=abs(a->id());
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16)||iferm==8);
// first the overall normalisation
if(q2!=_q2last) {
_couplast = -electroMagneticCoupling(q2);
_q2last=q2;
}
norm(_couplast);
// the left and right couplings
// photon
if(c->id()==ParticleID::gamma) {
left (_charge[iferm]);
right(_charge[iferm]);
}
// heavy photon
else {
assert(c->id()==32);
int ianti = abs(b->id());
if(ianti==iferm) {
left (_gl[iferm]);
right(_gr[iferm]);
}
else {
left (_gl[7]);
right(_gr[7]);
}
}
}
diff --git a/Models/LH/LHFFWVertex.cc b/Models/LH/LHFFWVertex.cc
--- a/Models/LH/LHFFWVertex.cc
+++ b/Models/LH/LHFFWVertex.cc
@@ -1,180 +1,181 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHFFWVertex class.
//
#include "LHFFWVertex.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
using namespace Herwig;
LHFFWVertex::LHFFWVertex()
: _ckm(3,vector<Complex>(3,0.0)), _couplast(0.), _q2last(0.*GeV2),
_corrL(0.),_corrH(0.),_tcorrL(0.),_tcorrH(0.),_tHcorrL(0.), _tHcorrH(0.) {
// order of vertex in couplings
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void LHFFWVertex::persistentOutput(PersistentOStream & os) const {
os << _ckm << _corrL << _corrH << _tcorrL << _tcorrH << _tHcorrL << _tHcorrH;
}
void LHFFWVertex::persistentInput(PersistentIStream & is, int) {
is >> _ckm >> _corrL >> _corrH >> _tcorrL >> _tcorrH >> _tHcorrL >> _tHcorrH;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHFFWVertex,FFVVertex>
describeHerwigLHFFWVertex("Herwig::LHFFWVertex", "HwLHModel.so");
void LHFFWVertex::Init() {
static ClassDocumentation<LHFFWVertex> documentation
("The LHFFWVertex class implements the vertices for"
" the coupling of the W and heavy W to the Standard Model "
"fermions and the heavy top quark in the Little Higgs model");
}
void LHFFWVertex::doinit() {
// particles for outgoing W-
// quarks
for(int ix=1;ix<6;ix+=2) {
for(int iy=2;iy<7;iy+=2) {
addToList(-ix, iy, -24);
addToList(-ix, iy, -34);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix, ix+1, -24);
addToList(-ix, ix+1, -34);
}
// particles for outgoing W+
// quarks
for(int ix=2;ix<7;ix+=2) {
for(int iy=1;iy<6;iy+=2) {
addToList(-ix, iy, 24);
addToList(-ix, iy, 34);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix-1, ix, 24);
addToList(-ix-1, ix, 34);
}
// couplings to new heavy quark
addToList(-5, 8, -24);
addToList(-5, 8, -34);
addToList(-8, 5, 24);
addToList(-8, 5, 34);
ThePEG::Helicity::FFVVertex::doinit();
cLHModelPtr model =
dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must be using the LHModel "
<< " in LHFFWVertex::doinit()"
<< Exception::runerror;
// cast the CKM object to the HERWIG one
ThePEG::Ptr<Herwig::StandardCKM>::transient_const_pointer
hwCKM=ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardCKM>::
transient_const_pointer>(generator()->standardModel()->CKM());
if(!hwCKM)
throw InitException() << "Must have access to the Herwig::StandardCKM object"
<< "for the CKM matrix in LHFFWVertex::doinit()"
<< Exception::runerror;
_ckm = hwCKM->getUnsquaredMatrix(model->families());
// compute the correction factors
double s2(sqr(model->sinTheta())),c2(sqr(model->cosTheta()));
double vf(model->vev()/model->f());
double xL = sqr(model->lambda1())/(sqr(model->lambda1())+sqr(model->lambda2()));
// from Table VIII with -sign to agree with our SM conventions
_corrL = 1.-0.5*sqr(vf)*c2*(c2-s2);
_corrH = -model->cosTheta()/model->sinTheta();
_tcorrL = 1.-0.5*sqr(vf)*(c2*(c2-s2)+sqr(xL));
_tcorrH = -model->cosTheta()/model->sinTheta();
_tHcorrL = -vf*xL;
_tHcorrH = vf*xL*model->cosTheta()/model->sinTheta();
}
void LHFFWVertex::setCoupling(Energy2 q2, tcPDPtr a,
tcPDPtr b, tcPDPtr c) {
// first the overall normalisation
if(q2!=_q2last) {
_couplast = -sqrt(0.5)*weakCoupling(q2);
_q2last=q2;
}
norm(_couplast);
right(0.);
// the left and right couplings
int iferm=abs(a->id());
int ianti=abs(b->id());
bool heavy(false);
if(iferm==8) {
iferm = 6;
heavy = true;
}
if(ianti==8) {
ianti = 6;
heavy = true;
}
// quarks
if(iferm>=1 && iferm <=6) {
int iu,id;
// up type first
if(iferm%2==0) {
iu = iferm/2;
id = (ianti+1)/2;
}
// down type first
else {
iu = ianti/2;
id = (iferm+1)/2;
}
assert( iu>=1 && iu<=3 && id>=1 && id<=3);
left(_ckm[iu-1][id-1]);
}
// leptons
else if(iferm>=11 && iferm <=16) {
left(1.);
}
else assert(false);
// correction factors
// light W
if(abs(c->id())==ParticleID::Wplus) {
// light quarks or leptons
if(iferm<6&&ianti<6) {
left(_corrL*left());
}
// light top quark
else if(!heavy) {
left(_tcorrL*left());
}
// heavy top quark
else {
left(_tHcorrL*left());
}
}
// heavy W
else {
// light quarks or leptons
if(iferm<6&&ianti<6) {
left(_corrH*left());
}
// light top quark
else if(!heavy) {
left(_tcorrH*left());
}
// heavy top quark
else {
left(_tHcorrH*left());
}
}
}
diff --git a/Models/LH/LHFFZVertex.cc b/Models/LH/LHFFZVertex.cc
--- a/Models/LH/LHFFZVertex.cc
+++ b/Models/LH/LHFFZVertex.cc
@@ -1,181 +1,182 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHFFZVertex class.
//
#include "LHFFZVertex.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
void LHFFZVertex::persistentOutput(PersistentOStream & os) const {
os << _gl << _gr << _glH << _grH;
}
void LHFFZVertex::persistentInput(PersistentIStream & is, int) {
is >> _gl >> _gr >> _glH >> _grH;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHFFZVertex,FFVVertex>
describeHerwigLHFFZVertex("Herwig::LHFFZVertex", "HwLHModel.so");
void LHFFZVertex::Init() {
static ClassDocumentation<LHFFZVertex> documentation
("The LHFFZVertex class implements the couplings of the Z and Z_H in"
" the Little Higgs model to the fermions, both of the Standard Model"
" and the additional heavy top.");
}
LHFFZVertex::LHFFZVertex() : _couplast(0.0), _q2last(0.*GeV2) {
// set order in the couplings
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void LHFFZVertex::doinit() {
for(int ib=23;ib<34;ib+=10) {
// the quarks
for(int ix=1;ix<7;++ix) {
addToList(-ix, ix, ib);
}
addToList( -8, 8, ib);
addToList( -6, 8, ib);
addToList( -8, 6, ib);
// the leptons
for(int ix=11;ix<17;++ix) {
addToList(-ix, ix, ib);
}
}
FFVVertex::doinit();
cLHModelPtr model = dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!model) throw InitException() << "Must be using the LHModel "
<< " in LHFFZVertex::doinit()"
<< Exception::runerror;
double sw2(sin2ThetaW());
double sw(sqrt(sw2)),cw(sqrt(1.-sw2));
double pre =-0.5/sw/cw;
double s (model->sinTheta() ),c (model->cosTheta() );
double sp(model->sinThetaPrime()),cp(model->cosThetaPrime());
double sp2(sqr(sp)),cp2(sqr(cp));
// from Eqn A35
double xW(-0.5/cw*s*c*(sqr(c)-sqr(s)));
double xB(-2.5/sw*sp*cp*(cp2-sp2));
double yu = -0.4, ye = 0.6;
double vf(model->vev()/model->f());
double xL(sqr(model->lambda1())/(sqr(model->lambda1())+sqr(model->lambda2())));
double vu = pre*( 0.5-4./3.*sw2-sqr(vf)*(+0.5*cw*xW*c/s
+sw*xB/sp/cp*(2.*yu+7./15. -cp2/6.)));
double vd = pre*(-0.5+2./3.*sw2-sqr(vf)*(-0.5*cw*xW*c/s
+sw*xB/sp/cp*(2.*yu+11./15. +cp2/6.)));
double ve = pre*(-0.5+2.* sw2-sqr(vf)*(-0.5*cw*xW*c/s
+sw*xB/sp/cp*(2.*ye-9./5. +1.5*cp2)));
double vv = pre*(+0.5 -sqr(vf)*(+0.5*cw*xW*c/s
+sw*xB/sp/cp*( ye-4./5. +0.5*cp2)));
double au = pre*(-0.5-sqr(vf)*(-0.5*cw*xW*c/s+sw*xB/sp/cp*(0.2-0.5*cp2)));
double ad = pre*( 0.5-sqr(vf)*(+0.5*cw*xW*c/s-sw*xB/sp/cp*(0.2-0.5*cp2)));
double ae = pre*( 0.5-sqr(vf)*(+0.5*cw*xW*c/s-sw*xB/sp/cp*(0.2-0.5*cp2)));
double av = pre*(-0.5-sqr(vf)*(-0.5*cw*xW*c/s+sw*xB/sp/cp*(0.2-0.5*cp2)));
double vtl = pre*( 0.5-4./3.*sw2-sqr(vf)*(-0.5*sqr(xL)+0.5*cw*xW*c/s
+sw*xB/sp/cp*(2.*yu+9./5.-1.5*cp2
+(7./15.-2.*cp2/3.)*xL)));
double atl = pre*(-0.5 -sqr(vf)*(+0.5*sqr(xL)-0.5*cw*xW*c/s
+sw*xB/sp/cp*(+0.2-0.5*cp2-0.2*xL)));
double vth = 2./3.*sw/cw;
double ath = 0.;
double vtm = 0.25*xL*vf/cw/sw;
double atm = -vtm;
_gl.resize(17);
_gr.resize(17);
for(unsigned ix=1;ix<4;++ix) {
_gl[2*ix-1] = vd - ad;
_gl[2*ix ] = vu - au;
_gl[2*ix+9 ] = ve - ae;
_gl[2*ix+10] = vv - av;
_gr[2*ix-1] = vd + ad;
_gr[2*ix ] = vu + au;
_gr[2*ix+9 ] = ve + ae;
_gr[2*ix+10] = vv + av;
}
_gl[6] = vtl - atl;
_gr[6] = vtl + atl;
_gl[7] = vtm - atm;
_gr[7] = vtm + atm;
_gl[8] = vth - ath;
_gr[8] = vth + ath;
// heavy Z
double fact = 0.25*c/s/sw;
vu = fact;
vd = -fact;
ve = -fact;
vv = fact;
au = -fact;
ad = fact;
ae = fact;
av = -fact;
vtl = fact;
atl = -fact;
vth = 0.;
ath = 0.;
vtm = -0.25*xL*vf*c/s/sw;
atm = -vtm;
_glH.resize(17);
_grH.resize(17);
for(unsigned ix=1;ix<4;++ix) {
_glH[2*ix-1] = vd - ad;
_glH[2*ix ] = vu - au;
_glH[2*ix+9 ] = ve - ae;
_glH[2*ix+10] = vv - av;
_grH[2*ix-1] = vd + ad;
_grH[2*ix ] = vu + au;
_grH[2*ix+9 ] = ve + ae;
_grH[2*ix+10] = vv + av;
}
_glH[6] = vtl - atl;
_grH[6] = vtl + atl;
_glH[7] = vtm - atm;
_grH[7] = vtm + atm;
_glH[8] = vth - ath;
_grH[8] = vth + ath;
}
void LHFFZVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,tcPDPtr c) {
// first the overall normalisation
if(q2!=_q2last) {
_couplast = electroMagneticCoupling(q2);
_q2last=q2;
}
norm(_couplast);
// the left and right couplings
int iferm = abs(a->id());
int ianti = abs(b->id());
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16)|| iferm == 8);
// Z0
if(c->id()==ParticleID::Z0) {
if(ianti==iferm) {
left (_gl[iferm]);
right(_gr[iferm]);
}
else {
left (_gl[7]);
right(_gr[7]);
}
}
else {
if(ianti==iferm) {
left (_glH[iferm]);
right(_grH[iferm]);
}
else {
left (_glH[7]);
right(_grH[7]);
}
}
}
diff --git a/Models/LH/LHWHHVertex.cc b/Models/LH/LHWHHVertex.cc
--- a/Models/LH/LHWHHVertex.cc
+++ b/Models/LH/LHWHHVertex.cc
@@ -1,286 +1,287 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHWHHVertex class.
//
#include "LHWHHVertex.h"
#include "LHModel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
LHWHHVertex::LHWHHVertex() :
couplast_(0.), q2last_(ZERO), coup_(24) {
orderInGs(0);
orderInGem(1);
// neutral
addToList( 22, 37,-37);
addToList( 22, 38,-38);
addToList( 32, 37,-37);
addToList( 32, 38,-38);
addToList( 23, 37,-37);
addToList( 23, 38,-38);
addToList( 33, 37,-37);
addToList( 33, 38,-38);
addToList( 32, 25, 36);
addToList( 32, 35, 36);
addToList( 23, 25, 36);
addToList( 23, 35, 36);
addToList( 33, 25, 36);
addToList( 33, 35, 36);
// W+
addToList( 24, 25,-37);
addToList( 24, 35,-37);
addToList( 24, 36,-37);
addToList( 24, 37,-38);
addToList( 34, 25,-37);
addToList( 34, 35,-37);
addToList( 34, 36,-37);
addToList( 34, 37,-38);
// W-
addToList(-24, 25, 37);
addToList(-24, 35, 37);
addToList(-24, 36, 37);
addToList(-24,-37, 38);
addToList(-34, 25, 37);
addToList(-34, 35, 37);
addToList(-34, 36, 37);
addToList(-34,-37, 38);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr LHWHHVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHWHHVertex::fullclone() const {
return new_ptr(*this);
}
void LHWHHVertex::persistentOutput(PersistentOStream & os) const {
os << coup_;
}
void LHWHHVertex::persistentInput(PersistentIStream & is, int) {
is >> coup_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHWHHVertex,VSSVertex>
describeHerwigLHWHHVertex("Herwig::LHWHHVertex", "HwLHModel.so");
void LHWHHVertex::Init() {
static ClassDocumentation<LHWHHVertex> documentation
("The LHWHHVertex class implements the coupling of a pair of Higgs"
" bosons to an electroweak gauge boson in the Little Higgs model.");
}
void LHWHHVertex::doinit() {
VSSVertex::doinit();
// model
cLHModelPtr model =
dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must be using the LHModel "
<< " in LHWHHVertex::doinit()"
<< Exception::runerror;
double sw2(sin2ThetaW());
double sw(sqrt(sw2)),cw(sqrt(1.-sw2));
double s (model->sinTheta() ),c (model->cosTheta() );
double sp(model->sinThetaPrime()),cp(model->cosThetaPrime());
double s0 (model->sinTheta0());
double sP (model->sinThetaP());
double sPlus(model->sinThetaPlus());
coup_[ 0] = 0.5/sw*(sqrt(2.)*s0-sPlus);
coup_[ 1] = sqrt(0.5)/sw;
coup_[ 2] = Complex(0.,1.)/sw*sqrt(0.5);
coup_[ 3] = 1./sw;
coup_[ 4] = 0.;
coup_[ 5] = 0.;
coup_[ 6] = 1.;
coup_[ 7] = 2.;
coup_[ 8] = Complex(0.,0.5)/cw/sw*(sP-2.*s0);
coup_[ 9] =-Complex(0.,1.)/cw/sw;
coup_[10] =-sw/cw;
coup_[11] = (1.-2.*sw2)/cw/sw;
coup_[12] =-0.25/sw*(sqr(c)-sqr(s))/s/c*(sqrt(2.)*s0-sPlus);
coup_[13] =-sqrt(0.5)/sw*0.5*(sqr(c)-sqr(s))/s/c;
coup_[14] =-Complex(0.,1.)*sqrt(0.5)*0.5*(sqr(c)-sqr(s))/s/c;
coup_[15] =-0.5*(sqr(c)-sqr(s))/s/c/sw;
coup_[16] =-Complex(0.,0.5)/cw*0.5*(sqr(cp)-sqr(sp))/sp/cp*(sP-2.*s0);
coup_[17] = Complex(0.,1.)/cw*0.5*(sqr(cp)-sqr(sp))/sp/cp;
coup_[18] =-0.5*(sqr(cp)-sqr(sp))/sp/cp/cw;
coup_[19] =-0.5*(sqr(cp)-sqr(sp))/sp/cp/cw;
coup_[20] =-Complex(0.,0.5)/sw*0.5*(sqr(c)-sqr(s))/s/c*(sP-2.*s0);
coup_[21] = Complex(0.,1.)/sw*0.5*(sqr(c)-sqr(s))/s/c;
coup_[22] = 0.;
coup_[23] =-0.5/sw*(sqr(c)-sqr(s))/s/c;
}
void LHWHHVertex::setCoupling(Energy2 q2, tcPDPtr particle1,
tcPDPtr particle2, tcPDPtr particle3) {
if( q2 != q2last_ || couplast_==0.) {
q2last_ = q2;
couplast_ = -electroMagneticCoupling(q2);
}
int ibos = particle1->id();
int isc1 = particle2->id();
int isc2 = particle3->id();
if(ibos==ParticleID::gamma) {
if(isc1==37)
norm(coup_[6]*couplast_);
else if(isc1==38)
norm(coup_[7]*couplast_);
else if(isc1==-37)
norm(-coup_[6]*couplast_);
else if(isc1==-38)
norm(-coup_[7]*couplast_);
else
assert(false);
}
else if(ibos==32) {
if(isc1==37)
norm(coup_[18]*couplast_);
else if(isc1==38)
norm(coup_[19]*couplast_);
else if(isc1==-37)
norm(-coup_[18]*couplast_);
else if(isc1==-38)
norm(-coup_[19]*couplast_);
else if(isc1==25)
norm(coup_[16]*couplast_);
else if(isc1==35)
norm(coup_[17]*couplast_);
else if(isc2==25)
norm(-coup_[16]*couplast_);
else if(isc2==35)
norm(-coup_[17]*couplast_);
else
assert(false);
}
else if(ibos==ParticleID::Z0) {
if(isc1==37)
norm(coup_[10]*couplast_);
else if(isc1==38)
norm(coup_[11]*couplast_);
else if(isc1==-37)
norm(-coup_[10]*couplast_);
else if(isc1==-38)
norm(-coup_[11]*couplast_);
else if(isc1==25)
norm(coup_[8]*couplast_);
else if(isc1==35)
norm(coup_[9]*couplast_);
else if(isc2==25)
norm(-coup_[8]*couplast_);
else if(isc2==35)
norm(-coup_[9]*couplast_);
else
assert(false);
}
else if(ibos==33) {
if(isc1==37)
norm(coup_[22]*couplast_);
else if(isc1==38)
norm(coup_[23]*couplast_);
else if(isc1==-37)
norm(-coup_[22]*couplast_);
else if(isc1==-38)
norm(-coup_[23]*couplast_);
else if(isc1==25)
norm(coup_[20]*couplast_);
else if(isc1==35)
norm(coup_[21]*couplast_);
else if(isc2==25)
norm(-coup_[20]*couplast_);
else if(isc2==35)
norm(-coup_[21]*couplast_);
else
assert(false);
}
else if(ibos==ParticleID::Wplus) {
if(isc1==25)
norm(coup_[0]*couplast_);
else if(isc1==35)
norm(coup_[1]*couplast_);
else if(isc1==36)
norm(coup_[2]*couplast_);
else if(isc1==37)
norm(coup_[3]*couplast_);
else if(isc2==25)
norm(-coup_[0]*couplast_);
else if(isc2==35)
norm(-coup_[1]*couplast_);
else if(isc2==36)
norm(-coup_[2]*couplast_);
else if(isc2==37)
norm(-coup_[3]*couplast_);
else
assert(false);
}
else if(ibos==34) {
if(isc1==25)
norm(coup_[12]*couplast_);
else if(isc1==35)
norm(coup_[13]*couplast_);
else if(isc1==36)
norm(coup_[14]*couplast_);
else if(isc1==37)
norm(coup_[15]*couplast_);
else if(isc2==25)
norm(-coup_[12]*couplast_);
else if(isc2==35)
norm(-coup_[13]*couplast_);
else if(isc2==36)
norm(-coup_[14]*couplast_);
else if(isc2==37)
norm(-coup_[15]*couplast_);
else
assert(false);
}
else if(ibos==ParticleID::Wminus) {
if(isc1==25)
norm(conj(coup_[0])*couplast_);
else if(isc1==35)
norm(conj(coup_[1])*couplast_);
else if(isc1==36)
norm(conj(coup_[2])*couplast_);
else if(isc1==37)
norm(conj(coup_[3])*couplast_);
else if(isc2==25)
norm(-conj(coup_[0])*couplast_);
else if(isc2==35)
norm(-conj(coup_[1])*couplast_);
else if(isc2==36)
norm(-conj(coup_[2])*couplast_);
else if(isc2==37)
norm(-conj(coup_[3])*couplast_);
else
assert(false);
}
else if(ibos==-34) {
if(isc1==25)
norm(conj(coup_[12])*couplast_);
else if(isc1==35)
norm(conj(coup_[13])*couplast_);
else if(isc1==36)
norm(conj(coup_[14])*couplast_);
else if(isc1==-37)
norm(conj(coup_[15])*couplast_);
else if(isc2==25)
norm(-conj(coup_[12])*couplast_);
else if(isc2==35)
norm(-conj(coup_[13])*couplast_);
else if(isc2==36)
norm(-conj(coup_[14])*couplast_);
else if(isc2==-37)
norm(-conj(coup_[15])*couplast_);
else
assert(false);
}
}
diff --git a/Models/LH/LHWWHHVertex.cc b/Models/LH/LHWWHHVertex.cc
--- a/Models/LH/LHWWHHVertex.cc
+++ b/Models/LH/LHWWHHVertex.cc
@@ -1,496 +1,497 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHWWHHVertex class.
//
#include "LHWWHHVertex.h"
#include "LHModel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
LHWWHHVertex::LHWWHHVertex() :
couplast_(0.), q2last_(ZERO), coup_(107) {
orderInGs(0);
orderInGem(2);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr LHWWHHVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHWWHHVertex::fullclone() const {
return new_ptr(*this);
}
void LHWWHHVertex::persistentOutput(PersistentOStream & os) const {
os << coup_;
}
void LHWWHHVertex::persistentInput(PersistentIStream & is, int) {
is >> coup_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHWWHHVertex,VVSSVertex>
describeHerwigLHWWHHVertex("Herwig::LHWWHHVertex", "HwLHModel.so");
void LHWWHHVertex::Init() {
static ClassDocumentation<LHWWHHVertex> documentation
("The LHWWHHVertex class implements the couplings of a pair"
" of electroweak gauge bosons and a pair of Higgs bosons in"
" the Little Higgs model.");
}
void LHWWHHVertex::doinit() {
// VVHH
addToList( 24, -24, 25, 25);
addToList( 23, 23, 25, 25);
addToList( 24, -34, 25, 25);
addToList( 34, -24, 25, 25);
addToList( 23, 32, 25, 25);
addToList( 34, -34, 25, 25);
addToList( 33, 33, 25, 25);
addToList( 32, 32, 25, 25);
addToList( 23, 33, 25, 25);
addToList( 32, 33, 25, 25);
// VVH Phi_0
addToList( 24, -24, 25, 35);
addToList( 23, 23, 25, 35);
addToList( 24, -34, 25, 35);
addToList( 34, -24, 25, 35);
addToList( 23, 32, 25, 35);
addToList( 34, -34, 25, 35);
addToList( 33, 33, 25, 35);
addToList( 32, 32, 25, 35);
addToList( 23, 33, 25, 35);
addToList( 32, 33, 25, 35);
// VV Phi_0 Phi_0
addToList( 24, -24, 35, 35);
addToList( 23, 23, 35, 35);
addToList( 24, -34, 35, 35);
addToList( 34, -24, 35, 35);
addToList( 23, 32, 35, 35);
addToList( 34, -34, 35, 35);
addToList( 33, 33, 35, 35);
addToList( 32, 32, 35, 35);
addToList( 23, 33, 35, 35);
addToList( 32, 33, 35, 35);
// VV Phi_P Phi_P
addToList( 24, -24, 36, 36);
addToList( 23, 23, 36, 36);
addToList( 24, -34, 36, 36);
addToList( 34, -24, 36, 36);
addToList( 23, 32, 36, 36);
addToList( 34, -34, 36, 36);
addToList( 33, 33, 36, 36);
addToList( 32, 32, 36, 36);
addToList( 23, 33, 36, 36);
addToList( 32, 33, 36, 36);
// VV Phi+ Phi-
addToList( 24, -24, 37, -37);
addToList( 23, 23, 37, -37);
addToList( 22, 22, 37, -37);
addToList( 22, 23, 37, -37);
addToList( 24, -34, 37, -37);
addToList( 34, -24, 37, -37);
addToList( 34, -34, 37, -37);
addToList( 33, 33, 37, -37);
addToList( 32, 32, 37, -37);
addToList( 32, 33, 37, -37);
addToList( 22, 32, 37, -37);
addToList( 23, 33, 37, -37);
addToList( 23, 32, 37, -37);
// VV Phi++ Phi--
addToList( 24, -24, 38, -38);
addToList( 23, 23, 38, -38);
addToList( 22, 22, 38, -38);
addToList( 22, 23, 38, -38);
addToList( 24, -34, 38, -38);
addToList( 34, -24, 38, -38);
addToList( 34, -34, 38, -38);
addToList( 33, 33, 38, -38);
addToList( 32, 32, 38, -38);
addToList( 32, 33, 38, -38);
addToList( 22, 32, 38, -38);
addToList( 23, 33, 38, -38);
addToList( 23, 32, 38, -38);
// VV H phi- + cc
addToList( 24, 22, 25, -37);
addToList( 24, 23, 25, -37);
addToList( 24, 32, 25, -37);
addToList( 24, 33, 25, -37);
addToList( 34, 22, 25, -37);
addToList( 34, 23, 25, -37);
addToList( 34, 32, 25, -37);
addToList( 34, 33, 25, -37);
addToList( -24, 22, 25, 37);
addToList( -24, 23, 25, 37);
addToList( -24, 32, 25, 37);
addToList( -24, 33, 25, 37);
addToList( -34, 22, 25, 37);
addToList( -34, 23, 25, 37);
addToList( -34, 32, 25, 37);
addToList( -34, 33, 25, 37);
// VV phi0 phi- + cc
addToList( 24, 22, 35, -37);
addToList( 24, 23, 35, -37);
addToList( 24, 32, 35, -37);
addToList( 24, 33, 35, -37);
addToList( 34, 22, 35, -37);
addToList( 34, 23, 35, -37);
addToList( 34, 32, 35, -37);
addToList( 34, 33, 35, -37);
addToList( -24, 22, 35, 37);
addToList( -24, 23, 35, 37);
addToList( -24, 32, 35, 37);
addToList( -24, 33, 35, 37);
addToList( -34, 22, 35, 37);
addToList( -34, 23, 35, 37);
addToList( -34, 32, 35, 37);
addToList( -34, 33, 35, 37);
// VV phiP phi- + cc
addToList( 24, 22, 36, -37);
addToList( 24, 23, 36, -37);
addToList( 24, 32, 36, -37);
addToList( 24, 33, 36, -37);
addToList( 34, 22, 36, -37);
addToList( 34, 23, 36, -37);
addToList( 34, 32, 36, -37);
addToList( 34, 33, 36, -37);
addToList( -24, 22, 36, 37);
addToList( -24, 23, 36, 37);
addToList( -24, 32, 36, 37);
addToList( -24, 33, 36, 37);
addToList( -34, 22, 36, 37);
addToList( -34, 23, 36, 37);
addToList( -34, 32, 36, 37);
addToList( -34, 33, 36, 37);
// VV phi+ phi -- + cc
addToList( 24, 22, 37, -38);
addToList( 24, 23, 37, -38);
addToList( 24, 32, 37, -38);
addToList( 24, 33, 37, -38);
addToList( 34, 22, 37, -38);
addToList( 34, 23, 37, -38);
addToList( 34, 32, 37, -38);
addToList( 34, 33, 37, -38);
addToList( -24, 22, -37, 38);
addToList( -24, 23, -37, 38);
addToList( -24, 32, -37, 38);
addToList( -24, 33, -37, 38);
addToList( -34, 22, -37, 38);
addToList( -34, 23, -37, 38);
addToList( -34, 32, -37, 38);
addToList( -34, 33, -37, 38);
// VV H phi-- + cc
addToList( 24, 24, 25, -38);
addToList( -24, -24, 25, 38);
addToList( 24, 34, 25, -38);
addToList( -24, -34, 25, 38);
addToList( 34, 34, 25, -38);
addToList( -34, -34, 25, 38);
// VV phi0 phi-- + cc
addToList( 24, 24, 35, -38);
addToList( -24, -24, 35, 38);
addToList( 24, 34, 35, -38);
addToList( -24, -34, 35, 38);
addToList( 34, 34, 35, -38);
addToList( -34, -34, 35, 38);
// VV phiP phi-- + cc
addToList( 24, 24, 36, -38);
addToList( -24, -24, 36, 38);
addToList( 24, 34, 36, -38);
addToList( -24, -34, 36, 38);
addToList( 34, 34, 36, -38);
addToList( -34, -34, 36, 38);
VVSSVertex::doinit();
// model
cLHModelPtr model =
dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must be using the LHModel "
<< " in LHWWWWVertex::doinit()"
<< Exception::runerror;
double sw2(sin2ThetaW()),cw2(1.-sw2);
double sw(sqrt(sw2)),cw(sqrt(cw2));
double s (model->sinTheta() ),c (model->cosTheta() );
double sp(model->sinThetaPrime()),cp(model->cosThetaPrime());
double s0 (model->sinTheta0());
double sPlus(model->sinThetaPlus());
// VV HH
coup_[ 0] = 0.5/sw2;
coup_[ 1] = 0.5/sw2/cw2;
coup_[ 2] = 0.;
coup_[ 3] =-0.25/sw2*(sqr(c)-sqr(s))/c/s;
coup_[ 4] =-0.25/sw/cw2*(sqr(cp)-sqr(sp))/cp/sp;
coup_[ 5] =-0.5/sw2;
coup_[ 6] =-0.5/sw2;
coup_[ 7] =-0.5/cw2;
coup_[ 8] =-0.25/sw2/cw*(sqr(c)-sqr(s))/c/s;
coup_[ 9] =-0.25/sw/cw*(sqr(c*sp)+sqr(s*cp))/c/s/sp/cp;
// VV H Phi_0
coup_[ 10] = 0.5*s0/sw2;
coup_[ 11] = 1.5*s0/sw2/cw2;
coup_[ 12] = 0.;
coup_[ 13] =-0.25/sw2*(sqr(c)-sqr(s))/c/s*s0;
coup_[ 14] =-0.75/sw/cw2*(sqr(cp)-sqr(sp))/cp/sp*s0;
coup_[ 15] = -0.5/sw2*s0;
coup_[ 16] = 0.5/sw2*(1.+sqr(sqr(c)-sqr(s))/sqr(s*c))*s0;
coup_[ 17] = 0.5/cw2*(1.+sqr(sqr(cp)-sqr(sp))/sqr(sp*cp))*s0;
coup_[ 18] =-0.75/cw/sw2*(sqr(c)-sqr(s))/c/s*s0;
coup_[ 19] = 0.25/sw/cw/c/s/sp/cp*((sqr(c*sp)+sqr(s*cp))
+2.*(sqr(c)-sqr(s))*(sqr(cp)-sqr(sp)))*s0;
// VV phi0 phi0
coup_[ 20] = 1./sw2;
coup_[ 21] = 2./cw2/sw2;
coup_[ 22] = 0.;
coup_[ 23] =-0.5/sw2*(sqr(c)-sqr(s))/c/s;
coup_[ 24] =-1./sw/cw2*(sqr(cp)-sqr(sp))/cp/sp;
coup_[ 25] =-1./sw2;
coup_[ 26] = 0.5/sw2*sqr(sqr(c)-sqr(s))/sqr(s*c);
coup_[ 26] = 0.5/cw2*sqr(sqr(cp)-sqr(sp))/sqr(sp*cp);
coup_[ 28] =-1./cw/sw2*(sqr(c)-sqr(s))/c/s;
coup_[ 29] = 0.5/cw/sw*(sqr(c)-sqr(s))*(sqr(cp)-sqr(sp))/s/c/sp/cp;
// VV phi_P phi_P
coup_[ 30] = 1./sw2;
coup_[ 31] = 2./sw2/cw2;
coup_[ 32] = 0.;
coup_[ 33] =-0.5/sw2*(sqr(c)-sqr(s))/c/s;
coup_[ 34] =-1./sw/cw2*(sqr(cp)-sqr(sp))/cp/sp;
coup_[ 35] =-1./sw2;
coup_[ 36] = 0.5/sw2*sqr(sqr(c)-sqr(s))/sqr(s*c);
coup_[ 37] = 0.5/cw2*sqr(sqr(cp)-sqr(sp))/sqr(sp*cp);
coup_[ 38] =-1./cw/sw2*(sqr(c)-sqr(s))/s/c;
coup_[ 39] = 0.5/cw/sw*(sqr(c)-sqr(s))*(sqr(cp)-sqr(sp))/s/c/sp/cp;
// VV phi+ phi-
coup_[ 40] = 2./sw2;
coup_[ 41] = 2.*sw2/cw2;
coup_[ 42] = 2.;
coup_[ 43] =-2.*sw/cw;
coup_[ 44] =-1./sw2*(sqr(c)-sqr(s))/s/c;
coup_[ 45] = 0.;
coup_[ 46] = 0.5/sw2*sqr(sqr(c)-sqr(s))/sqr(s*c);
coup_[ 47] =-0.5/sw2/sqr(s*c);
coup_[ 48] = 0.5/cw2*sqr(sqr(cp)-sqr(sp))/sqr(sp*cp);
coup_[ 49] = 0.;
coup_[ 50] =-1./cw*(sqr(cp)-sqr(sp))/sp/cp;
coup_[ 51] = 0.;
coup_[ 52] = sw/cw2*(sqr(cp)-sqr(sp))/sp/cp;
// VV phi++ phi--
coup_[ 53] = 1./sw2;
coup_[ 54] = 2./cw2/sw2*sqr(1.-2.*sw2);
coup_[ 55] = 8.;
coup_[ 56] = 4./sw/cw*(1.-2.*sw2);
coup_[ 57] =-0.5/sw2*(sqr(c)-sqr(s))/s/c;
coup_[ 58] = 2./sw*(sqr(c)-sqr(s))/s/c;
coup_[ 59] =-1./sw2;
coup_[ 60] = 0.5/sw2*sqr(sqr(c)-sqr(s))/sqr(s*c);
coup_[ 61] = 0.5/cw2*sqr(sqr(cp)-sqr(sp))/sqr(sp*cp);
coup_[ 62] =-0.5/cw/sw*(sqr(c)-sqr(s))*(sqr(cp)-sqr(sp))/s/c/sp/cp;
coup_[ 63] =-2./cw*(sqr(cp)-sqr(sp))/cp/sp;
coup_[ 64] = 1./sw2/cw*(sqr(c )-sqr(s ))/s /c *(1.-2.*sw2);
coup_[ 65] =-1./cw2/sw*(sqr(cp)-sqr(sp))/sp/cp*(1.-2.*sw2);
// VV h phi-
coup_[ 66] =-0.5/sw*(sPlus-sqrt(2.)*s0);
coup_[ 67] = 0.5/cw/sw2*(sPlus*sw2-sqrt(2.)*s0*(1.+sw2));
coup_[ 68] =-0.25/sw/cw*(sqr(cp)-sqr(sp))/cp/sp*(sPlus-2.*sqrt(2.)*s0);
coup_[ 69] = 0.25/sw2*(sqr(c)-sqr(s))/s/c*s0;
coup_[ 70] = 0.25/sw*(sqr(c)-sqr(s))/s/c*(sPlus-sqrt(2.)*s0);
coup_[ 71] =-0.25/sw2/cw*(sqr(c)-sqr(s))/s/c*(sPlus*sw2-sqrt(2.)*s0*(1.+sw2));
coup_[ 72] =-0.25/sw/cw/s/c/sp/cp*(sPlus*(sqr(c*sp)+sqr(s*cp))
+sqrt(2.)*(sqr(c)-sqr(s))*(sqr(cp)-sqr(sp)));
coup_[ 73] =-0.25/sw2*s0*(pow(c,4)+pow(s,4))/sqr(s*c);
// VV phi0 phi-
coup_[ 74] =-sqrt(0.5)/sw;
coup_[ 75] =-sqrt(0.5)/sw2/cw*(1.+sw2);
coup_[ 76] = sqrt(0.5)/sw/cw*(sqr(cp)-sqr(sp))/sp/cp;
coup_[ 77] = 0.5*sqrt(0.5)/sw2*(sqr(c)-sqr(s))/c/s;
coup_[ 78] = 0.5*sqrt(0.5)/sw*(sqr(c)-sqr(s))/c/s;
coup_[ 79] = 0.5*sqrt(0.5)/sw2/cw*(sqr(c)-sqr(s))/c/s*(1.+sw2);
coup_[ 80] =-0.5*sqrt(0.5)/sw/cw*(sqr(cp)-sqr(sp))/cp/sp*(sqr(c)-sqr(s))/c/s;
coup_[ 81] =-0.5*sqrt(0.5)/sw2*(pow(c,4)+pow(s,4))/sqr(s*c);
// VV phi+ phi--
coup_[ 82] = 3./sw;
coup_[ 83] = (1.-3.*sw2)/cw/sw2;
coup_[ 84] = 1./sw/cw*(sqr(cp)-sqr(sp))/cp/sp;
coup_[ 85] = Complex(0.,1.)*0.5*sqrt(0.5)/sw2*(sqr(c)-sqr(s))/s/c;
coup_[ 86] =-3./sw*(sqr(c)-sqr(s))/s/c;
coup_[ 87] =-0.5/sw2/cw*(sqr(c)-sqr(s))/s/c*(1.-3.*sw2);
coup_[ 88] =-0.5/sw/cw*(sqr(c)-sqr(s))/s/c*(sqr(cp)-sqr(sp))/cp/sp;
coup_[ 89] =-Complex(0.,1.)*0.5*sqrt(0.5)/sw2*(pow(c,4)+pow(s,4))/sqr(s*c);
// VV phip phi-
coup_[ 90] =-Complex(0.,1.)/sw*sqrt(0.5);
coup_[ 91] =-Complex(0.,1.)/sw2/cw*(1.+sw2);
coup_[ 92] = Complex(0.,1.)/sw/cw*sqrt(0.5)*(sqr(cp)-sqr(sp))/cp/sp;
coup_[ 93] = Complex(0.,1.)/sw2*sqrt(0.5)*0.5*(sqr(c)-sqr(s))/s/c;
coup_[ 94] =-Complex(0.,1.)*sqrt(0.5)*0.5/sw*(sqr(c)-sqr(s))/s/c;
coup_[ 95] = Complex(0.,1.)*sqrt(0.5)*0.5/sw2/cw*(sqr(c)-sqr(s))/s/c*(1.+sw2);
coup_[ 96] =-Complex(0.,1.)*sqrt(0.5)*0.5/sw/cw*(sqr(c )-sqr(s ))/s/c*
(sqr(cp)-sqr(sp))/cp/sp;
coup_[ 97] =-Complex(0.,1.)/sw2*sqrt(0.5)*0.5*(pow(c,4)+pow(s,4))/sqr(s*c);
// VV H phi--
coup_[ 98] = sqrt(2.)/sw2*s0;
coup_[ 99] =-sqrt(2.)/sw2*0.5*(sqr(c)-sqr(s))/s/c*s0;
coup_[100] = sqrt(2.)/sw2*0.5*(pow(c,4)+pow(s,4))/sqr(s*c)*s0;
// VV phi0 phi--
coup_[101] = sqrt(2.)/sw2;
coup_[102] =-sqrt(2.)/sw2*0.5*(sqr(c)-sqr(s))/s/c;
coup_[103] = sqrt(2.)/sw2*0.5*(pow(c,4)+pow(s,4))/sqr(s*c);
// VV phip phi--
coup_[104] = Complex(0.,1.)*sqrt(2.)/sw2;
coup_[105] =-Complex(0.,1.)*sqrt(2.)/sw2*0.5*(sqr(c)-sqr(s))/s/c;
coup_[106] = Complex(0.,1.)*sqrt(2.)/sw2*0.5*(pow(c,4)+pow(s,4))/sqr(s*c);
}
void LHWWHHVertex::setCoupling(Energy2 q2,
tcPDPtr part1,tcPDPtr part2,
tcPDPtr part3,tcPDPtr part4) {
if( q2 != q2last_ || couplast_==0.) {
q2last_ = q2;
couplast_ = sqr(electroMagneticCoupling(q2));
}
int ibos1 = part1->id();
int ibos2 = part2->id();
int isca1 = part3->id();
int isca2 = part4->id();
if( isca1 == isca2 ||
(isca1==25&&isca2==35) || (isca1==35&&isca2==25)) {
unsigned int ioff = 0;
if (isca1!=isca2) ioff = 10;
else if(isca1==35 ) ioff = 20;
else if(isca1==36 ) ioff = 30;
if(ibos1==23&&ibos2==23)
norm(coup_[1+ioff]*couplast_);
else if(ibos1==33&&ibos2==33)
norm(coup_[6+ioff]*couplast_);
else if(ibos1==33&&ibos2==33)
norm(coup_[7+ioff]*couplast_);
else if(abs(ibos1)==24&&abs(ibos2)==24)
norm(coup_[0+ioff]*couplast_);
else if(abs(ibos1)==34&&abs(ibos2)==34)
norm(coup_[5+ioff]*couplast_);
else if(( abs(ibos1) == 24 && abs(ibos2) == 34) ||
( abs(ibos1) == 34 && abs(ibos2) == 24))
norm(coup_[3+ioff]*couplast_);
else if(( ibos1 == 23 && ibos2 == 32) ||
( ibos1 == 32 && ibos2 == 23))
norm(coup_[4+ioff]*couplast_);
else if(( ibos1 == 23 && ibos2 == 33) ||
( ibos1 == 33 && ibos2 == 23))
norm(coup_[8+ioff]*couplast_);
else if(( ibos1 == 32 && ibos2 == 33) ||
( ibos1 == 33 && ibos2 == 32))
norm(coup_[9+ioff]*couplast_);
else
assert(false);
}
else if(isca1==-isca2) {
unsigned int ioff = abs(isca1) == 37 ? 40 : 53;
if(abs(ibos1)==24&&abs(ibos2)==24)
norm(coup_[0+ioff]*couplast_);
else if(ibos1==23&&ibos2==23)
norm(coup_[1+ioff]*couplast_);
else if(ibos1==22&&ibos2==22)
norm(coup_[2+ioff]*couplast_);
else if(( ibos1 == 22 && ibos2 == 23) ||
( ibos1 == 23 && ibos2 == 22))
norm(coup_[3+ioff]*couplast_);
else if(( abs(ibos1) == 24 && abs(ibos2) == 34) ||
( abs(ibos1) == 34 && abs(ibos2) == 24))
norm(coup_[4+ioff]*couplast_);
else if(( ibos1 == 22 && ibos2 == 33) ||
( ibos1 == 33 && ibos2 == 22))
norm(coup_[5+ioff]*couplast_);
else if(abs(ibos1)==34&&abs(ibos2)==34)
norm(coup_[6+ioff]*couplast_);
else if(ibos1==33&&ibos2==33)
norm(coup_[7+ioff]*couplast_);
else if(ibos1==32&&ibos2==32)
norm(coup_[8+ioff]*couplast_);
else if(( ibos1 == 32 && ibos2 == 33) ||
( ibos1 == 33 && ibos2 == 32))
norm(coup_[9+ioff]*couplast_);
else if(( ibos1 == 22 && ibos2 == 32) ||
( ibos1 == 32 && ibos2 == 22))
norm(coup_[10+ioff]*couplast_);
else if(( ibos1 == 23 && ibos2 == 33) ||
( ibos1 == 33 && ibos2 == 23))
norm(coup_[11+ioff]*couplast_);
else if(( ibos1 == 23 && ibos2 == 32) ||
( ibos1 == 32 && ibos2 == 23))
norm(coup_[12+ioff]*couplast_);
else
assert(false);
}
else if(((abs(ibos1) == 24 || abs(ibos1) == 34) &&
(abs(ibos2) != 24 && abs(ibos2) != 34)) ||
((abs(ibos2) == 24 || abs(ibos2) == 34) &&
(abs(ibos1) != 24 && abs(ibos1) != 34))) {
int iw,ineut;
if(abs(ibos1) == 24 || abs(ibos1) == 34) {
iw = abs(ibos1);
ineut = ibos2;
}
else {
iw = abs(ibos2);
ineut = ibos1;
}
unsigned int ioff = 66;
if((isca1 == 35 && abs(isca2) == 37) ||
(isca2 == 35 && abs(isca1) == 37)) {
ioff += 8;
}
else if ((abs(isca1) == 37 && abs(isca2) == 38) ||
(abs(isca2) == 37 && abs(isca1) == 38)) {
ioff += 16;
}
else if ((isca1 == 35 && abs(isca2) == 37) ||
(isca2 == 35 && abs(isca1) == 37)) {
ioff += 24;
}
else
assert(false);
if(iw==34) ioff += 4;
if(ineut==22)
norm(coup_[0+ioff]*couplast_);
else if(ineut==23)
norm(coup_[1+ioff]*couplast_);
else if(ineut==32)
norm(coup_[2+ioff]*couplast_);
else if(ineut==33)
norm(coup_[3+ioff]*couplast_);
else
assert(false);
}
else {
unsigned int ioff = 98;
if(isca1==25||isca2==25)
ioff += 0;
else if(isca1==35||isca2==35)
ioff += 3;
else if(isca1==36||isca2==36)
ioff += 6;
else
assert(false);
if(ibos1==ibos2) {
if(abs(ibos1)==24) {
norm(coup_[0+ioff]*couplast_);
}
else if(abs(ibos1)==34) {
norm(coup_[1+ioff]*couplast_);
}
else
assert(false);
}
else {
norm(coup_[2+ioff]*couplast_);
}
}
}
diff --git a/Models/LH/LHWWHVertex.cc b/Models/LH/LHWWHVertex.cc
--- a/Models/LH/LHWWHVertex.cc
+++ b/Models/LH/LHWWHVertex.cc
@@ -1,224 +1,225 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHWWHVertex class.
//
#include "LHWWHVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
void LHWWHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(_coup,GeV);
}
void LHWWHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(_coup,GeV);
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHWWHVertex,VVSVertex>
describeHerwigLHWWHVertex("Herwig::LHWWHVertex", "HwLHModel.so");
void LHWWHVertex::Init() {
static ClassDocumentation<LHWWHVertex> documentation
("The LHWWHVertex class implements the coupling of two electroweak"
" gauge bosons to a Higgs boson in the Little Higgs Model including the "
"additional heavy photon, Z and W bosons and the triplet Higgs bosons.");
}
LHWWHVertex::LHWWHVertex()
: _couplast(0.), _q2last(0.*GeV2) {
// order in the couplings
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void LHWWHVertex::doinit() {
// W_L W_L H
addToList( 24, -24, 25);
// Z_L Z_L H
addToList( 23, 23, 25);
// W_L W_H H
addToList( 24, -34, 25);
addToList( 34, -24, 25);
// Z_L A_H H
addToList( 23, 32, 25);
// W_H W_H H
addToList( 34, -34, 25);
// Z_H Z_H H
addToList( 33, 33, 25);
// A_H A_H H
addToList( 32, 32, 25);
// Z_H Z_L H
addToList( 23, 33, 25);
// Z_H A_H H
addToList( 33, 32, 25);
// W_L W_L Phi0
addToList( 24, -24, 35);
// W_L W_H Phi0
addToList( 24, -34, 35);
addToList( 34, -24, 35);
// Z_L Z_L Phi0
addToList( 23, 23, 35);
// Z_L Z_H Phi0
addToList( 23, 33, 35);
// W_H W_H Phi0
addToList( 34, -34, 35);
// Z_H Z_H Phi0
addToList( 33, 33, 35);
// A_H Z_H Phi0
addToList( 32, 33, 35);
// A_H Z_L Phi0
addToList( 32, 23, 35);
// A_H A_H Phi0
addToList( 32, 32, 35);
// W_L Z_L Phi-
addToList( 24, 23, -37);
addToList( -24, 23, 37);
// W_L A_H Phi-
addToList( 24, 32, -37);
addToList( -24, 32, 37);
// W_L Z_H Phi-
addToList( 24, 33, -37);
addToList( -24, 33, 37);
// W_H Z_L Phi-
addToList( 34, 23, -37);
addToList( -34, 23, 37);
// W_H A_H Phi-
addToList( 34, 32, -37);
addToList( -34, 32, 37);
// W_H Z_H Phi-
addToList( 34, 33, -37);
addToList( -34, 33, 37);
// W_L W_L Phi--
addToList( 24, 24, -38);
addToList( -24, -24, 38);
// W_H W_H Phi--
addToList( 34, 34, -38);
addToList( -34, -34, 38);
// W_L W_H Phi--
addToList( 24, 34, -38);
addToList( -24, -34, 38);
// model
cLHModelPtr model =
dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!model) throw InitException() << "Must be using the LHModel "
<< " in LHWWHVertex::doinit()"
<< Exception::runerror;
// base class
VVSVertex::doinit();
// calculate the couplings for the different combinations of particles
double sw(sqrt(sin2ThetaW())),cw(sqrt(1.-sin2ThetaW()));
Energy fact = getParticleData(ParticleID::Wplus)->mass()/sw;
double vf(sqr(model->vev()/model->f()));
double vr(model->vevPrime()/model->vev());
double r2(sqrt(2.));
double s (model->sinTheta() ),c (model->cosTheta() );
double sp(model->sinThetaPrime()),cp(model->cosThetaPrime());
double sPlus(model->sinTheta0());
double s0(model->sinTheta0());
_coup.resize(27);
// couplings to SM higgs
_coup[ 0] = fact *(1.-vf/3.+0.5*vf* sqr(sqr(c)-sqr(s))
-0.5*sqr(s0)-2.*r2*s0*vr);
_coup[ 1] = fact/sqr(cw)*(1.-vf/3.-0.5*vf*(sqr(sqr(c)-sqr(s))+5.*sqr(sqr(cp)-sqr(sp)))
-0.5*sqr(s0)+4.*r2*s0*vr);
_coup[ 2] =-fact;
_coup[ 3] =-fact;
_coup[ 4] =-fact*sqr(sw/cw);
_coup[ 5] =-fact* 0.5*(sqr(c)-sqr(s))/s/c;
_coup[ 6] =-fact/cw*0.5*(sqr(c)-sqr(s))/s/c;
_coup[ 7] =-fact/sqr(cw)*sw*0.5*(sqr(cp)-sqr(sp))/sp/cp;
_coup[ 8] =-fact/cw*sw*0.5/s/c/sp/cp*(sqr(c*sp)+sqr(s*cp));
_coup[ 9] =-fact*(s0-2.*r2*vr);
_coup[10] = fact*(s0-2.*r2*vr);
_coup[11] = fact*(s0-2.*r2*vr)*0.5*(sqr(c)-sqr(s))/s/c;
_coup[12] =-fact/sqr(cw)*(s0-4.*r2*vr);
_coup[13] = fact*(s0+sqr(sqr(c)-sqr(s))/sqr(s*c)*r2*vr);
_coup[14] = fact/cw*0.5*(sqr(c)-sqr(s))/s/c*(s0-4.*r2*vr);
_coup[15] = fact*sw/sqr(cw)*0.5*(sqr(cp)-sqr(sp))/sp/cp*(s0-4.*r2*vr);
_coup[16] = fact*sw/cw*0.5/s/c/sp/cp*(s0*(sqr(c*sp)+sqr(s*cp))
+2.*r2*(sqr(c)-sqr(s))*(sqr(cp)-sqr(sp))*vr);
_coup[17] = fact*sqr(sw/cw)*(s0+r2*vr*sqr(sqr(cp)-sqr(sp))/sqr(sp*cp));
_coup[18] =-2.*fact/cw*vr;
_coup[19] = fact/cw*(sqr(c)-sqr(s))/s/c*vr;
_coup[20] =-fact*sw/cw*0.5*(sqr(cp)-sqr(sp))/sp/cp*(sPlus-4.*vr);
_coup[21] =-fact*sw/cw*(sqr(c*cp)+sqr(s*sp))/s/c/sp/cp*vr;
_coup[22] = fact*(sqr(c)-sqr(s))/s/c*vr;
_coup[23] =-fact*(pow(c,4)+pow(s,4))/sqr(s*c)*vr;
_coup[24] = fact*4.*vr;
_coup[25] = fact*2.*(pow(c,4)+pow(s,4))/sqr(s*c)*vr;
_coup[26] =-fact*2.*vr*(sqr(c)-sqr(s))/s/c;
}
void LHWWHVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b, tcPDPtr c) {
// first the overall normalisation
if(q2!=_q2last) {
_couplast = electroMagneticCoupling(q2);
_q2last=q2;
}
int ih = abs(c->id());
long int ibos[2]={abs(a->id()),abs(b->id())};
if(ih==25) {
if ( ibos[0]==24&&ibos[1]==24 ) norm(UnitRemoval::InvE *_couplast*_coup[0]);
else if( ibos[0]==23&&ibos[1]==23 ) norm(UnitRemoval::InvE *_couplast*_coup[1]);
else if( ibos[0]==34&&ibos[1]==34 ) norm(UnitRemoval::InvE *_couplast*_coup[2]);
else if( ibos[0]==33&&ibos[1]==33 ) norm(UnitRemoval::InvE *_couplast*_coup[3]);
else if( ibos[0]==32&&ibos[1]==32 ) norm(UnitRemoval::InvE *_couplast*_coup[4]);
else if((ibos[0]==24&&ibos[1]==34) ||
(ibos[0]==34&&ibos[1]==24) ) norm(UnitRemoval::InvE *_couplast*_coup[5]);
else if((ibos[0]==23&&ibos[1]==33) ||
(ibos[0]==33&&ibos[1]==23) ) norm(UnitRemoval::InvE *_couplast*_coup[6]);
else if((ibos[0]==23&&ibos[1]==32) ||
(ibos[0]==32&&ibos[1]==23) ) norm(UnitRemoval::InvE *_couplast*_coup[7]);
else if((ibos[0]==33&&ibos[1]==32) ||
(ibos[0]==32&&ibos[1]==33) ) norm(UnitRemoval::InvE *_couplast*_coup[8]);
else assert(false);
}
else if(ih==35) {
if ( ibos[0]==24&&ibos[1]==24 ) norm(UnitRemoval::InvE *_couplast*_coup[ 9]);
else if( ibos[0]==34&&ibos[1]==34 ) norm(UnitRemoval::InvE *_couplast*_coup[10]);
else if((ibos[0]==24&&ibos[1]==34) ||
(ibos[0]==34&&ibos[1]==24) ) norm(UnitRemoval::InvE *_couplast*_coup[11]);
else if( ibos[0]==23&&ibos[1]==23 ) norm(UnitRemoval::InvE *_couplast*_coup[12]);
else if( ibos[0]==33&&ibos[1]==33 ) norm(UnitRemoval::InvE *_couplast*_coup[13]);
else if((ibos[0]==23&&ibos[1]==33) ||
(ibos[0]==33&&ibos[1]==23) ) norm(UnitRemoval::InvE *_couplast*_coup[14]);
else if((ibos[0]==23&&ibos[1]==32) ||
(ibos[0]==32&&ibos[1]==23) ) norm(UnitRemoval::InvE *_couplast*_coup[15]);
else if((ibos[0]==33&&ibos[1]==32) ||
(ibos[0]==32&&ibos[1]==33) ) norm(UnitRemoval::InvE *_couplast*_coup[16]);
else if((ibos[0]==32&&ibos[1]==32) ) norm(UnitRemoval::InvE *_couplast*_coup[17]);
else assert(false);
}
else if(ih==37) {
if ((ibos[0]==24&&ibos[1]==23) ||
(ibos[0]==23&&ibos[1]==24) ) norm(UnitRemoval::InvE *_couplast*_coup[18]);
else if((ibos[0]==34&&ibos[1]==23) ||
(ibos[0]==23&&ibos[1]==34) ) norm(UnitRemoval::InvE *_couplast*_coup[19]);
else if((ibos[0]==24&&ibos[1]==32) ||
(ibos[0]==32&&ibos[1]==24) ) norm(UnitRemoval::InvE *_couplast*_coup[20]);
else if((ibos[0]==34&&ibos[1]==32) ||
(ibos[0]==32&&ibos[1]==34) ) norm(UnitRemoval::InvE *_couplast*_coup[21]);
else if((ibos[0]==24&&ibos[1]==33) ||
(ibos[0]==33&&ibos[1]==24) ) norm(UnitRemoval::InvE *_couplast*_coup[22]);
else if((ibos[0]==34&&ibos[1]==33) ||
(ibos[0]==33&&ibos[1]==34) ) norm(UnitRemoval::InvE *_couplast*_coup[23]);
else assert(false);
}
else if(ih==38) {
if ((ibos[0]==24&&ibos[1]==24) ) norm(UnitRemoval::InvE *_couplast*_coup[24]);
else if((ibos[0]==34&&ibos[1]==34) ) norm(UnitRemoval::InvE *_couplast*_coup[24]);
else if((ibos[0]==34&&ibos[1]==24) ||
(ibos[0]==24&&ibos[1]==34) ) norm(UnitRemoval::InvE *_couplast*_coup[24]);
else assert(false);
}
else assert(false);
}
diff --git a/Models/LH/LHWWWVertex.cc b/Models/LH/LHWWWVertex.cc
--- a/Models/LH/LHWWWVertex.cc
+++ b/Models/LH/LHWWWVertex.cc
@@ -1,151 +1,152 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHWWWVertex class.
//
#include "LHWWWVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
void LHWWWVertex::persistentOutput(PersistentOStream & os) const {
os << _corr;
}
void LHWWWVertex::persistentInput(PersistentIStream & is, int) {
is >> _corr;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHWWWVertex,VVVVertex>
describeHerwigLHWWWVertex("Herwig::LHWWWVertex", "HwLHModel.so");
void LHWWWVertex::Init() {
static ClassDocumentation<LHWWWVertex> documentation
("The LHWWWVertex class implements the triple electroweak"
" gauge boson couplings in the Little Higgs model.");
}
LHWWWVertex::LHWWWVertex() : _couplast(0.),_q2last(ZERO) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void LHWWWVertex::doinit() {
// particles
addToList(24, -24, 22);
addToList(24, -24, 23);
addToList(24, -24, 32);
addToList(24, -24, 33);
addToList(34, -24, 23);
addToList(34, -24, 32);
addToList(34, -24, 33);
addToList(24, -34, 23);
addToList(24, -34, 32);
addToList(24, -34, 33);
addToList(34, -34, 22);
addToList(34, -34, 23);
addToList(34, -34, 32);
addToList(34, -34, 33);
// model
cLHModelPtr model =
dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must be using the LHModel "
<< " in LHWWWVertex::doinit()"
<< Exception::runerror;
// correction factors for the different interactions
double sw(sqrt(model->sin2ThetaW())),cw(sqrt(1.-model->sin2ThetaW()));
double vf(sqr(model->vev()/model->f()));
double s (model->sinTheta() ),c (model->cosTheta() );
double sp(model->sinThetaPrime()),cp(model->cosThetaPrime());
double xB(-2.5/sw*sp*cp*(sqr(cp)-sqr(sp)));
double xH(2.5/sw/cw*s*c*sp*cp*(sqr(c*sp)+sqr(s*cp))/
(5.*sqr(sp*cp/sw)-sqr(s*c/cw)));
double xW(-0.5/cw*s*c*(sqr(c)-sqr(s)));
_corr.resize(12);
// W_L W_L A_L
_corr[ 0] = -1.;
// W_L W_L A_H
_corr[ 1] = cw/sw*vf*xB;
// W_L W_H A_L
_corr[ 2] = 0.;
// W_L W_H A_H
_corr[ 3] = -vf/sw*xH;
// W_H W_H A_L
_corr[ 4] = -1.;
// W_H W_H A_H
_corr[ 5] = vf/sw*(xH*(sqr(c)-sqr(s))/s/c+cw*xB);
// W_L W_L Z_L
_corr[ 6] = -cw/sw;
// W_L W_L Z_H
_corr[ 7] = vf/sw*(cw*xW+s*c*(sqr(c)-sqr(s)));
// W_L W_H Z_L
_corr[ 8] = -vf/sw*xW;
// W_L W_H Z_H
_corr[ 9] = -1./sw;
// W_H W_H Z_L
_corr[10] = -cw/sw;
// W_H W_H Z_H
_corr[11] = (sqr(c)-sqr(s))/s/c/sw;
VVVVertex::doinit();
}
// couplings for the WWW vertex
void LHWWWVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b, tcPDPtr c) {
// first the overall normalisation
if(q2!=_q2last) {
_couplast = electroMagneticCoupling(q2);
_q2last=q2;
}
int ia(a->iCharge()/3),ib(b->iCharge()/3),ic(c->iCharge()/3);
int ida(a->id()), idb(b->id()), idc(c->id());
// get the particles in the interaction
int ineut,nh(0);
if(ia==0) {
ineut=ida;
if(abs(idb)==34) ++nh;
if(abs(idc)==34) ++nh;
}
else if(ib==0) {
ineut=idb;
if(abs(ida)==34) ++nh;
if(abs(idc)==34) ++nh;
}
else {
ineut=idc;
if(abs(ida)==34) ++nh;
if(abs(idb)==34) ++nh;
}
if(nh==0) {
if (ineut==22) norm(_corr[ 0]*_couplast);
else if(ineut==23) norm(_corr[ 6]*_couplast);
else if(ineut==32) norm(_corr[ 1]*_couplast);
else if(ineut==33) norm(_corr[ 7]*_couplast);
}
else if(nh==1) {
if (ineut==22) norm(_corr[ 2]*_couplast);
else if(ineut==23) norm(_corr[ 8]*_couplast);
else if(ineut==32) norm(_corr[ 3]*_couplast);
else if(ineut==33) norm(_corr[ 9]*_couplast);
}
else if(nh==2) {
if (ineut==22) norm(_corr[ 4]*_couplast);
else if(ineut==23) norm(_corr[10]*_couplast);
else if(ineut==32) norm(_corr[ 5]*_couplast);
else if(ineut==33) norm(_corr[11]*_couplast);
}
// check the order for the overall sign
if((ia<0 && ib>0 && ic==0) ||
(ia==0 && ib<0 && ic>0 ) ||
(ia>0 && ib==0 && ic<0 ) ) norm(-norm());
}
diff --git a/Models/LH/LHWWWWVertex.cc b/Models/LH/LHWWWWVertex.cc
--- a/Models/LH/LHWWWWVertex.cc
+++ b/Models/LH/LHWWWWVertex.cc
@@ -1,309 +1,310 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHWWWWVertex class.
//
#include "LHWWWWVertex.h"
#include "LHModel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
LHWWWWVertex::LHWWWWVertex() :
_couplast(0.0), _q2last(sqr(Constants::MaxEnergy)), _coup(36,0.) {
// order in the couplings
orderInGem(2);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr LHWWWWVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHWWWWVertex::fullclone() const {
return new_ptr(*this);
}
void LHWWWWVertex::persistentOutput(PersistentOStream & os) const {
os << _coup;
}
void LHWWWWVertex::persistentInput(PersistentIStream & is, int) {
is >> _coup;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHWWWWVertex,VVVVVertex>
describeHerwigLHWWWWVertex("Herwig::LHWWWWVertex", "HwLHModel.so");
void LHWWWWVertex::Init() {
static ClassDocumentation<LHWWWWVertex> documentation
("The LHWWWWVertex class implements the quartic electroweak"
" boson couplings in the Little Higgs Model");
}
void LHWWWWVertex::doinit() {
// all charge W's
addToList(24, -24, 24, -24);
addToList(34, -34, 34, -34);
addToList(24, -24, 34, -34);
addToList(24, -24, 24, -34);
addToList(24, -24, 34, -24);
addToList(34, -24, 34, -24);
addToList(24, -34, 24, -34);
addToList(34, -34, 24, -34);
addToList(34, -34, 34, -24);
// two neutral and 2 W_L
addToList(22, 24, 22, -24);
addToList(23, 24, 23, -24);
addToList(22, 24, 23, -24);
addToList(22, 24, 32, -24);
addToList(22, 24, 33, -24);
addToList(23, 24, 33, -24);
addToList(23, 24, 32, -24);
addToList(33, 24, 33, -24);
addToList(33, 24, 32, -24);
// two neutral and 2 W_H
addToList(22, 34, 22, -34);
addToList(23, 34, 23, -34);
addToList(22, 34, 23, -34);
addToList(22, 34, 32, -34);
addToList(22, 34, 33, -34);
addToList(23, 34, 33, -34);
addToList(23, 34, 32, -34);
addToList(33, 34, 33, -34);
addToList(33, 34, 32, -34);
// two neutral W_L W_H
addToList(23, 24, 23, -34);
addToList(23, 24, 22, -34);
addToList(22, 24, 32, -34);
addToList(23, 24, 32, -34);
addToList(33, 24, 33, -34);
addToList(33, 24, 32, -34);
addToList(22, 24, 33, -34);
addToList(23, 24, 33, -34);
addToList(23, 34, 23, -24);
addToList(23, 34, 22, -24);
addToList(22, 34, 32, -24);
addToList(23, 34, 32, -24);
addToList(33, 34, 33, -24);
addToList(33, 34, 32, -24);
addToList(22, 34, 33, -24);
addToList(23, 34, 33, -24);
// model
cLHModelPtr model =
dynamic_ptr_cast<cLHModelPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must be using the LHModel "
<< " in LHWWWWVertex::doinit()"
<< Exception::runerror;
// correction factors for the different interactions
double sw2(sin2ThetaW());
double sw(sqrt(sw2)),cw(sqrt(1.-sw2));
double s (model->sinTheta() ),c (model->cosTheta() );
double sp(model->sinThetaPrime()),cp(model->cosThetaPrime());
double vf(sqr(model->vev()/model->f()));
double xB(-2.5/sw*sp*cp*(sqr(cp)-sqr(sp)));
double xW(-0.5/cw*s*c*(sqr(c)-sqr(s)));
double xH(2.5/sw/cw*s*c*sp*cp*(sqr(c*sp)+sqr(s*cp))/
(5.*sqr(sp*cp/sw)-sqr(s*c/cw)));
// 4 W's
_coup[ 0] =-1./sw2;
_coup[ 1] =-1./sw2;
_coup[ 2] = 0.5/sw2*(sqr(c)-sqr(s))/c/s;
_coup[ 3] =-0.25/sw2*vf*s*c*(sqr(c)-sqr(s));
_coup[ 4] =-0.25/sw2;
_coup[ 5] =-1./sw2*(pow(c,6)+pow(s,c))/sqr(s*c);
// 2 W_L
_coup[ 6] = 1.;
_coup[ 7] = sqr(cw/sw);
_coup[ 8] = cw/sw;
_coup[ 9] =-cw/sw*xB*vf;
_coup[10] =-cw/sw*xW*vf+0.5/sw*s*c*(sqr(c)-sqr(s))*vf;
_coup[11] =-(sqr(cw)-sw2)/sw2*xW*vf;
_coup[12] =-sqr(cw/sw)*xB*vf;
_coup[13] = 0.;
_coup[14] = 1./sw2;
_coup[15] = xH*vf/sw2;
_coup[16] = 1.;
_coup[17] = sqr(cw/sw);
_coup[18] = cw/sw;
_coup[19] =-cw/sw*xB*vf-xH/sw*vf*(sqr(c)-sqr(s))/s/c;
_coup[20] =-1./sw*(sqr(c)-sqr(s))/s/c;
_coup[21] =-cw/sw2*(sqr(c)-sqr(s))/s/c;
_coup[22] =-sqr(cw/sw)*xB*vf-cw/sw2*xH*vf*(sqr(c)-sqr(s))/c/s;
_coup[23] = 0.;
_coup[24] = (pow(c,6)+pow(s,6))/sqr(s*c)/sw2;
_coup[25] = xH/sw2*vf*(pow(c,6)+pow(s,6))/sqr(s*c)
+cw/sw2*xB*vf*(sqr(c)-sqr(s))/s/c;
_coup[26] = 0.;
_coup[27] = 2.*cw/sw2*xW*vf;
_coup[28] = 0.;
_coup[29] = xH*vf/sw;
_coup[30] = xH*vf*cw/sw2;
_coup[31] = xW*vf/sw;
_coup[32] =-(sqr(c)-sqr(s))/s/c/sw2;
_coup[33] =-xH*vf*(sqr(c)-sqr(s))/s/c-cw/sw2*xB*vf;
_coup[34] = 1./sw;
_coup[35] = cw/sw2;
VVVVVertex::doinit();
}
void LHWWWWVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,
tcPDPtr c,tcPDPtr d) {
// id's of the particles
long int id[4]={a->id(),b->id(),c->id(),d->id()};
// order the particles
int ngamma(0),nz(0);
int iorder[4];
for(int ix=0;ix<4;++ix) {
if (id[ix]==22||id[ix]==32) ++ngamma;
else if (id[ix]==23||id[ix]==33) ++nz;
}
// if photons or Z's
if(ngamma!=0 || nz!=0) {
int iy=0;
// put the photons first
for(int ix=0;iy<ngamma&&ix<4;++ix) {
if(id[ix]==22||id[ix]==32) {
iorder[iy]=ix;
++iy;
}
}
// then the Z bosons
for(int ix=0;iy<ngamma+nz&&ix<4;++ix) {
if(id[ix]==23||id[ix]==33) {
iorder[iy]=ix;
++iy;
}
}
// then the W+
for(int ix=0;iy<3&&ix<4;++ix) {
if(id[ix]==24||id[ix]==34) {
iorder[iy]=ix;
++iy;
}
}
assert(iy==3);
// finally the W-
for(int ix=0;iy<4&&ix<4;++ix) {
if(id[ix]==-24||id[ix]==-34) {
iorder[iy]=ix;
++iy;
}
}
assert(iy==4);
}
else {
int iy=0;
// first the W+
for(int ix=0;iy<3&&ix<4;++ix) {
if(id[ix]==24||id[ix]==34) {
iorder[iy]=ix;
++iy;
}
}
assert(iy==2);
// finally the W-
for(int ix=0;iy<4&&ix<4;++ix) {
if(id[ix]==-24||id[ix]==-34) {
iorder[iy]=ix;
++iy;
}
}
assert(iy==4);
}
setOrder(iorder[0],iorder[1],iorder[2],iorder[3]);
setType(2);
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = sqr(electroMagneticCoupling(q2));
_q2last=q2;
}
// ids of the particles
for(unsigned int ix=0;ix<4;++ix) {
if (iorder[ix]==0) id[ix] = abs(a->id());
else if(iorder[ix]==1) id[ix] = abs(b->id());
else if(iorder[ix]==2) id[ix] = abs(c->id());
else if(iorder[ix]==3) id[ix] = abs(d->id());
}
if( ngamma == 0 && nz == 0 ) {
if(id[0]==id[1]) {
if(id[2]==id[3]) {
if(id[0]==24&&id[2]==24)
norm(_couplast*_coup[0]);
else if(id[0]==34&&id[2]==34)
norm(_couplast*_coup[5]);
else
norm(_couplast*_coup[1]);
}
else {
if(id[0]==24)
norm(_couplast*_coup[3]);
else
norm(_couplast*_coup[2]);
}
}
else {
if(id[2]==id[3]) {
if(id[2]==24)
norm(_couplast*_coup[3]);
else
norm(_couplast*_coup[2]);
}
else
norm(_couplast*_coup[4]);
}
}
else {
if(id[2]==id[3]) {
unsigned int ioff = id[2]==24 ? 0 : 10;
if(id[0]==22&&id[1]==22)
norm(_couplast*_coup[6+ioff]);
else if(id[0]==23&&id[1]==23)
norm(_couplast*_coup[7+ioff]);
else if((id[0]==22&&id[1]==23) || (id[0]==23&&id[1]==22))
norm(_couplast*_coup[8+ioff]);
else if((id[0]==22&&id[1]==32) || (id[0]==32&&id[1]==22))
norm(_couplast*_coup[9+ioff]);
else if((id[0]==22&&id[1]==33) || (id[0]==33&&id[1]==22))
norm(_couplast*_coup[10+ioff]);
else if((id[0]==23&&id[1]==33) || (id[0]==33&&id[1]==22))
norm(_couplast*_coup[11+ioff]);
else if((id[0]==23&&id[1]==32) || (id[0]==32&&id[1]==23))
norm(_couplast*_coup[12+ioff]);
else if( id[0]==33&&id[1]==33)
norm(_couplast*_coup[14+ioff]);
else if((id[0]==32&&id[1]==33) || (id[0]==33&&id[1]==32))
norm(_couplast*_coup[15+ioff]);
else
assert(false);
}
else {
if(id[0]==23&&id[1]==23)
norm(_couplast*_coup[27]);
else if((id[0]==22&&id[1]==23) || (id[0]==23&&id[1]==22))
norm(_couplast*_coup[28]);
else if((id[0]==22&&id[1]==32) || (id[0]==32&&id[1]==22))
norm(_couplast*_coup[29]);
else if((id[0]==23&&id[1]==32) || (id[0]==32&&id[1]==23))
norm(_couplast*_coup[30]);
else if( id[0]==33&&id[1]==33)
norm(_couplast*_coup[31]);
else if((id[0]==32&&id[1]==33) || (id[0]==33&&id[1]==32))
norm(_couplast*_coup[32]);
else if((id[0]==22&&id[1]==33) || (id[0]==33&&id[1]==22))
norm(_couplast*_coup[33]);
else if((id[0]==23&&id[1]==33) || (id[0]==33&&id[1]==22))
norm(_couplast*_coup[34]);
else
assert(false);
}
}
}
diff --git a/Models/LHTP/LHTPFFGVertex.cc b/Models/LHTP/LHTPFFGVertex.cc
--- a/Models/LHTP/LHTPFFGVertex.cc
+++ b/Models/LHTP/LHTPFFGVertex.cc
@@ -1,73 +1,74 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPFFGVertex class.
//
#include "LHTPFFGVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
IBPtr LHTPFFGVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHTPFFGVertex::fullclone() const {
return new_ptr(*this);
}
// Static variable needed for the type description system in ThePEG.
DescribeNoPIOClass<LHTPFFGVertex,FFVVertex>
describeHerwigLHTPFFGVertex("Herwig::LHTPFFGVertex", "HwLHTPModel.so");
void LHTPFFGVertex::Init() {
static ClassDocumentation<LHTPFFGVertex> documentation
("The LHTPFFGVertex class implements the couples of the fermions "
"to the gluons in the Little Higgs model with T-parity.");
}
LHTPFFGVertex::LHTPFFGVertex()
: coupLast_(0.), q2Last_(0.*GeV2) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TFUND);
}
void LHTPFFGVertex::doinit() {
// SM quarks
for(int ix = 1; ix < 7; ++ix) {
addToList(-ix, ix, 21);
}
// additional top quark
addToList(-8, 8, 21);
// T odd quarks
for(long ix = 4000001; ix <= 4000006; ++ix) {
addToList(-ix, ix, 21);
}
addToList(-4000008, 4000008, 21);
FFVVertex::doinit();
}
// coupling for FFG vertex
void LHTPFFGVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr,tcPDPtr) {
// first the overall normalisation
if(q2!=q2Last_) {
coupLast_ = -strongCoupling(q2);
q2Last_=q2;
}
norm(coupLast_);
// the left and right couplings
int iferm=abs(a->id());
if( iferm > 8 ) iferm -= 4000000;
if((iferm>=1 && iferm<=8)) {
left (1.);
right(1.);
}
else
assert(false);
}
diff --git a/Models/LHTP/LHTPFFHVertex.cc b/Models/LHTP/LHTPFFHVertex.cc
--- a/Models/LHTP/LHTPFFHVertex.cc
+++ b/Models/LHTP/LHTPFFHVertex.cc
@@ -1,387 +1,388 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPFFHVertex class.
//
#include "LHTPFFHVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
void LHTPFFHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(cL_,1./GeV) << ounit(cR_,1./GeV) << model_;
}
void LHTPFFHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(cL_,1./GeV) >> iunit(cR_,1./GeV) >> model_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHTPFFHVertex,FFSVertex>
describeHerwigLHTPFFHVertex("Herwig::LHTPFFHVertex", "HwLHTPModel.so");
void LHTPFFHVertex::Init() {
static ClassDocumentation<LHTPFFHVertex> documentation
("The LHTPFFHVertex class implements the interaction of the fermions"
" and the Higgs bosons in the Little Higgs model with T-parity");
}
LHTPFFHVertex::LHTPFFHVertex()
: q2Last_(ZERO) {
orderInGem(1);
orderInGs(0);
massLast_[0] = 0.*GeV;
massLast_[1] = 0.*GeV;
idLast_[0] = 0;
idLast_[1] = 0;
+ colourStructure(ColourStructure::DELTA);
}
void LHTPFFHVertex::doinit() {
// SM like higgs
addToList( -3, 3, 25);
addToList( -4, 4, 25);
addToList( -5, 5, 25);
addToList( -6, 6, 25);
addToList( -6, 8, 25);
addToList( -8, 6, 25);
addToList( -8, 8, 25);
addToList( -13, 13, 25);
addToList( -15, 15, 25);
addToList( -4000002, 4000002, 25);
addToList( -4000004, 4000004, 25);
addToList( -4000006, 4000006, 25);
addToList( -4000012, 4000012, 25);
addToList( -4000014, 4000014, 25);
addToList( -4000016, 4000016, 25);
// phi0
addToList( -3 , 4000003, 35);
addToList( -4 , 4000004, 35);
addToList( -5 , 4000005, 35);
addToList( -4000003, 3, 35);
addToList( -4000004, 4, 35);
addToList( -4000005, 5, 35);
addToList( -6 , 4000006, 35);
addToList( -8 , 4000006, 35);
addToList( -4000006, 6, 35);
addToList( -4000006, 8, 35);
// phiP
addToList( -2 , 4000002, 36);
addToList( -3 , 4000003, 36);
addToList( -4 , 4000004, 36);
addToList( -5 , 4000005, 36);
addToList( -4000002, 2, 36);
addToList( -4000003, 3, 36);
addToList( -4000004, 4, 36);
addToList( -4000005, 5, 36);
addToList( -12 , 4000012, 36);
addToList( -14 , 4000014, 36);
addToList( -16 , 4000016, 36);
addToList( -4000012, 12, 36);
addToList( -4000014, 14, 36);
addToList( -4000016, 16, 36);
addToList( -6 , 4000006, 36);
addToList( -6 , 4000008, 36);
addToList( -8 , 4000006, 36);
addToList( -8 , 4000008, 36);
addToList( -4000006, 6, 36);
addToList( -4000008, 6, 36);
addToList( -4000006, 8, 36);
addToList( -4000008, 8, 36);
// phi +/-
addToList( -1 , 4000002, -37);
addToList( -3 , 4000004, -37);
addToList( -5 , 4000006, -37);
addToList( -4000001, 2, -37);
addToList( -4000003, 4, -37);
addToList( -4000005, 6, -37);
addToList( -4000005, 8, -37);
addToList( -4000002, 1, 37);
addToList( -4000004, 3, 37);
addToList( -4000006, 5, 37);
addToList( -2 , 4000001, 37);
addToList( -4 , 4000003, 37);
addToList( -6 , 4000005, 37);
addToList( -8 , 4000005, 37);
addToList( -11 , 4000012, -37);
addToList( -13 , 4000014, -37);
addToList( -15 , 4000016, -37);
addToList( -4000011, 12, -37);
addToList( -4000013, 14, -37);
addToList( -4000015, 16, -37);
addToList( -4000012, 11 , 37);
addToList( -4000014, 13 , 37);
addToList( -4000016, 15 , 37);
addToList( -12, 4000011, 37);
addToList( -14, 4000013, 37);
addToList( -16, 4000015, 37);
model_ =
dynamic_ptr_cast<cLHTPModelPtr>(generator()->standardModel());
if(!model_) throw InitException() << "Must be using the LHModel "
<< " in LHFFPVertex::doinit()"
<< Exception::runerror;
cL_ .resize(18);
cR_ .resize(18);
Energy v = model_->vev();
Energy f = model_->f();
double vf = model_->vev()/model_->f();
double sa = model_->sinAlpha();
double ca = model_->cosAlpha();
// lightest higgs couplings
// coupling of light SM fermions
cL_[0] = cR_[0] = 1./v;
// couplings to top quarks
cL_[1] = cR_[1] = sa*ca/f;
cL_[2] = -sa/ca/v;
cR_[2] = sqr(ca)*vf/v;
// couplings to T-odd quarks
cL_[3] = cR_[3] = 0.5*sqrt(0.5)/f*model_->kappaQuark();
// couplings to T-odd leptons
cL_[4] = cR_[4] = 0.5*sqrt(0.5)/f*model_->kappaLepton();
// Phi0
// quark, T-odd quark
cL_[5] = sqrt(0.5)/f;
cR_[5] = ZERO;
// and top quarks
cL_[6] = sqrt(0.5)*model_->cosThetaR()/f/ca;
cR_[6] = ZERO;
cL_[7] = sqrt(0.5)*model_->sinThetaR()/f/ca;
cR_[7] = ZERO;
// PhiP
// quark, T-odd quark
cL_[8] = vf/f*model_->kappaQuark()/12;
cR_[8] = sqrt(0.5)/f;
// lepton, T-odd lepton
cL_[9] = vf/f*model_->kappaLepton()/12;
cR_[9] = ZERO;
// top, T_-
cL_[10] = model_->cosThetaR()*sqrt(2.)*vf/f/ca/3;
cR_[10] = ZERO;
cL_[11] = model_->sinThetaR()*sqrt(2.)*vf/f/ca/3;
cR_[11] = ZERO;
// top, t_-
cL_[12] = model_->cosThetaL()*vf/f/12.*model_->kappaQuark();
cR_[12] = model_->cosThetaR()*sqrt(0.5)/f/ca;
cL_[13] = model_->sinThetaL()*vf/f/12.*model_->kappaQuark();
cR_[13] = model_->sinThetaR()*sqrt(0.5)/f/ca;
// Phi +/-
cL_[14] = vf/f*model_->kappaLepton()/24.;
cR_[14] = ZERO;
// quark T-odd quark
cL_[15] = vf/f*model_->kappaQuark() /24.;
cR_[15] =-vf*sqrt(0.5)/v;
cL_[16] = model_->cosThetaL()*vf/f*model_->kappaQuark() /24.;
cR_[16] =-model_->cosThetaR()*vf*sqrt(0.5)/v/ca;
cL_[17] = model_->sinThetaL()*vf/f*model_->kappaQuark() /24.;
cR_[17] =-model_->sinThetaR()*vf*sqrt(0.5)/v/ca;
FFSVertex::doinit();
}
void LHTPFFHVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b, tcPDPtr c) {
norm(1.);
int iferm=abs(a->id());
int ianti=abs(b->id());
// int ihigg=abs(c->id());
// left and right couplings set to one
// SM like higgs
if(c->id()==ParticleID::h0) {
// to SM fermions and T
if(iferm<=16&&ianti<=16) {
// running masses
if(q2!=q2Last_||idLast_[0]!=iferm||idLast_[1]!=ianti) {
q2Last_ = q2;
idLast_[0] = iferm;
assert((idLast_[0]>=1 && idLast_[0]<=8 ) ||
(idLast_[0]>=11 && idLast_[0]<=16));
if(idLast_[0]!=8)
massLast_[0] = model_->mass(q2,a);
else
massLast_[0] = model_->mass(q2,getParticleData(ParticleID::t));
idLast_[1] = ianti;
assert((idLast_[1]>=1 && idLast_[1]<=8 ) ||
(idLast_[1]>=11 && idLast_[1]<=16));
if(idLast_[0]!=idLast_[1]) {
if(idLast_[1]!=8)
massLast_[1] = model_->mass(q2,a);
else
massLast_[1] = model_->mass(q2,getParticleData(ParticleID::t));
}
else {
massLast_[1] = massLast_[0];
}
}
if(iferm<6||iferm>8) {
left (-Complex(cL_[0]*massLast_[0]));
right(-Complex(cR_[0]*massLast_[0]));
}
else {
if(iferm==8&&ianti==8) {
left ( Complex(cL_[1]*massLast_[0]));
right( Complex(cR_[1]*massLast_[0]));
}
else {
if(a->id()==ParticleID::tbar||b->id()==ParticleID::tbar) {
left (-Complex(cL_[2]*massLast_[0]));
right(-Complex(cR_[2]*massLast_[0]));
}
else {
left (-Complex(cR_[2]*massLast_[0]));
right(-Complex(cL_[2]*massLast_[0]));
}
}
}
}
else {
if(iferm<=4000006) {
left ( Complex(cL_[3]*model_->vev()));
right( Complex(cR_[3]*model_->vev()));
}
else {
left ( Complex(cL_[4]*model_->vev()));
right( Complex(cR_[4]*model_->vev()));
}
}
}
// Phi0
else if(c->id()==ParticleID::H0 ||
c->id()==ParticleID::A0) {
tcPDPtr ferm = a;
if(iferm>4000000) {
swap(iferm,ianti);
ferm = b;
}
if(q2!=q2Last_||idLast_[0]!=iferm) {
q2Last_ = q2;
idLast_[0] = iferm;
assert((idLast_[0]>=1 && idLast_[0]<=8 ) ||
(idLast_[0]>=11 && idLast_[0]<=16));
if(idLast_[0]!=8)
massLast_[0] = model_->mass(q2,ferm);
else
massLast_[0] = model_->mass(q2,getParticleData(ParticleID::t));
}
if(c->id()==ParticleID::H0 ) {
unsigned int iloc = 5;
if(iferm==6) iloc = 6;
else if(iferm==8) iloc = 7;
if( (a->id()>=1&&a->id()<=8) || (b->id()>=1&&b->id()<=8) ) {
left ( Complex(cR_[iloc]*massLast_[0]));
right( Complex(cL_[iloc]*massLast_[0]));
}
else {
left ( Complex(cL_[iloc]*massLast_[0]));
right( Complex(cR_[iloc]*massLast_[0]));
}
}
// PhiP
else if(c->id()==ParticleID::A0) {
if(iferm<=5) {
if( (a->id()>=1&&a->id()<=5) || (b->id()>=1&&b->id()<=5) ) {
if(iferm%2==0) {
right(Complex(0., 1.)*model_->vev()*cL_[8]);
left (Complex(0.,-1.)*massLast_[0] *cR_[8]);
}
else {
right(Complex(ZERO));
left (Complex(0., 1.)*massLast_[0] *cR_[8]);
}
}
else {
if(iferm%2==0) {
left (Complex(0.,-1.)*model_->vev()*cL_[8]);
right(Complex(0., 1.)*massLast_[0] *cR_[8]);
}
else {
left (Complex(ZERO));
right(Complex(0.,-1.)*massLast_[0] *cR_[8]);
}
}
}
else if(iferm>=12) {
if( (a->id()>=11&&a->id()<=16) || (b->id()>=11&&b->id()<=16) ) {
right(Complex(0., 1.)*model_->vev()*cL_[9]);
left (Complex(0.,-1.)*massLast_[0] *cR_[9]);
}
else {
right(Complex(0.,-1.)*massLast_[0] *cR_[9]);
left (Complex(0., 1.)*model_->vev()*cL_[9]);
}
}
else {
if(ianti==4000008) {
unsigned int iloc = (iferm+14)/2;
if( (a->id()==6||a->id()==8) || (b->id()==6||b->id()==8) ) {
left (Complex(0., 1.)*massLast_[0]*cR_[iloc]);
right(Complex(0., 1.)*massLast_[0]*cL_[iloc]);
}
else {
left (Complex(0.,-1.)*massLast_[0]*cL_[iloc]);
right(Complex(0.,-1.)*massLast_[0]*cR_[iloc]);
}
}
else {
unsigned int iloc = (iferm+18)/2;
if( (a->id()==6||a->id()==8) || (b->id()==6||b->id()==8) ) {
left (Complex(0., 1.)*model_->vev()*cL_[iloc]);
right(Complex(0.,-1.)*massLast_[0] *cR_[iloc]);
}
else {
left (Complex(0., 1.)*massLast_[0] *cR_[iloc]);
right(Complex(0.,-1.)*model_->vev()*cL_[iloc]);
}
}
}
}
}
else if(abs(c->id())==ParticleID::Hplus) {
tcPDPtr ferm = a;
if(iferm>4000000) {
swap(iferm,ianti);
ferm = b;
}
if(q2!=q2Last_||idLast_[0]!=iferm) {
q2Last_ = q2;
idLast_[0] = iferm;
assert((idLast_[0]>=1 && idLast_[0]<=8 ) ||
(idLast_[0]>=11 && idLast_[0]<=16));
if(idLast_[0]!=8)
massLast_[0] = model_->mass(q2,ferm);
else
massLast_[0] = model_->mass(q2,getParticleData(ParticleID::t));
}
Complex cleft(0.),cright(0.);
// lepton and T-odd lepton
if(iferm>=11&&iferm<=16) {
cright = cR_[14]*massLast_[0];
cleft = cL_[14]*model_->vev();
}
else if(iferm>=1&&iferm<=6) {
cright = cR_[15]*massLast_[0];
cleft = cL_[15]*model_->vev();
}
else if(iferm==6) {
cright = cR_[16]*massLast_[0];
cleft = cL_[16]*model_->vev();
}
else if(iferm==8) {
cright = cR_[17]*massLast_[0];
cleft = cL_[17]*model_->vev();
}
if((a->id()>=1&&a->id()<=16) ||(b->id()>=1&&b->id()<=16) ) {
swap(cleft,cright);
cleft *= -1.;
cright *= -1.;
}
if(c->id()==ParticleID::Hminus) {
cleft *= -1.;
cright *= -1.;
}
left (cleft );
right(cright);
}
}
diff --git a/Models/LHTP/LHTPFFPVertex.cc b/Models/LHTP/LHTPFFPVertex.cc
--- a/Models/LHTP/LHTPFFPVertex.cc
+++ b/Models/LHTP/LHTPFFPVertex.cc
@@ -1,193 +1,194 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPFFPVertex class.
//
#include "LHTPFFPVertex.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "LHTPModel.h"
using namespace Herwig;
IBPtr LHTPFFPVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHTPFFPVertex::fullclone() const {
return new_ptr(*this);
}
void LHTPFFPVertex::persistentOutput(PersistentOStream & os) const {
os << charge_ << coupd_ << coupu_ << coupe_ << coupnu_
<< TPreFactor_ << sL_ << cL_ << sR_ << cR_;
}
void LHTPFFPVertex::persistentInput(PersistentIStream & is, int) {
is >> charge_ >> coupd_ >> coupu_ >> coupe_ >> coupnu_
>> TPreFactor_ >> sL_ >> cL_ >> sR_ >> cR_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHTPFFPVertex,FFVVertex>
describeHerwigLHTPFFPVertex("Herwig::LHTPFFPVertex", "HwLHTPModel.so");
void LHTPFFPVertex::Init() {
static ClassDocumentation<LHTPFFPVertex> documentation
("The LHTPFFPVertex class implements the coupling"
" of the charged fermions to the photon in the Little Higgs"
" model with T-parity.");
}
LHTPFFPVertex::LHTPFFPVertex() :
charge_(37,0.0), coupLast_(0.), q2Last_(-1.*GeV2),
coupd_(0.), coupu_(0.), coupe_(0.), coupnu_(0.),
TPreFactor_(0.), sL_(0.), cL_(1.), sR_(0.), cR_(1.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void LHTPFFPVertex::doinit() {
// interactions with the photon
// the quarks
for(int ix = 1; ix < 7; ++ix) {
addToList(-ix, ix, 22);
}
// the leptons
for(int ix = 11; ix < 17; ix += 2) {
addToList(-ix, ix, 22);
}
// extra top quark
addToList(-8, 8, 22);
// the T-odd quarks
for(long ix = 4000001;ix < 4000007; ++ix) {
addToList(-ix, ix, 22);
}
// the T-odd leptons
for(long ix = 4000011; ix < 4000017; ix += 2) {
addToList(-ix, ix, 22);
}
// extra top quark
addToList(-4000008, 4000008, 22);
// interactions with A_H
// quarks and T-odd quark
for(int ix = 1; ix < 7; ++ix) {
addToList(-ix - 4000000, ix , 32);
addToList(-ix , ix + 4000000, 32);
}
// leptons and T-odd leptons (both charged leptons and neutrinos)
for(int ix = 11; ix < 17; ++ix ) {
addToList(-ix - 4000000, ix , 32);
addToList(-ix , ix + 4000000, 32);
}
// T+T-A_H
addToList(-4000008, 8, 32);
addToList( -8, 4000008, 32);
// T-tA_H
addToList(-4000008, 6, 32);
addToList( -6, 4000008, 32);
// T-tA_H
addToList(-4000006, 8, 32);
addToList( -8, 4000006, 32);
// charges
for(int ix = 1; ix < 16; ++ix) {
tcPDPtr ptemp = getParticleData(ix);
if(ptemp) charge_[ix] = double(ptemp->iCharge())/3.;
}
for(int ix = 4000001; ix < 4000016; ++ix) {
tcPDPtr ptemp = getParticleData(ix);
if(ptemp) charge_[ix-3999980] = double(ptemp->iCharge())/3.;
}
// couplings to A_H
double sw = generator()->standardModel()->sin2ThetaW();
double cw = sqrt(1.-sw);
sw = sqrt(sw);
// model
cLHTPModelPtr model =
dynamic_ptr_cast<cLHTPModelPtr>(generator()->standardModel());
if(!model) throw InitException() << "Must be using the LHTPModel "
<< " in LHTPFFPVertex::doinit()"
<< Exception::runerror;
double cH = model->cosThetaH();
double sH = model->sinThetaH();
sL_ = model->sinThetaL();
cL_ = model->cosThetaL();
sR_ = model->sinThetaR();
cR_ = model->cosThetaR();
// couplings of fermion T-odd fermion A_H
coupd_ = -0.1*(cH/cw-5.*sH/sw);
coupu_ = -0.1*(cH/cw+5.*sH/sw);
coupe_ = -0.1*(cH/cw-5.*sH/sw);
coupnu_ = -0.1*(cH/cw+5.*sH/sw);
// couplings of T+T- A_H
TPreFactor_ = 0.4*cH/cw;
FFVVertex::doinit();
}
// coupling for FFP vertex
void LHTPFFPVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,tcPDPtr c) {
// first the overall normalisation
if(q2!=q2Last_) {
coupLast_ = -electroMagneticCoupling(q2);
q2Last_=q2;
}
norm(coupLast_);
// the left and right couplings
long iferm=abs(a->id()),ibos(c->id());
if(ibos == ParticleID::gamma) {
if(iferm < 20) {
left (charge_[iferm]);
right(charge_[iferm]);
}
else {
iferm-=3999980;
left (charge_[iferm]);
right(charge_[iferm]);
}
}
else if(ibos == 32) {
long ianti = abs(b->id());
if(iferm>4000000) swap(iferm,ianti);
assert(iferm<4000000&&ianti>4000000);
if( iferm == 6 || iferm == 8 ) {
if (iferm==6&&ianti==4000006) {
left (cL_*coupu_);
right(0.);
}
else if(iferm==6&&ianti==4000008) {
left (-TPreFactor_*sL_);
right(-TPreFactor_*sR_);
}
else if(iferm==8&&ianti==4000006) {
left (sL_*coupu_);
right(0.);
}
else if(iferm==8&&ianti==4000008) {
left ( TPreFactor_*cL_);
right( TPreFactor_*cR_);
}
else
assert(false);
}
// quarks (inclding top)
else if(iferm <= 5) {
if(iferm % 2 == 0) left(coupu_);
else left(coupd_);
right(0.);
}
// leptons
else {
if(iferm %2 == 0) left(coupnu_);
else left(coupe_ );
right(0.);
}
}
else
assert(false);
}
diff --git a/Models/LHTP/LHTPFFWVertex.cc b/Models/LHTP/LHTPFFWVertex.cc
--- a/Models/LHTP/LHTPFFWVertex.cc
+++ b/Models/LHTP/LHTPFFWVertex.cc
@@ -1,199 +1,200 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPFFWVertex class.
//
#include "LHTPFFWVertex.h"
#include "LHTPModel.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/StandardModel/CKMBase.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
using namespace Herwig;
IBPtr LHTPFFWVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHTPFFWVertex::fullclone() const {
return new_ptr(*this);
}
void LHTPFFWVertex::persistentOutput(PersistentOStream & os) const {
os << ckm_ << sL_ << cL_;
}
void LHTPFFWVertex::persistentInput(PersistentIStream & is, int) {
is >> ckm_ >> sL_ >> cL_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHTPFFWVertex,FFVVertex>
describeHerwigLHTPFFWVertex("Herwig::LHTPFFWVertex", "HwLHTPModel.so");
void LHTPFFWVertex::Init() {
static ClassDocumentation<LHTPFFWVertex> documentation
("The LHTPFFWVertex class implements the couplings of the W"
" and W_H bosons of the Little Higgss model with T-parity to the fermions.");
}
void LHTPFFWVertex::doinit() {
// particles for outgoing W-
// quarks
for(int ix = 1; ix < 6; ix += 2) {
for(int iy = 2; iy < 7; iy += 2) {
addToList(-ix, iy, -24);
}
}
// additional T quark
addToList(-5, 8, -24);
// leptons
for(int ix = 11; ix < 17; ix += 2) {
addToList(-ix, ix + 1, -24);
}
// T-odd quarks
for(long ix = 4000002; ix < 4000007; ix += 2) {
addToList(-ix + 1, ix, -24);
}
// T-odd leptons
for(long ix = 4000011; ix < 4000017; ix += 2) {
addToList(-ix, ix + 1, -24);
}
// particles for outgoing W+
// quarks
for(int ix = 2; ix < 7; ix += 2) {
for(int iy = 1; iy < 6; iy += 2) {
addToList(-ix, iy, 24);
}
}
// additional T quark
addToList(-8, 5, 24);
// leptons
for(int ix = 11; ix < 17; ix += 2) {
addToList(-ix - 1, ix, 24);
}
// T-odd quarks
for(long ix = 4000002; ix < 4000009; ix += 2) {
addToList(-ix, ix-1, 24);
}
// T-odd leptons
for(long ix = 4000011; ix < 4000017; ix += 2) {
addToList(-ix-1, ix, 24);
}
// particles for W_H-
// quark and T-odd quark
for(int ix = 1; ix < 6; ix += 2) {
addToList(-ix-4000000, ix+1, -34);
addToList(-ix, ix+1+4000000, -34);
}
addToList(-4000005, 8, -34);
// lepton and T-odd lepton
for(int ix = 11;ix < 17; ix += 2) {
addToList(-ix-4000000, ix+1, -34);
addToList(-ix, ix+1+4000000, -34);
}
// particles for w_h+
// quark and T-odd quark
for(int ix = 1;ix < 6;ix += 2) {
addToList(ix + 4000000, -ix - 1, 34);
addToList(ix, -ix - 4000001, 34);
}
addToList(4000005, -8, 34);
// leptons and T-odd lepton
for(int ix = 11; ix < 17; ix += 2) {
addToList(-ix - 4000001, ix, 34);
addToList(-ix - 1, ix + 4000000, 34);
}
ThePEG::Helicity::FFVVertex::doinit();
Ptr<CKMBase>::transient_pointer CKM = generator()->standardModel()->CKM();
// cast the CKM object to the HERWIG one
ThePEG::Ptr<Herwig::StandardCKM>::transient_const_pointer
hwCKM = ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardCKM>::
transient_const_pointer>(CKM);
if(hwCKM) {
vector< vector<Complex > > CKM;
CKM = hwCKM->getUnsquaredMatrix(generator()->standardModel()->families());
for(unsigned int ix=0;ix<3;++ix) {
for(unsigned int iy=0;iy<3;++iy) {
ckm_[ix][iy]=CKM[ix][iy];
}
}
}
else {
throw InitException() << "Must have access to the Herwig::StandardCKM object"
<< "for the CKM matrix in LHTPFFWVertex::doinit()"
<< Exception::runerror;
}
// model
cLHTPModelPtr model =
dynamic_ptr_cast<cLHTPModelPtr>(generator()->standardModel());
if(!model) throw InitException() << "Must be using the LHTPModel "
<< " in LHTPFFWVertex::doinit()"
<< Exception::runerror;
sL_ = model->sinThetaL();
cL_ = model->cosThetaL();
}
LHTPFFWVertex::LHTPFFWVertex()
: sL_(0.), cL_(1.), ckm_(3,vector<Complex>(3,0.0)),
coupLast_(0.),q2Last_(ZERO) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
// coupling for FFW vertex
void LHTPFFWVertex::setCoupling(Energy2 q2, tcPDPtr a,
tcPDPtr b, tcPDPtr c) {
// first the overall normalisation
if(q2!=q2Last_) {
coupLast_ = -sqrt(0.5)*weakCoupling(q2);
q2Last_ = q2;
}
norm(coupLast_);
long ia(abs(a->id())),ib(abs(b->id()));
// SM W boson
if(abs(c->id())==ParticleID::Wplus) {
// quarks
if(ia >= 1 && ia <= 8 && ib >= 1 && ib <= 8 ) {
int iu,id;
// up type first
if(ia % 2 == 0) {
iu = ia/2;
id = (ib+1)/2;
}
// down type first
else {
iu = ib/2;
id = (ia+1)/2;
}
if(iu==4) iu=3;
assert( iu>=1 && iu<=3 && id>=1 && id<=3);
if ( ia==6 || ib==6 ) left(ckm_[iu-1][id-1]*cL_);
else if ( ia==8 || ib==8 ) left(ckm_[iu-1][id-1]*sL_);
else left(ckm_[iu-1][id-1] );
right(0.);
}
// leptons
else if( ia >= 11 && ia <= 16) {
left(1.);
right(0.);
}
else {
left (1.);
right(1.);
}
}
else {
if(ia==6||ib==6) left(-cL_);
else if(ia==8||ib==8) left(-sL_);
else left(-1. );
right(0.);
}
}
diff --git a/Models/LHTP/LHTPFFZVertex.cc b/Models/LHTP/LHTPFFZVertex.cc
--- a/Models/LHTP/LHTPFFZVertex.cc
+++ b/Models/LHTP/LHTPFFZVertex.cc
@@ -1,232 +1,233 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPFFZVertex class.
//
#include "LHTPFFZVertex.h"
#include "LHTPModel.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
IBPtr LHTPFFZVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHTPFFZVertex::fullclone() const {
return new_ptr(*this);
}
void LHTPFFZVertex::persistentOutput(PersistentOStream & os) const {
os << gl_ << gr_ << tl_ << tr_ << coupd_ << coupu_ << coupe_ << coupnu_
<< sL_ << cL_ << sR_ << cR_;
}
void LHTPFFZVertex::persistentInput(PersistentIStream & is, int) {
is >> gl_ >> gr_ >> tl_ >> tr_ >> coupd_ >> coupu_ >> coupe_ >> coupnu_
>> sL_ >> cL_ >> sR_ >> cR_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHTPFFZVertex,FFVVertex>
describeHerwigLHTPFFZVertex("Herwig::LHTPFFZVertex", "HwLHTPModel.so");
void LHTPFFZVertex::Init() {
static ClassDocumentation<LHTPFFZVertex> documentation
("The LHTPFFZVertex class implements the couplings of "
"the fermions to the Z boson and its heavy partner in the"
" Little Higgs model with T-parity.");
}
LHTPFFZVertex::LHTPFFZVertex()
: gl_(37,0.0), gr_(37,0.0), tl_( 6,0.0), tr_( 6,0.0),
coupd_(0.), coupu_(0.), coupe_(0.), coupnu_(0.),
sL_(0.), cL_(1.), sR_(0.), cR_(1.),
coupLast_(0.0), q2Last_(0.*GeV2) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void LHTPFFZVertex::doinit() {
// Z
// the quarks
for(int ix = 1; ix < 7; ++ix) {
addToList(-ix, ix, 23);
}
// T+T+
addToList(-8, +8, 23);
//T+t
addToList(-6, +8, 23);
addToList(-8, +6, 23);
// the leptons
for(int ix = 11; ix < 17; ++ix) {
addToList(-ix, ix, 23);
}
// the T-odd quarks
for(long ix = 4000001; ix < 4000007; ++ix) {
addToList(-ix, ix, 23);
}
addToList(-4000008, +4000008, 23);
// the T-odd leptons
for(long ix = 11;ix<17;++ix) {
addToList(-ix-4000000, ix+4000000, 23);
}
// Z_H
// the quarks
for(int ix=1;ix<7;++ix) {
addToList(-ix-4000000, ix, 33);
addToList(-ix, ix+4000000, 33);
}
addToList( -8, +4000008, 33);
addToList( 8, -4000008, 33);
addToList( -6, +4000008, 33);
addToList( 6, -4000008, 33);
// the leptons
for(int ix=11;ix<17;++ix) {
addToList(-ix-4000000, ix, 33);
addToList(-ix, ix+4000000, 33);
}
// model
cLHTPModelPtr model =
dynamic_ptr_cast<cLHTPModelPtr>(generator()->standardModel());
if(!model) throw InitException() << "Must be using the LHTPModel "
<< " in LHTPFFPVertex::doinit()"
<< Exception::runerror;
double sw = model->sin2ThetaW();
double cw = sqrt(1.-sw);
sw = sqrt(sw);
double fact = 0.25/sw/cw;
for(int ix=1;ix<4;++ix) {
// SM fermions
gl_[2*ix-1] = fact*(model->vd() + model->ad() );
gl_[2*ix ] = fact*(model->vu() + model->au() );
gl_[2*ix+9 ] = fact*(model->ve() + model->ae() );
gl_[2*ix+10] = fact*(model->vnu() + model->anu());
gr_[2*ix-1] = fact*(model->vd() - model->ad() );
gr_[2*ix ] = fact*(model->vu() - model->au() );
gr_[2*ix+9 ] = fact*(model->ve() - model->ae() );
gr_[2*ix+10] = fact*(model->vnu() - model->anu());
// T-odd fermions
gl_[2*ix-1 +20] = fact*(model->vd() + model->ad() );
gl_[2*ix +20] = fact*(model->vu() + model->au() );
gl_[2*ix+9 +20] = fact*(model->ve() + model->ae() );
gl_[2*ix+10+20] = fact*(model->vnu() + model->anu());
gr_[2*ix-1 +20] = gl_[2*ix-1 +20];
gr_[2*ix +20] = gl_[2*ix +20];
gr_[2*ix+9 +20] = gl_[2*ix+9 +20];
gr_[2*ix+10+20] = gl_[2*ix+10+20];
}
// couplngis to Z for extended top sector
tl_[0] = (0.5*sqr(model->cosThetaL())-2./3.*sqr(sw))/cw/sw;
tr_[0] = -2./3.*sw/cw;
tl_[1] = (0.5*sqr(model->sinThetaL())-2./3.*sqr(sw))/cw/sw;
tr_[1] = -2./3.*sw/cw;
tl_[2] = 0.5/sw/cw*model->sinThetaL()*model->cosThetaL();
tr_[2] = 0.;
// couplings to the Z_H of T-odd fermions
double cH = model->cosThetaH();
double sH = model->sinThetaH();
sL_ = model->sinThetaL();
cL_ = model->cosThetaL();
sR_ = model->sinThetaR();
cR_ = model->cosThetaR();
coupd_ = 0.1*(sH/cw+5.*cH/sw);
coupu_ = 0.1*(sH/cw-5.*cH/sw);
coupe_ = 0.1*(sH/cw+5.*cH/sw);
coupnu_ = 0.1*(sH/cw-5.*cH/sw);
tl_[5] = -2./3.*sw/cw;
tr_[5] = -2./3.*sw/cw;
// couplings of T-odd top to the Z_H
tl_[3] = 0.4*sH*sL_/cw;
tr_[3] = 0.4*sH*sR_/cw;
tl_[4] =-0.4*sH*cL_/cw;
tr_[4] =-0.4*sH*cR_/cw;
// base class initialisation
FFVVertex::doinit();
}
void LHTPFFZVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,tcPDPtr c) {
// first the overall normalisation
if(q2!=q2Last_) {
coupLast_ = -electroMagneticCoupling(q2);
q2Last_=q2;
}
norm(coupLast_);
// the left and right couplings
long iferm = abs(a->id());
long ianti = abs(b->id());
long ibos = c->id();
if(ibos == ParticleID::Z0) {
if(iferm == 8 || iferm == 6) {
if(iferm == 6 && ianti == 6) {
left (tl_[0]);
right(tr_[0]);
}
else if(iferm == 8 && ianti == 8) {
left (tl_[1]);
right(tr_[1]);
}
else {
left (tl_[2]);
right(tr_[2]);
}
}
else if(iferm == 4000008) {
left (tl_[5]);
right(tr_[5]);
}
else if((iferm >= 1 && iferm <= 6)|| (iferm >= 11 && iferm <= 16)) {
left (gl_[iferm]);
right(gr_[iferm]);
}
else {
iferm = (iferm % 4000000) + 20;
left (gl_[iferm]);
right(gr_[iferm]);
}
}
else if(ibos == 33) {
if(iferm>4000000) swap(iferm,ianti);
assert(iferm<4000000&&ianti>4000000);
if( iferm == 6 || iferm == 8 ) {
if (iferm==6&&ianti==4000006) {
left (cL_*coupu_);
right(0.);
}
else if(iferm==6&&ianti==4000008) {
left (tl_[3]);
right(tr_[3]);
}
else if(iferm==8&&ianti==4000006) {
left (sL_*coupu_);
right(0.);
}
else if(iferm==8&&ianti==4000008) {
left ( tl_[4]);
right( tr_[4]);
}
else
assert(false);
}
else {
right(0.);
if(iferm <= 6) {
if(iferm % 2 == 0) left( coupu_ );
else left( coupd_ );
}
else {
if(iferm % 2 == 0) left( coupnu_ );
else left( coupe_ );
}
}
}
else
assert(false);
}
diff --git a/Models/LHTP/LHTPHHHVertex.cc b/Models/LHTP/LHTPHHHVertex.cc
--- a/Models/LHTP/LHTPHHHVertex.cc
+++ b/Models/LHTP/LHTPHHHVertex.cc
@@ -1,75 +1,76 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPHHHVertex class.
//
#include "LHTPHHHVertex.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"
using namespace Herwig;
LHTPHHHVertex::LHTPHHHVertex() : ratio_(ZERO), coupLast_(0.), q2Last_(ZERO) {
orderInGem(1);
orderInGs (0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr LHTPHHHVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHTPHHHVertex::fullclone() const {
return new_ptr(*this);
}
void LHTPHHHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(ratio_,GeV);
}
void LHTPHHHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(ratio_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<LHTPHHHVertex,SSSVertex>
describeHerwigLHTPHHHVertex("Herwig::LHTPHHHVertex", "HwLHTPModel.so");
void LHTPHHHVertex::Init() {
static ClassDocumentation<LHTPHHHVertex> documentation
("The LHTPHHHVertex class implements the trilinear Higgs boson"
" self couplings in the Little Higgs model with T-parity");
}
void LHTPHHHVertex::doinit() {
addToList(25,25, 25);
addToList(25,35, 35);
addToList(25,36, 36);
addToList(25,37,-37);
SSSVertex::doinit();
ratio_ = sqr(getParticleData(ParticleID::h0)->mass())/
getParticleData(ParticleID::Wplus)->mass();
}
void LHTPHHHVertex::setCoupling(Energy2 q2,tcPDPtr part1,tcPDPtr part2,tcPDPtr) {
if(q2!=q2Last_||coupLast_==0.) {
coupLast_ = weakCoupling(q2)*ratio_*UnitRemoval::InvE;
q2Last_=q2;
}
long id = part2->id()!=ParticleID::h0 ? abs(part2->id()) : abs(part1->id());
if(id==ParticleID::h0) norm( -coupLast_);
else if(id==35) norm( 3.*coupLast_);
else if(id==36) norm( 3.*coupLast_);
else if(id==37) norm(1.5*coupLast_);
else assert(false);
}
diff --git a/Models/LHTP/LHTPWHHVertex.cc b/Models/LHTP/LHTPWHHVertex.cc
--- a/Models/LHTP/LHTPWHHVertex.cc
+++ b/Models/LHTP/LHTPWHHVertex.cc
@@ -1,201 +1,202 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPWHHVertex class.
//
#include "LHTPWHHVertex.h"
#include "LHTPModel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
LHTPWHHVertex::LHTPWHHVertex() :
coupLast_(0.), q2Last_(ZERO), coup_(11) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr LHTPWHHVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHTPWHHVertex::fullclone() const {
return new_ptr(*this);
}
void LHTPWHHVertex::persistentOutput(PersistentOStream & os) const {
os << coup_;
}
void LHTPWHHVertex::persistentInput(PersistentIStream & is, int) {
is >> coup_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHTPWHHVertex,VSSVertex>
describeHerwigLHTPWHHVertex("Herwig::LHTPWHHVertex", "HwLHTPModel.so");
void LHTPWHHVertex::Init() {
static ClassDocumentation<LHTPWHHVertex> documentation
("The LHTPWHHVertex class implements the coupling of a pair of Higgs"
" bosons to an electroweak gauge boson in the Little"
" Higgs model with T-parity.");
}
void LHTPWHHVertex::doinit() {
// photon
addToList( 22, 37,-37);
addToList( 22, 38,-38);
// Z0
addToList( 23, 37,-37);
addToList( 23, 38,-38);
addToList( 23, 35, 36);
// W+
addToList( 24, 35,-37);
addToList( 24, 36,-37);
addToList( 24, 37,-38);
// W-
addToList(-24, 35, 37);
addToList(-24, 36, 37);
addToList(-24,-37, 38);
// A_H
addToList( 32, 25, 36);
// Z_H
addToList( 33, 25, 36);
// W_H
addToList( 34, 25,-37);
addToList(-34, 25, 37);
VSSVertex::doinit();
// model
cLHTPModelPtr model =
dynamic_ptr_cast<cLHTPModelPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must be using the LHModel "
<< " in LHWWWWVertex::doinit()"
<< Exception::runerror;
double sw2(sin2ThetaW());
double sw(sqrt(sw2)),cw(sqrt(1.-sw2));
double vf(model->vev()/model->f());
coup_[ 0] = 1.;
coup_[ 1] = 2.;
coup_[ 2] =-sw/cw;
coup_[ 3] = (1.-2.*sw2)/cw/sw;
coup_[ 4] =-Complex(0.,1.)/cw/sw;
coup_[ 5] = sqrt(0.5)/sw;
coup_[ 6] = Complex(0.,1.)/sw*sqrt(0.5);
coup_[ 7] = 1./sw;
coup_[ 8] = Complex(0.,1)*sqrt(0.5)*vf/3./cw;
coup_[ 9] = Complex(0.,1)*sqrt(0.5)*vf/3./sw;
coup_[10] =-vf/6./sw;
}
void LHTPWHHVertex::setCoupling(Energy2 q2, tcPDPtr particle1,
tcPDPtr particle2, tcPDPtr particle3) {
if( q2 != q2Last_ || coupLast_==0.) {
q2Last_ = q2;
coupLast_ = electroMagneticCoupling(q2);
}
int ibos = particle1->id();
int isc1 = particle2->id();
int isc2 = particle3->id();
if(ibos==ParticleID::gamma) {
if(isc1==37)
norm(coup_[0]*coupLast_);
else if(isc1==38)
norm(coup_[1]*coupLast_);
else if(isc1==-37)
norm(-coup_[0]*coupLast_);
else if(isc1==-38)
norm(-coup_[1]*coupLast_);
else
assert(false);
}
else if(ibos==ParticleID::Z0) {
if(isc1==37)
norm(coup_[2]*coupLast_);
else if(isc1==38)
norm(coup_[3]*coupLast_);
else if(isc1==-37)
norm(-coup_[2]*coupLast_);
else if(isc1==-38)
norm(-coup_[3]*coupLast_);
else if(isc1==35)
norm(coup_[4]*coupLast_);
else if(isc2==35)
norm(-coup_[4]*coupLast_);
else
assert(false);
}
else if(ibos==ParticleID::Wplus) {
if(isc1==35)
norm(coup_[5]*coupLast_);
else if(isc1==36)
norm(coup_[6]*coupLast_);
else if(isc1==-38)
norm(-coup_[7]*coupLast_);
else if(isc2==35)
norm(-coup_[5]*coupLast_);
else if(isc2==36)
norm(-coup_[6]*coupLast_);
else if(isc2==-38)
norm( coup_[7]*coupLast_);
else
assert(false);
}
else if(ibos==ParticleID::Wminus) {
if(isc1==35)
norm(conj(coup_[5])*coupLast_);
else if(isc1==36)
norm(conj(coup_[6])*coupLast_);
else if(isc1==38)
norm(-conj(coup_[7])*coupLast_);
else if(isc2==35)
norm(-conj(coup_[5])*coupLast_);
else if(isc2==36)
norm(-conj(coup_[6])*coupLast_);
else if(isc2==38)
norm( conj(coup_[7])*coupLast_);
else
assert(false);
}
else if(ibos==32) {
if(isc1==25)
norm( coup_[8]*coupLast_);
else if(isc2==25)
norm(-coup_[8]*coupLast_);
else
assert(false);
}
else if(ibos==33) {
if(isc1==25)
norm( coup_[9]*coupLast_);
else if(isc2==25)
norm(-coup_[9]*coupLast_);
else
assert(false);
}
else if(ibos==34) {
if(isc1==25)
norm( coup_[10]*coupLast_);
else if(isc2==25)
norm(-coup_[10]*coupLast_);
else
assert(false);
}
else if(ibos==-34) {
if(isc1==25)
norm( conj(coup_[10])*coupLast_);
else if(isc2==25)
norm(-conj(coup_[10])*coupLast_);
else
assert(false);
}
else
assert(false);
}
diff --git a/Models/LHTP/LHTPWWHVertex.cc b/Models/LHTP/LHTPWWHVertex.cc
--- a/Models/LHTP/LHTPWWHVertex.cc
+++ b/Models/LHTP/LHTPWWHVertex.cc
@@ -1,188 +1,189 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPWWHVertex class.
//
#include "LHTPWWHVertex.h"
#include "LHTPModel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
IBPtr LHTPWWHVertex::clone() const {
return new_ptr(*this);
}
IBPtr LHTPWWHVertex::fullclone() const {
return new_ptr(*this);
}
void LHTPWWHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(coup_,GeV);
}
void LHTPWWHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(coup_,GeV);
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHTPWWHVertex,VVSVertex>
describeHerwigLHTPWWHVertex("Herwig::LHTPWWHVertex", "HwLHTPModel.so");
void LHTPWWHVertex::Init() {
static ClassDocumentation<LHTPWWHVertex> documentation
("The LHTPWWHVertex class implements the coupling of two electroweak"
" gauge bosons to a Higgs boson in the Little Higgs Model with T-Parity"
"including the additional heavy photon, Z and W bosons and the "
"triplet Higgs bosons.");
}
LHTPWWHVertex::LHTPWWHVertex() : coupLast_(0.), q2Last_(0.*GeV2) {
// order in the couplings
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void LHTPWWHVertex::doinit() {
// W_L W_L H
addToList( 24, -24, 25);
// Z_L Z_L H
addToList( 23, 23, 25);
// W_H W_H H
addToList( 34, -34, 25);
// Z_H Z_H H
addToList( 33, 33, 25);
// A_H A_H H
addToList( 32, 32, 25);
// Z_H A_H H
addToList( 33, 32, 25);
// Z_L Z_H Phi0
addToList( 23, 33, 35);
// A_H Z_L Phi0
addToList( 32, 23, 35);
// W_L W_H PhiP
addToList( 24, -34, 36);
addToList( 34, -24, 36);
// W_H Z_L Phi+/-
addToList( 34, 23, -37);
addToList( -34, 23, 37);
// W_L A_H Phi+/-
addToList( 24, 32, -37);
addToList( -24, 32, 37);
// W_L Z_H Phi+/-
addToList( 24, 33, -37);
addToList( -24, 33, 37);
// W_H A_L Phi+/-
addToList( 34, 22, -37);
addToList( -34, 22, 37);
// W_L W_H Phi --/++
addToList( 24, 34, -38);
addToList( -24, -34, 38);
// model
cLHTPModelPtr model =
dynamic_ptr_cast<cLHTPModelPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must be using the LHTPModel "
<< " in LHTPWWHVertex::doinit()"
<< Exception::runerror;
// base class
VVSVertex::doinit();
// calculate the couplings for the different combinations of particles
Energy fact = 0.5*model->vev()/model->sin2ThetaW();
double sw(sqrt(model->sin2ThetaW())),cw(sqrt(1.-model->sin2ThetaW()));
double vf(model->vev()/model->f());
double r2(sqrt(2.));
coup_.resize(14);
// H
coup_[ 0] = fact *(1.-sqr(vf)/3.);
coup_[ 1] = fact/sqr(cw)*(1.-sqr(vf)/3.);
coup_[ 2] =-fact;
coup_[ 3] =-fact;
coup_[ 4] =-fact*sqr(sw/cw);
coup_[ 5] =-fact/cw*sw;
// PhiP
coup_[ 6] = r2*fact*vf/3.;
// Phi0
coup_[ 7] =-fact*vf/r2/cw;
coup_[ 8] = fact*vf/r2*sw/sqr(cw);
// Phi+
coup_[ 9] = fact*vf/6./cw*(1.+2.*sqr(sw));
coup_[10] = fact*vf*sw/cw*0.5;
coup_[11] = fact*vf*5./6.;
coup_[12] =-fact*vf*sw/3.;
// Phi++
coup_[13] =-fact*vf;
}
void LHTPWWHVertex::setCoupling(Energy2 q2,tcPDPtr a,
tcPDPtr b, tcPDPtr c) {
// first the overall normalisation
if(q2!=q2Last_) {
coupLast_ = sqr(electroMagneticCoupling(q2));
q2Last_=q2;
}
long ih = abs(c->id());
long ibos[2]={abs(a->id()),abs(b->id())};
if(ih == 25) {
if( ibos[0] == 24 && ibos[1] == 24)
norm(UnitRemoval::InvE *coupLast_*coup_[0]);
else if( ibos[0] == 23 && ibos[1] == 23 )
norm(UnitRemoval::InvE *coupLast_*coup_[1]);
else if( ibos[0] == 34 && ibos[1] == 34 )
norm(UnitRemoval::InvE *coupLast_*coup_[2]);
else if( ibos[0] == 33 && ibos[1] == 33 )
norm(UnitRemoval::InvE *coupLast_*coup_[3]);
else if( ibos[0] == 32 && ibos[1] == 32 )
norm(UnitRemoval::InvE *coupLast_*coup_[4]);
else if((ibos[0] == 33 && ibos[1] == 32) ||
(ibos[0] == 32 && ibos[1] == 33) )
norm(UnitRemoval::InvE *coupLast_*coup_[5]);
else
assert(false);
}
else if(ih == 36) {
if( a->id() == 34 || b->id() == 34)
norm( Complex(0.,1.)*UnitRemoval::InvE *coupLast_*coup_[6]);
else
norm(-Complex(0.,1.)*UnitRemoval::InvE *coupLast_*coup_[6]);
}
else if(ih == 35) {
if((ibos[0] == 23 && ibos[1] == 33) ||
(ibos[0] == 33 && ibos[1] == 23) )
norm(UnitRemoval::InvE *coupLast_*coup_[7]);
else if((ibos[0] == 23 && ibos[1] == 32) ||
(ibos[0] == 32 && ibos[1] == 23) )
norm(UnitRemoval::InvE *coupLast_*coup_[8]);
else
assert(false);
}
else if(ih == 37) {
if((ibos[0] == 34 && ibos[1] == 23) ||
(ibos[0] == 23 && ibos[1] == 34) ) {
norm(UnitRemoval::InvE *coupLast_*coup_[ 9]);
}
else if((ibos[0] == 24 && ibos[1] == 32) ||
(ibos[0] == 32 && ibos[1] == 24) )
norm(UnitRemoval::InvE *coupLast_*coup_[10]);
else if((ibos[0] == 24 && ibos[1] == 33) ||
(ibos[0] == 33 && ibos[1] == 24) )
norm(UnitRemoval::InvE *coupLast_*coup_[11]);
else if((ibos[0] == 34 && ibos[1] == 22) ||
(ibos[0] == 22 && ibos[1] == 34) )
norm(UnitRemoval::InvE *coupLast_*coup_[12]);
else
assert(false);
}
else if(ih == 38) {
norm(UnitRemoval::InvE *coupLast_*coup_[13]);
}
else
assert(false);
}
diff --git a/Models/LHTP/LHTPWWWVertex.cc b/Models/LHTP/LHTPWWWVertex.cc
--- a/Models/LHTP/LHTPWWWVertex.cc
+++ b/Models/LHTP/LHTPWWWVertex.cc
@@ -1,140 +1,141 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LHTPWWWVertex class.
//
#include "LHTPWWWVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "LHTPModel.h"
using namespace Herwig;
LHTPWWWVertex::LHTPWWWVertex() : coupLast_(0.), q2Last_(ZERO),
couplings_(3 ,0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void LHTPWWWVertex::persistentOutput(PersistentOStream & os) const {
os << couplings_;
}
void LHTPWWWVertex::persistentInput(PersistentIStream & is, int) {
is >> couplings_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<LHTPWWWVertex,VVVVertex>
describeHerwigLHTPWWWVertex("Herwig::LHTPWWWVertex", "HwLHTPModel.so");
void LHTPWWWVertex::Init() {
static ClassDocumentation<LHTPWWWVertex> documentation
("The LHTPWWWVertex class implements the coupling of three "
"electroweak gauge bosons and their heavy partners in the "
"Little Higgs model with T-parity.");
}
void LHTPWWWVertex::doinit() {
//SM interactions
addToList( 24, -24, 22);
addToList( 24, -24, 23);
//LHTP
//W_H W_H A_L
addToList( 34, -34, 22);
//W_H W_H Z_L
addToList( 34, -34, 23);
//W_H W_L A_H
addToList( 34, -24, 32);
addToList( 24, -34, 32);
//W_H W_L Z_H
addToList( 34, -24, 33);
addToList( 24, -34, 33);
VVVVertex::doinit();
cLHTPModelPtr model =
dynamic_ptr_cast<cLHTPModelPtr>(generator()->standardModel());
if( !model )
throw InitException()
<< "LHTPWWWVertex::doinit() - Model pointer must be of LHTPModel"
<< "type, cannot continue without this."
<< Exception::abortnow;
double sw(sqrt(model->sin2ThetaW()));
double cw(sqrt(1. - model->sin2ThetaW()));
//W W Z
couplings_[0] = cw/sw;
//W_L W_H A_H
couplings_[1] = model->sinThetaH()/sw;
//W_L W_H Z_H
couplings_[2] = 1./sw;
}
void LHTPWWWVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,tcPDPtr c) {
if(q2 != q2Last_) {
coupLast_ = electroMagneticCoupling(q2);
q2Last_ = q2;
}
int ida=a->id();
int idb=b->id();
int idc=c->id();
// get the PDG code for the neutral boson
long boson(0);
if(!a->charged()) {
boson = ida;
ida = 22;
}
else if(abs(ida) !=ParticleID::Wplus) {
ida = ida > 0 ? 24 : -24;
}
if(!b->charged()) {
boson = idb;
idb = 22;
}
else if(abs(idb) !=ParticleID::Wplus) {
idb = idb > 0 ? 24 : -24;
}
if(!c->charged()) {
boson = idc;
idc = 22;
}
else if(abs(idc) !=ParticleID::Wplus) {
idc = idc > 0 ? 24 : -24;
}
assert( boson ==22 || boson==23 || boson==32 || boson==33);
// get the prefactor
double pre(0.);
switch (boson) {
case 22:
pre = 1.;
break;
case 23:
pre = couplings_[0];
break;
case 32:
pre = couplings_[1];
break;
case 33:
pre = couplings_[2];
break;
default:
assert(false);
};
// W- W+ photon and cylic perms
if((ida==-24 && idb== 24 && idc== 22) ||
(ida== 22 && idb==-24 && idc== 24) ||
(ida== 24 && idb== 22 && idc==-24) ) norm( coupLast_*pre);
// W+ W- photon (anticylic perms of above)
else if((ida== 24 && idb==-24 && idc== 22) ||
(ida== 22 && idb== 24 && idc==-24) ||
(ida==-24 && idb== 22 && idc== 24) ) norm(-coupLast_*pre);
else
throw Helicity::HelicityConsistencyError()
<< "LHTPWWWVertex::setCoupling - Incorrect particles in LHTPWWWVertex. "
<< a->id() << " " << b->id() << " " << c->id() << '\n'
<< Exception::runerror;
}
diff --git a/Models/Leptoquarks/LeptoquarkModelSLQFFVertex.cc b/Models/Leptoquarks/LeptoquarkModelSLQFFVertex.cc
--- a/Models/Leptoquarks/LeptoquarkModelSLQFFVertex.cc
+++ b/Models/Leptoquarks/LeptoquarkModelSLQFFVertex.cc
@@ -1,346 +1,347 @@
// -*- C++ -*-
//
// LeptoquarkModelSLQFFVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LeptoquarkModelSLQFFVertex class.
//
#include "LeptoquarkModelSLQFFVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Config/Constants.h"
using namespace Herwig;
IBPtr LeptoquarkModelSLQFFVertex::clone() const {
return new_ptr(*this);
}
IBPtr LeptoquarkModelSLQFFVertex::fullclone() const {
return new_ptr(*this);
}
LeptoquarkModelSLQFFVertex::LeptoquarkModelSLQFFVertex() {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void LeptoquarkModelSLQFFVertex::doinit() {
//S0
addToList( 15, 6,-9911561);
addToList(-15,-6, 9911561);
addToList(-16,-5, 9911561);
addToList( 16, 5,-9911561);
//~S0
addToList(-15,-5, 9921551);
addToList( 15, 5,-9921551);
//S1 triplet
//S1p
addToList(-15,-5, 9931551);
addToList( 15, 5,-9931551);
//S1z
addToList(-15,-6, 9931561);
addToList( 15, 6,-9931561);
addToList(-16,-5, 9931561);
addToList( 16, 5,-9931561);
//S1m
addToList(-16,-6, 9931661);
addToList( 16, 6,-9931661);
//S1/2 doublet
addToList( 15,-6, 9941561);
addToList(-15, 6,-9941561);
addToList(-15, 5,-9941551);
addToList(-16, 6,-9941551);
addToList( 15,-5, 9941551);
addToList( 16,-6, 9941551);
//S1/2 tilde doublet
addToList( 5,-16,-9951651);
addToList(-5, 16, 9951651);
addToList(-5, 15, 9951551);
addToList( 5,-15,-9951551);
//dS0
addToList( 15,-5, 9961551);
addToList(-15, 5,-9961551);
addToList( 16,-6, 9961551);
addToList(-16, 6,-9961551);
//~dS0
addToList( 15,-6, 9971561);
addToList(-15, 6,-9971561);
//dS1 triplet
//dS1p
addToList( 15,-6, 9981561);
addToList(-15, 6,-9981561);
//dS1z
addToList( 16,-6, 9981551);
addToList(-16, 6,-9981551);
addToList( 15,-5, 9981551);
addToList(-15, 5,-9981551);
//dS1m
addToList( 16,-5, 9981651);
addToList(-16, 5,-9981651);
//dS1/2 doublet
addToList(-15,-5, 9991551);
addToList( 15, 5,-9991551);
addToList(-15,-6, 9991561);
addToList( 15, 6,-9991561);
addToList(-16,-5, 9991561);
addToList( 16, 5,-9991561);
//dS1/2 tilde doublet
addToList(-15,-6, 9901561);
addToList( 15, 6,-9901561);
addToList(-16,-6, 9901661);
addToList( 16, 6,-9901661);
_theModel = generator()->standardModel();
tcHwLeptoquarkPtr hwLeptoquark=dynamic_ptr_cast<tcHwLeptoquarkPtr>(_theModel);
if(hwLeptoquark){
_CFF=hwLeptoquark->cfermion();
_cL0 =hwLeptoquark->cleft();
_cR0 =hwLeptoquark->cright();
_cR0t = hwLeptoquark->crighttilde();
_cL1 =hwLeptoquark->cleft1();
_cL12 =hwLeptoquark->cleft12();
_cR12 =hwLeptoquark->cright12();
_cL12t =hwLeptoquark->cleft12tilde();
_derivscale = hwLeptoquark->fscale();
_dcL0 =hwLeptoquark->dcleft();
_dcR0 =hwLeptoquark->dcright();
_dcR0t = hwLeptoquark->dcrighttilde();
_dcL1 =hwLeptoquark->dcleft1();
_dcL12 =hwLeptoquark->dcleft12();
_dcR12 =hwLeptoquark->dcright12();
_dcL12t =hwLeptoquark->dcleft12tilde();
}
FFSVertex::doinit();
}
void LeptoquarkModelSLQFFVertex::persistentOutput(PersistentOStream & os) const {
os << _CFF << _cL0 << _cR0 << _cR0t
<< _cL1 << _cL12 << _cR12 << _cL12t
<< _dcL0 << _dcR0 << _dcR0t
<< _dcL1 << _dcL12 << _dcR12 << _dcL12t
<< ounit(_derivscale,GeV);
}
void LeptoquarkModelSLQFFVertex::persistentInput(PersistentIStream & is, int) {
is >> _CFF >> _cL0 >> _cR0 >> _cR0t
>> _cL1 >> _cL12 >> _cR12 >> _cL12t
>>_dcL0 >> _dcR0 >> _dcR0t
>> _dcL1 >> _dcL12 >> _dcR12 >> _dcL12t
>> iunit(_derivscale,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<LeptoquarkModelSLQFFVertex,FFSVertex>
describeHerwigLeptoquarkModelSLQFFVertex("Herwig::LeptoquarkModelSLQFFVertex", "Herwig.so");
void LeptoquarkModelSLQFFVertex::Init() {
static ClassDocumentation<LeptoquarkModelSLQFFVertex> documentation
("The LeptoquarkModelSLQFFVertex class is the implementation"
" of the helicity amplitude calculation of the Leptoquark"
" quark-lepton vertex.");
}
void LeptoquarkModelSLQFFVertex::setCoupling(Energy2,tcPDPtr aa ,tcPDPtr bb, tcPDPtr cc) {
long isc(cc->id()), ism(aa->id()),
ichg(bb->id());
long lqid = isc;
long smid_1 = ism;
long smid_2 = ichg;
if(abs(lqid) < 9900000) {
lqid = ism;
smid_1 = ichg;
smid_2 = isc;
}
if(abs(lqid) < 9900000) {
smid_1 = ism;
smid_2 = isc;
}
if( abs(smid_1) > abs(smid_2) ) { swap(smid_1, smid_2); }
const Energy denom = sqrt(2.) * _derivscale;
const double mtop = getParticleData(ParticleID::t)->mass() / denom;
const double mbot = getParticleData(ParticleID::b)->mass() / denom;
const double mtau = getParticleData(ParticleID::tauminus)->mass() / denom;
//set the couplings to left and right
//S0
if( abs(isc) == 9911561 || abs(ism) == 9911561 || abs(ichg) == 9911561 ) {
if(abs(isc) == 5 || abs(ism) == 5 || abs(ichg) == 5) {
_cL = -_cL0; _cR = Complex(0.);
}
if(abs(isc) == 6 || abs(ism) == 6 || abs(ichg) == 6) {
_cL = _cL0;
_cR = _cR0;
}
}
//~S0
if( abs(isc) == 9921551 || abs(ism) == 9921551 || abs(ichg) == 9921551 ) {
_cL = Complex(0.); _cR = _cR0t;
}
//S1 triplet
//Q = + 4/3
if( abs(isc) == 9931551 || abs(ism) == 9931551 || abs(ichg) == 9931551 ) {
_cL = sqrt(2.)* _cL1; _cR = Complex(0.);
}
//Q = + 1/3
if( abs(isc) == 9931561 || abs(ism) == 9931561 || abs(ichg) == 9931561 ) {
_cL = - _cL1; _cR = Complex(0.);
}
//Q = - 2/3
if( abs(isc) == 9931661 || abs(ism) == 9931661 || abs(ichg) == 9931661 ) {
_cL = sqrt(2.) * _cL1; _cR = Complex(0.);
}
//S1/2 doublet
//Q = + 5/3
if( abs(isc) == 9941561 || abs(ism) == 9941561 || abs(ichg) == 9941561 ) {
_cR = _cL12; _cL = _cR12;
}
//Q = + 2/3
if( abs(isc) == 9941551 || abs(ism) == 9941551 || abs(ichg) == 9941551 ) {
if(abs(isc) == 5 || abs(ism) == 5 || abs(ichg) == 5) {
_cR = Complex(0.); _cL = - _cR12;
}
if(abs(isc) == 6 || abs(ism) == 6 || abs(ichg) == 6) {
_cL = Complex(0.); _cR = _cL12;
}
}
//S1/2 tilde doublet
//Q = + 2/3
if( abs(isc) == 9951551 || abs(ism) == 9951551 || abs(ichg) == 9951551 ) {
_cR = _cL12t; _cL = Complex(0.);
}
//Q = - 1/3
if( abs(isc) == 9951651 || abs(ism) == 9951651 || abs(ichg) == 9951651 ) {
_cR = _cL12t; _cL = Complex(0.);
}
//dS0
if( abs(isc) == 9961551 || abs(ism) == 9961551 || abs(ichg) == 9961551) {
if(abs(isc) == 5 || abs(ism) == 5 || abs(ichg) == 5) {
_cR = _dcL0 * mbot +_dcR0 * mtau;
_cL = _dcR0 * mbot + _dcL0 * mtau;
}
if(abs(isc) == 6 || abs(ism) == 6 || abs(ichg) == 6) {
_cR = _dcL0 * mtop;
_cL = Complex(0.);
}
}
//d~S0
if( abs(isc) == 9971561 || abs(ism) == 9971561 || abs(ichg) == 9971561) {
_cR = _dcR0t * mtau;
_cL = _dcR0t * mtop;
}
//dS1 triplet
if( abs(isc) == 9981561 || abs(ism) == 9981561 || abs(ichg) == 9981561) {
_cR = sqrt(2.) * _dcL1 * mtop;
_cL = sqrt(2.) * _dcL1 * mtau;
}
if( abs(isc) == 9981551 || abs(ism) == 9981551 || abs(ichg) == 9981551) {
if(abs(isc) == 5 || abs(ism) == 5 || abs(ichg) == 5) {
_cR = -_dcL1 * mbot;
_cL = -_dcL1 * mtau;
}
if(abs(isc) == 6 || abs(ism) == 6 || abs(ichg) == 6) {
_cR = _dcL1 * mtop;
_cL = Complex(0.);
}
}
if( abs(isc) == 9981651 || abs(ism) == 9981651 || abs(ichg) == 9981651) {
_cL = sqrt(2.) * _dcL1 * mbot;
_cR = Complex(0.);
}
//dS1/2 doublet
if( abs(isc) == 9991551 || abs(ism) == 9991551 || abs(ichg) == 9991551 ) {
_cL = _dcL12 * mbot + _dcR12 * mtau;
_cR = _dcR12 * mbot + _dcL12 * mtau;
}
if( abs(isc) == 9991561 || abs(ism) == 9991561 || abs(ichg) == 9991561 ) {
if(abs(isc) == 6 || abs(ism) == 6 || abs(ichg) == 6) {
_cL = _dcR12 * mtau;
_cR = _dcR12 * mtop;
}
if(abs(isc) == 5 || abs(ism) == 5 || abs(ichg) == 5) {
_cL = _dcL12 * mbot;
}
}
//dS1/2 tilde doublet
if( abs(isc) == 9901561 || abs(ism) == 9901561 || abs(ichg) == 9901561 ) {
_cL = _dcL12t * mtop;
_cR = _dcL12t * mtau;
}
if( abs(isc) == 9901661 || abs(ism) == 9901661 || abs(ichg) == 9901661 ) {
_cL = _dcL12t * mtop;
_cR = Complex(0.);
}
if(smid_1 > 0) {
left(conj(_cR));
right(conj(_cL));
}
else {
left(_cL);
right(_cR);
}
norm(_CFF);
}
diff --git a/Models/Leptoquarks/LeptoquarkModelSLQSLQGGVertex.cc b/Models/Leptoquarks/LeptoquarkModelSLQSLQGGVertex.cc
--- a/Models/Leptoquarks/LeptoquarkModelSLQSLQGGVertex.cc
+++ b/Models/Leptoquarks/LeptoquarkModelSLQSLQGGVertex.cc
@@ -1,71 +1,72 @@
// -*- C++ -*-
//
// LeptoquarkModelSLQSLQGGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LeptoquarkModelSLQSLQGGVertex class.
//
#include "LeptoquarkModelSLQSLQGGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
using namespace Herwig;
using namespace ThePEG;
LeptoquarkModelSLQSLQGGVertex::LeptoquarkModelSLQSLQGGVertex() : q2last_(ZERO),
couplast_(0.) {
orderInGs(2);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TTFUNDS);
}
void LeptoquarkModelSLQSLQGGVertex::doinit() {
addToList(21,21,9941551,-9941551);
addToList(21,21,9911561,-9911561);
addToList(21,21,9921551,-9921551);
addToList(21,21,9931561,-9931561);
addToList(21,21,9931551,-9931551);
addToList(21,21,9931661,-9931661);
addToList(21,21,9941561,-9941561);
addToList(21,21,9951551,-9951551);
addToList(21,21,9951651,-9951651);
addToList(21,21,9961551,-9961551);
addToList(21,21,9971561,-9971561);
addToList(21,21,9981561,-9981561);
addToList(21,21,9981551,-9981551);
addToList(21,21,9981651,-9981651);
addToList(21,21,9991551,-9991551);
addToList(21,21,9991561,-9991561);
addToList(21,21,9901561,-9901561);
addToList(21,21,9901661,-9901661);
VVSSVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<LeptoquarkModelSLQSLQGGVertex,VVSSVertex>
describeHerwigLeptoquarkModelSLQSLQGGVertex("Herwig::LeptoquarkModelSLQSLQGGVertex", "HwLeptoquarkModel.so");
void LeptoquarkModelSLQSLQGGVertex::Init() {
static ClassDocumentation<LeptoquarkModelSLQSLQGGVertex> documentation
("The LeptoquarkModelSLQSLQGGVertex class is the implementation of"
" the LeptoquarkModel scalar LQ-scalar LQ-gluon-gluon vertex");
}
void LeptoquarkModelSLQSLQGGVertex::setCoupling(Energy2 q2,tcPDPtr ,tcPDPtr ,tcPDPtr, tcPDPtr ) {
if(q2 != q2last_ || couplast_ == 0.) {
couplast_ = sqr(strongCoupling(q2));
q2last_ = q2;
}
norm(couplast_);
}
diff --git a/Models/Leptoquarks/LeptoquarkModelSLQSLQGVertex.cc b/Models/Leptoquarks/LeptoquarkModelSLQSLQGVertex.cc
--- a/Models/Leptoquarks/LeptoquarkModelSLQSLQGVertex.cc
+++ b/Models/Leptoquarks/LeptoquarkModelSLQSLQGVertex.cc
@@ -1,73 +1,74 @@
// -*- C++ -*-
//
// LeptoquarkModelSLQSLQGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the LeptoquarkModelSLQSLQGVertex class.
//
#include "LeptoquarkModelSLQSLQGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
LeptoquarkModelSLQSLQGVertex::LeptoquarkModelSLQSLQGVertex() : q2last_(ZERO),
couplast_(0.) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TFUND);
}
void LeptoquarkModelSLQSLQGVertex::doinit() {
addToList(21,9941551,-9941551);
addToList(21,9911561,-9911561);
addToList(21,9921551,-9921551);
addToList(21,9931561,-9931561);
addToList(21,9931551,-9931551);
addToList(21,9931661,-9931661);
addToList(21,9941561,-9941561);
addToList(21,9951551,-9951551);
addToList(21,9951651,-9951651);
addToList(21,9961551,-9961551);
addToList(21,9971561,-9971561);
addToList(21,9981561,-9981561);
addToList(21,9981551,-9981551);
addToList(21,9981651,-9981651);
addToList(21,9991551,-9991551);
addToList(21,9991561,-9991561);
addToList(21,9901561,-9901561);
addToList(21,9901661,-9901661);
VSSVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<LeptoquarkModelSLQSLQGVertex,VSSVertex>
describeHerwigLeptoquarkModelSLQSLQGVertex("Herwig::LeptoquarkModelSLQSLQGVertex", "HwLeptoquarkModel.so");
void LeptoquarkModelSLQSLQGVertex::Init() {
static ClassDocumentation<LeptoquarkModelSLQSLQGVertex> documentation
("The LeptoquarkModelSLQSLQGVertex class is the implementation of"
" the LeptoquarkModel scalar LQ-scalar LQ-gluon vertex");
}
void LeptoquarkModelSLQSLQGVertex::setCoupling(Energy2 q2,tcPDPtr ,tcPDPtr p2,tcPDPtr ) {
if(q2 != q2last_ || couplast_ == 0.) {
couplast_ = strongCoupling(q2);
q2last_ = q2;
}
if(p2->id()<0)
norm( couplast_);
else
norm(-couplast_);
}
diff --git a/Models/Makefile.am b/Models/Makefile.am
--- a/Models/Makefile.am
+++ b/Models/Makefile.am
@@ -1,181 +1,181 @@
SUBDIRS = RSModel StandardModel General Susy UED Zprime \
Transplanckian ADD Leptoquarks Sextet TTbAsymm \
LH LHTP Feynrules
noinst_LTLIBRARIES = libHwStandardModel.la
nodist_libHwStandardModel_la_SOURCES = \
StandardModel/SM__all.cc
libHwStandardModel_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/StandardModel
noinst_LTLIBRARIES += libHwModelGenerator.la
nodist_libHwModelGenerator_la_SOURCES = \
General/ModelGenerator__all.cc
libHwModelGenerator_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/General
if WANT_BSM
pkglib_LTLIBRARIES = \
HwRSModel.la \
HwUED.la \
HwSusy.la \
HwNMSSM.la \
HwRPV.la \
HwZprimeModel.la \
HwTransplanck.la \
HwADDModel.la \
HwLeptoquarkModel.la \
HwSextetModel.la \
HwTTbAModel.la \
HwLHModel.la \
HwLHTPModel.la
endif
#############
HwRSModel_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 10:0:0
HwRSModel_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/RSModel
nodist_HwRSModel_la_SOURCES = \
RSModel/RS__all.cc
#############
HwUED_la_LDFLAGS = \
-$(AM_LDFLAGS) -module -version-info 10:0:0
+$(AM_LDFLAGS) -module -version-info 10:1:0
HwUED_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/UED
nodist_HwUED_la_SOURCES = \
UED/UED__all.cc
#############
HwSusy_la_LDFLAGS = \
-$(AM_LDFLAGS) -module -version-info 13:0:0
+$(AM_LDFLAGS) -module -version-info 13:1:0
HwSusy_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/Susy
nodist_HwSusy_la_SOURCES = \
Susy/Susy__all.cc
#############
HwNMSSM_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 5:0:0
HwNMSSM_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/Susy/NMSSM
nodist_HwNMSSM_la_SOURCES = \
Susy/NMSSM/NMSSM__all.cc
#############
HwRPV_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 3:0:0
HwRPV_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/Susy/RPV
nodist_HwRPV_la_SOURCES = \
Susy/RPV/RPV__all.cc
#############
HwZprimeModel_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 3:0:0
HwZprimeModel_la_SOURCES = \
Zprime/ZprimeModel.cc Zprime/ZprimeModelZPQQVertex.cc
#############
HwTransplanck_la_LDFLAGS = \
-$(AM_LDFLAGS) -module -version-info 4:0:0
+$(AM_LDFLAGS) -module -version-info 4:1:0
HwTransplanck_la_SOURCES = \
Transplanckian/METRP2to2.cc
#############
HwADDModel_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 4:0:0
HwADDModel_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/ADD
nodist_HwADDModel_la_SOURCES = \
ADD/ADD__all.cc
#############
HwLeptoquarkModel_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 5:0:0
HwLeptoquarkModel_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/Leptoquarks
nodist_HwLeptoquarkModel_la_SOURCES = \
Leptoquarks/Leptoquark__all.cc
#############
HwSextetModel_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 3:0:0
HwSextetModel_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/Sextet
nodist_HwSextetModel_la_SOURCES = \
Sextet/Sextet__all.cc
#############
HwTTbAModel_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 3:0:0
HwTTbAModel_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/TTbAsymm
nodist_HwTTbAModel_la_SOURCES = \
TTbAsymm/TTbA__all.cc
#############
HwLHModel_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 5:0:0
HwLHModel_la_CPPFLAGS = \
$(AM_CPPFLAGS) -I$(srcdir)/LH
nodist_HwLHModel_la_SOURCES = \
LH/LH__all.cc
#############
HwLHTPModel_la_LDFLAGS = \
$(AM_LDFLAGS) -module -version-info 5:0:0
HwLHTPModel_la_LIBADD = \
$(GSLLIBS)
HwLHTPModel_la_CPPFLAGS = \
$(AM_CPPFLAGS) $(GSLINCLUDE) -I$(srcdir)/LHTP
nodist_HwLHTPModel_la_SOURCES = \
LHTP/LHTP__all.cc
#############
diff --git a/Models/RSModel/RSModelFFGGRVertex.cc b/Models/RSModel/RSModelFFGGRVertex.cc
--- a/Models/RSModel/RSModelFFGGRVertex.cc
+++ b/Models/RSModel/RSModelFFGGRVertex.cc
@@ -1,80 +1,81 @@
// -*- C++ -*-
//
// RSModelFFGGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RSModelFFGGRVertex class.
//
#include "RSModelFFGGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
RSModelFFGGRVertex::RSModelFFGGRVertex()
: couplast_(0.), q2last_(ZERO), kappa_(ZERO) {
orderInGem(1);
orderInGs (1);
+ colourStructure(ColourStructure::SU3TFUND);
}
void RSModelFFGGRVertex::doinit() {
for(int ix=1;ix<7;++ix) {
addToList(-ix,ix,21,39);
}
FFVTVertex::doinit();
tcHwRSPtr hwRS=dynamic_ptr_cast<tcHwRSPtr>(generator()->standardModel());
if(!hwRS) throw Exception()
<< "Must have RSModel in RSModelFFGGRVertex::doinit()"
<< Exception::runerror;
kappa_ = 2./hwRS->lambda_pi();
}
void RSModelFFGGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV);
}
void RSModelFFGGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RSModelFFGGRVertex,FFVTVertex>
describeHerwigRSModelFFGGRVertex("Herwig::RSModelFFGGRVertex", "HwRSModel.so");
void RSModelFFGGRVertex::Init() {
static ClassDocumentation<RSModelFFGGRVertex> documentation
("The RSModelFFGGRVertexxs class is the implementation"
" of the two fermion vector coupling for the RS model.");
}
// FFGGR coupling
#ifndef NDEBUG
void RSModelFFGGRVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr,
tcPDPtr cc, tcPDPtr) {
#else
void RSModelFFGGRVertex::setCoupling(Energy2 q2,tcPDPtr,tcPDPtr,
tcPDPtr, tcPDPtr) {
#endif
// work out the particles
assert(cc->id()==ParticleID::g && abs(aa->id()) <=6 );
// overall factor
if(q2last_ != q2 || couplast_ == 0. ) {
couplast_ = strongCoupling(q2);
q2last_ = q2;
}
left (1.);
right(1.);
// set the coupling
norm( UnitRemoval::E * kappa_ * couplast_);
}
diff --git a/Models/RSModel/RSModelFFGRVertex.cc b/Models/RSModel/RSModelFFGRVertex.cc
--- a/Models/RSModel/RSModelFFGRVertex.cc
+++ b/Models/RSModel/RSModelFFGRVertex.cc
@@ -1,64 +1,65 @@
// -*- C++ -*-
//
// RSModelFFGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RSModelFFGRVertex class.
//
#include "RSModelFFGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
void RSModelFFGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV);
}
void RSModelFFGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RSModelFFGRVertex,FFTVertex>
describeHerwigRSModelFFGRVertex("Herwig::RSModelFFGRVertex", "HwRSModel.so");
void RSModelFFGRVertex::Init() {
static ClassDocumentation<RSModelFFGRVertex> documentation
("The RSModelFFGRVertex class is the RSModel calculation"
" of the fermion-antifermion-graviton vertex");
}
void RSModelFFGRVertex::setCoupling(Energy2,tcPDPtr,tcPDPtr, tcPDPtr) {
norm(Complex(kappa_ * UnitRemoval::E));
}
RSModelFFGRVertex::RSModelFFGRVertex() : kappa_(ZERO) {
orderInGem(1);
orderInGs (0);
+ colourStructure(ColourStructure::DELTA);
}
void RSModelFFGRVertex::doinit() {
// PDG codes for the particles
// the quarks
for (int ix=1;ix<7;++ix) addToList(-ix,ix,39);
// the leptons
for (int ix=11;ix<17;++ix) addToList(-ix,ix,39);
FFTVertex::doinit();
tcHwRSPtr hwRS=dynamic_ptr_cast<tcHwRSPtr>(generator()->standardModel());
if(!hwRS)
throw Exception() << "Must have RSModel in RSModelFFGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwRS->lambda_pi();
}
diff --git a/Models/RSModel/RSModelFFWGRVertex.cc b/Models/RSModel/RSModelFFWGRVertex.cc
--- a/Models/RSModel/RSModelFFWGRVertex.cc
+++ b/Models/RSModel/RSModelFFWGRVertex.cc
@@ -1,190 +1,191 @@
// -*- C++ -*-
//
// RSModelFFWGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RSModelFFWGRVertex class.
//
#include "RSModelFFWGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
using namespace Herwig;
using namespace ThePEG;
RSModelFFWGRVertex::RSModelFFWGRVertex()
: charge_(17,0.), gl_(17,0.), gr_(17,0.),
ckm_(3,vector<Complex>(3,0.0)),
couplast_(0.), q2last_(ZERO), kappa_(ZERO) {
orderInGem(2);
orderInGs (0);
+ colourStructure(ColourStructure::DELTA);
}
void RSModelFFWGRVertex::doinit() {
for(int ix=11;ix<17;++ix) {
addToList(-ix,ix,22,39);
addToList(-ix,ix,23,39);
}
for(int ix=1;ix<7;++ix) {
addToList(-ix,ix,22,39);
addToList(-ix,ix,23,39);
}
// particles for outgoing W-
// quarks
for(int ix=1;ix<6;ix+=2) {
for(int iy=2;iy<7;iy+=2) {
addToList(-ix, iy, -24,39);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix, ix+1, -24,39);
}
// particles for outgoing W+
// quarks
for(int ix=2;ix<7;ix+=2) {
for(int iy=1;iy<6;iy+=2) {
addToList(-ix, iy, 24,39);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix-1, ix, 24,39);
}
FFVTVertex::doinit();
tcHwRSPtr hwRS=dynamic_ptr_cast<tcHwRSPtr>(generator()->standardModel());
if(!hwRS) throw Exception()
<< "Must have RSModel in RSModelFFWGRVertex::doinit()"
<< Exception::runerror;
double sw2 = sin2ThetaW();
double fact = 0.25/sqrt(sw2*(1.-sw2));
for(int ix=1;ix<4;++ix) {
charge_[2*ix-1] = hwRS->ed();
charge_[2*ix ] = hwRS->eu();
charge_[2*ix+9 ] = hwRS->ee();
charge_[2*ix+10] = hwRS->enu();
gl_[2*ix-1] = fact*(hwRS->vd() + hwRS->ad() );
gl_[2*ix ] = fact*(hwRS->vu() + hwRS->au() );
gl_[2*ix+9 ] = fact*(hwRS->ve() + hwRS->ae() );
gl_[2*ix+10] = fact*(hwRS->vnu() + hwRS->anu());
gr_[2*ix-1] = fact*(hwRS->vd() - hwRS->ad() );
gr_[2*ix ] = fact*(hwRS->vu() - hwRS->au() );
gr_[2*ix+9 ] = fact*(hwRS->ve() - hwRS->ae() );
gr_[2*ix+10] = fact*(hwRS->vnu() - hwRS->anu());
}
kappa_ = 2./hwRS->lambda_pi();
Ptr<CKMBase>::transient_pointer CKM = generator()->standardModel()->CKM();
// cast the CKM object to the HERWIG one
ThePEG::Ptr<Herwig::StandardCKM>::transient_const_pointer
hwCKM = ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardCKM>::
transient_const_pointer>(CKM);
if(hwCKM) {
vector< vector<Complex > > CKM;
CKM = hwCKM->getUnsquaredMatrix(generator()->standardModel()->families());
for(unsigned int ix=0;ix<3;++ix) {
for(unsigned int iy=0;iy<3;++iy) {
ckm_[ix][iy]=CKM[ix][iy];
}
}
}
else {
throw Exception() << "Must have access to the Herwig::StandardCKM object"
<< "for the CKM matrix in SMFFWVertex::doinit()"
<< Exception::runerror;
}
}
void RSModelFFWGRVertex::persistentOutput(PersistentOStream & os) const {
os << charge_ << gl_ << gr_ << ounit(kappa_,InvGeV) << ckm_;
}
void RSModelFFWGRVertex::persistentInput(PersistentIStream & is, int) {
is >> charge_ >> gl_ >> gr_ >> iunit(kappa_,InvGeV) >> ckm_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RSModelFFWGRVertex,FFVTVertex>
describeHerwigRSModelFFWGRVertex("Herwig::RSModelFFWGRVertex", "HwRSModel.so");
void RSModelFFWGRVertex::Init() {
static ClassDocumentation<RSModelFFWGRVertex> documentation
("The RSModelFFWGRVertexxs class is the implementation"
" of the two fermion vector coupling for the RS model.");
}
// FFWGR coupling
void RSModelFFWGRVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr bb,
tcPDPtr cc, tcPDPtr) {
// work out the particles
int iferm= abs(aa->id());
int ibos = abs(cc->id());
Complex coup;
// overall factor
assert( ibos >= 22 && ibos <= 24 );
if( q2last_ != q2 || couplast_ == 0. ) {
couplast_ = electroMagneticCoupling(q2);
q2last_ = q2;
}
// photon
if(ibos==22) {
// alpha
coup = UnitRemoval::E * kappa_ * couplast_;
// _charge of particle
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16));
coup *= charge_[iferm];
left (1.);
right(1.);
}
// Z boson
else if(ibos==23) {
coup = UnitRemoval::E * kappa_ * couplast_;
// _charge of particle
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16));
left (gl_[iferm]);
right(gr_[iferm]);
}
else if(ibos==24) {
coup = UnitRemoval::E * kappa_ * couplast_ *
sqrt(0.5) / sqrt(sin2ThetaW());
// the left and right couplings
int iferm=abs(aa->id());
int ianti=abs(bb->id());
// quarks
if(iferm>=1 && iferm <=6) {
int iu,id;
// up type first
if(iferm%2==0) {
iu = iferm/2;
id = (ianti+1)/2;
}
// down type first
else {
iu = ianti/2;
id = (iferm+1)/2;
}
assert( iu>=1 && iu<=3 && id>=1 && id<=3);
left(ckm_[iu-1][id-1]);
right(0.);
}
// leptons
else if(iferm>=11 && iferm <=16) {
left(1.);
right(0.);
}
else
assert(false);
}
// set the coupling
norm(coup);
}
diff --git a/Models/RSModel/RSModelGGGGRVertex.cc b/Models/RSModel/RSModelGGGGRVertex.cc
--- a/Models/RSModel/RSModelGGGGRVertex.cc
+++ b/Models/RSModel/RSModelGGGGRVertex.cc
@@ -1,76 +1,77 @@
// -*- C++ -*-
//
// RSModelGGGGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RSModelGGGGRVertex class.
//
#include "RSModelGGGGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
RSModelGGGGRVertex::RSModelGGGGRVertex()
: kappa_(ZERO), _couplast(0.), _q2last(ZERO) {
orderInGem(1);
orderInGs (1);
+ colourStructure(ColourStructure::SU3FF);
}
void RSModelGGGGRVertex::doinit() {
addToList(21, 21, 21, 39);
VVVTVertex::doinit();
// set the graviton coupling
tcHwRSPtr hwRS=dynamic_ptr_cast<tcHwRSPtr>(generator()->standardModel());
if(!hwRS)
throw Exception()
<< "Must have RSModel in RSModelGGGGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwRS->lambda_pi();
}
void RSModelGGGGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV);
}
void RSModelGGGGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RSModelGGGGRVertex,VVVTVertex>
describeHerwigRSModelGGGGRVertex("Herwig::RSModelGGGGRVertex", "HwRSModel.so");
void RSModelGGGGRVertex::Init() {
static ClassDocumentation<RSModelGGGGRVertex> documentation
("The RSModelGGGGRVertex class is the four point coupling"
" of three vector bosons and a graviton in the Randell-Sundrum model.");
}
// couplings for the GGGGR vertex
#ifndef NDEBUG
void RSModelGGGGRVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,
tcPDPtr c, tcPDPtr) {
#else
void RSModelGGGGRVertex::setCoupling(Energy2 q2,tcPDPtr,tcPDPtr,
tcPDPtr, tcPDPtr) {
#endif
assert(a->id() == ParticleID::g && b->id() == ParticleID::g &&
c->id() == ParticleID::g);
if(q2!=_q2last||_couplast==0.) {
_couplast = strongCoupling(q2);
_q2last=q2;
}
norm(Complex(_couplast*kappa_*UnitRemoval::E));
}
diff --git a/Models/RSModel/RSModelSSGRVertex.cc b/Models/RSModel/RSModelSSGRVertex.cc
--- a/Models/RSModel/RSModelSSGRVertex.cc
+++ b/Models/RSModel/RSModelSSGRVertex.cc
@@ -1,60 +1,61 @@
// -*- C++ -*-
//
// RSModelSSGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RSModelSSGRVertex class.
//
#include "RSModelSSGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
RSModelSSGRVertex::RSModelSSGRVertex() : kappa_(ZERO) {
orderInGem(1);
orderInGs (0);
+ colourStructure(ColourStructure::SINGLET);
}
void RSModelSSGRVertex::doinit() {
addToList(25,25,39);
SSTVertex::doinit();
tcHwRSPtr hwRS=dynamic_ptr_cast<tcHwRSPtr>(generator()->standardModel());
if(!hwRS)
throw Exception() << "Must have RSModel in RSModelSSGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwRS->lambda_pi();
}
void RSModelSSGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV);
}
void RSModelSSGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RSModelSSGRVertex,SSTVertex>
describeHerwigRSModelSSGRVertex("Herwig::RSModelSSGRVertex", "HwRSModel.so");
void RSModelSSGRVertex::Init() {
static ClassDocumentation<RSModelSSGRVertex> documentation
("The RSModelSSGRVertex class is the implementation of"
" the RSModel scalar-scalar-graviton vertex");
}
void RSModelSSGRVertex::setCoupling(Energy2,tcPDPtr,tcPDPtr, tcPDPtr) {
norm(Complex(kappa_ * UnitRemoval::E));
}
diff --git a/Models/RSModel/RSModelVVGRVertex.cc b/Models/RSModel/RSModelVVGRVertex.cc
--- a/Models/RSModel/RSModelVVGRVertex.cc
+++ b/Models/RSModel/RSModelVVGRVertex.cc
@@ -1,63 +1,64 @@
// -*- C++ -*-
//
// RSModelVVGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RSModelVVGRVertex class.
//
#include "RSModelVVGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
void RSModelVVGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV);
}
void RSModelVVGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RSModelVVGRVertex,VVTVertex>
describeHerwigRSModelVVGRVertex("Herwig::RSModelVVGRVertex", "HwRSModel.so");
void RSModelVVGRVertex::Init() {
static ClassDocumentation<RSModelVVGRVertex> documentation
("The RSModelVVGRVertex class is the implementation"
" of the RSModel vector-vector-graviton vertex");
}
void RSModelVVGRVertex::setCoupling(Energy2,tcPDPtr,tcPDPtr, tcPDPtr) {
norm(Complex(UnitRemoval::E * kappa_));
}
RSModelVVGRVertex::RSModelVVGRVertex() : kappa_(ZERO) {
orderInGem(1);
orderInGs (0);
+ colourStructure(ColourStructure::DELTA);
}
void RSModelVVGRVertex::doinit() {
addToList(23,23,39);
addToList(22,22,39);
addToList(24,-24,39);
addToList(21,21,39);
VVTVertex::doinit();
tcHwRSPtr hwRS=dynamic_ptr_cast<tcHwRSPtr>(generator()->standardModel());
if(!hwRS)
throw Exception() << "Must be RSModel in RSModelVVGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwRS->lambda_pi();
}
diff --git a/Models/RSModel/RSModelWWWGRVertex.cc b/Models/RSModel/RSModelWWWGRVertex.cc
--- a/Models/RSModel/RSModelWWWGRVertex.cc
+++ b/Models/RSModel/RSModelWWWGRVertex.cc
@@ -1,97 +1,98 @@
// -*- C++ -*-
//
// RSModelVVVGRVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RSModelWWWGRVertex class.
//
#include "RSModelWWWGRVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
RSModelWWWGRVertex::RSModelWWWGRVertex()
: kappa_(ZERO), _couplast(0.),
_q2last(ZERO), _zfact(0.) {
// order in the couplings
orderInGem(2);
orderInGs (0);
+ colourStructure(ColourStructure::SINGLET);
}
void RSModelWWWGRVertex::doinit() {
addToList(24,-24, 22, 39);
addToList(24,-24, 23, 39);
VVVTVertex::doinit();
_zfact = sqrt((1.-sin2ThetaW())/sin2ThetaW());
// set the graviton coupling
tcHwRSPtr hwRS=dynamic_ptr_cast<tcHwRSPtr>(generator()->standardModel());
if(!hwRS)
throw Exception()
<< "Must have RSModel in RSModelWWWGRVertex::doinit()"
<< Exception::runerror;
kappa_=2./hwRS->lambda_pi();
}
void RSModelWWWGRVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(kappa_,InvGeV) << _zfact;
}
void RSModelWWWGRVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(kappa_,InvGeV) >> _zfact;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RSModelWWWGRVertex,VVVTVertex>
describeHerwigRSModelWWWGRVertex("Herwig::RSModelWWWGRVertex", "HwRSModel.so");
void RSModelWWWGRVertex::Init() {
static ClassDocumentation<RSModelWWWGRVertex> documentation
("The RSModelWWWGRVertex class is the four point coupling"
" of three vector bosons and a graviton in the Randell-Sundrum model.");
}
// couplings for the WWWGR vertex
void RSModelWWWGRVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,
tcPDPtr c, tcPDPtr) {
int ida=a->id();
int idb=b->id();
int idc=c->id();
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = electroMagneticCoupling(q2);
_q2last=q2;
}
// W- W+ photon and cylic perms
if((ida==-24 && idb== 24 && idc== 22) ||
(ida== 22 && idb==-24 && idc== 24) ||
(ida== 24 && idb== 22 && idc==-24) )
norm(Complex(_couplast*kappa_*UnitRemoval::E));
// W+ W- photon (anticylic perms of above)
else if((ida== 24 && idb==-24 && idc== 22) ||
(ida== 22 && idb== 24 && idc==-24) ||
(ida==-24 && idb== 22 && idc== 24) )
norm(-Complex(_couplast*kappa_*UnitRemoval::E));
// W- W+ Z and cylic perms
else if((ida==-24 && idb== 24 && idc== 23) ||
(ida== 23 && idb==-24 && idc== 24) ||
(ida== 24 && idb== 23 && idc==-24) )
norm(Complex(_couplast*_zfact*kappa_*UnitRemoval::E));
// W+ W- Z (anticylic perms of above)
else if((ida== 24 && idb==-24 && idc== 23) ||
(ida== 23 && idb== 24 && idc==-24) ||
(ida==-24 && idb== 23 && idc== 24) )
norm(-Complex(_couplast*_zfact*kappa_*UnitRemoval::E));
else assert(false);
}
diff --git a/Models/Sextet/SextetFFSVertex.h b/Models/Sextet/SextetFFSVertex.h
--- a/Models/Sextet/SextetFFSVertex.h
+++ b/Models/Sextet/SextetFFSVertex.h
@@ -1,138 +1,140 @@
// -*- C++ -*-
#ifndef HERWIG_SextetFFSVertex_H
#define HERWIG_SextetFFSVertex_H
//
// This is the declaration of the SextetFFSVertex class.
//
#include "ThePEG/Helicity/Vertex/Scalar/FFSVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SextetFFSVertex class.
*
* @see \ref SextetFFSVertexInterfaces "The interfaces"
* defined for SextetFFSVertex.
*/
class SextetFFSVertex: public Helicity::FFSVertex {
public:
/**
* The default constructor.
*/
- SextetFFSVertex() {}
+ SextetFFSVertex() {
+ colourStructure(ColourStructure::SU3K6);
+ }
/**
* Calculate the couplings.
* @param q2 The scale \f$q^2\f$ for the coupling at the vertex.
* @param part1 The ParticleData pointer for the first particle.
* @param part2 The ParticleData pointer for the second particle.
* @param part3 The ParticleData pointer for the third particle.
*/
virtual void setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3);
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.
*/
SextetFFSVertex & operator=(const SextetFFSVertex &);
private:
/**
* The various couplings
*/
//@{
/**
* The \f$SU(2)\f$ quark-doublet coupling to \f$\Phi_{6,1,1/3}\f$
*/
vector<double> g1L_;
/**
* The \f$SU(2)\f$ singlet coupling to \f$\Phi_{6,1,1/3}\f$
*/
vector<double> g1R_;
/**
* The \f$SU(2)\f$ singlet coupling to \f$\Phi_{6,1,-2/3}\f$
*/
vector<double> g1pR_;
/**
* The \f$SU(2)\f$ singlet coupling to \f$\Phi_{6,1,4/3}\f$
*/
vector<double> g1ppR_;
/**
* Coupling to \f$\Phi_{6,3,1/3}\f$
*/
vector<double> g3L_;
//@}
};
}
#endif /* HERWIG_SextetFFSVertex_H */
diff --git a/Models/Sextet/SextetFFVVertex.h b/Models/Sextet/SextetFFVVertex.h
--- a/Models/Sextet/SextetFFVVertex.h
+++ b/Models/Sextet/SextetFFVVertex.h
@@ -1,124 +1,126 @@
// -*- C++ -*-
#ifndef HERWIG_SextetFFVVertex_H
#define HERWIG_SextetFFVVertex_H
//
// This is the declaration of the SextetFFVVertex class.
//
#include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SextetFFVVertex class.
*
* @see \ref SextetFFVVertexInterfaces "The interfaces"
* defined for SextetFFVVertex.
*/
class SextetFFVVertex: public Helicity::FFVVertex {
public:
/**
* The default constructor.
*/
- SextetFFVVertex() {}
+ SextetFFVVertex() {
+ colourStructure(ColourStructure::SU3K6);
+ }
/**
* Calculate the couplings.
* @param q2 The scale \f$q^2\f$ for the coupling at the vertex.
* @param part1 The ParticleData pointer for the first particle.
* @param part2 The ParticleData pointer for the second particle.
* @param part3 The ParticleData pointer for the third particle.
*/
virtual void setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3);
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.
*/
SextetFFVVertex & operator=(const SextetFFVVertex &);
private:
/**
* The various couplings
*/
//@{
/**
* The \f$SU(2)\f$ quark-doublet coupling to \f$\Phi_{6,2,-1/6}\f$
*/
vector<double> g2_;
/**
* The \f$SU(2)\f$ singlet coupling to \f$\Phi_{6,2,5/6}\f$
*/
vector<double> g2p_;
//@}
};
}
#endif /* HERWIG_SextetFFVVertex_H */
diff --git a/Models/Sextet/SextetGGSSVertex.cc b/Models/Sextet/SextetGGSSVertex.cc
--- a/Models/Sextet/SextetGGSSVertex.cc
+++ b/Models/Sextet/SextetGGSSVertex.cc
@@ -1,78 +1,79 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SextetGGSSVertex class.
//
#include "SextetGGSSVertex.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 "SextetModel.h"
#include "SextetParticles.h"
using namespace Herwig;
-SextetGGSSVertex::SextetGGSSVertex() : q2last_(), couplast_()
-{}
+SextetGGSSVertex::SextetGGSSVertex() : q2last_(), couplast_() {
+ colourStructure(ColourStructure::SU3TT6);
+}
IBPtr SextetGGSSVertex::clone() const {
return new_ptr(*this);
}
IBPtr SextetGGSSVertex::fullclone() const {
return new_ptr(*this);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<SextetGGSSVertex,VVSSVertex>
describeSextetGGSSVertex("Herwig::SextetGGSSVertex", "HwSextetModel.so");
void SextetGGSSVertex::Init() {
static ClassDocumentation<SextetGGSSVertex> documentation
("The SextetGGSSVertex class implements the coupling of two gluons to two"
" scalar sextets");
}
void SextetGGSSVertex::setCoupling(Energy2 q2, tcPDPtr, tcPDPtr, tcPDPtr,
tcPDPtr) {
if(q2 != q2last_ || couplast_ == 0.) {
couplast_ = sqr(strongCoupling(q2));
q2last_ = q2;
}
norm(couplast_);
}
void SextetGGSSVertex::doinit() {
orderInGs(2);
orderInGem(0);
SextetModelPtr model =
dynamic_ptr_cast<SextetModelPtr>(generator()->standardModel());
if(!model) throw Exception() << "Must be using the SextetModel"
<< " in SextetGSSVertex::doinit()"
<< Exception::runerror;
// add the enabled particles
if(model->ScalarSingletY43Enabled())
addToList(21,21,ParticleID::ScalarDQSingletY43,
ParticleID::ScalarDQSingletY43bar);
if(model->ScalarSingletY13Enabled())
addToList(21,21,ParticleID::ScalarDQSingletY13,
ParticleID::ScalarDQSingletY13bar);
if(model->ScalarSingletY23Enabled())
addToList(21,21,ParticleID::ScalarDQSingletY23,
ParticleID::ScalarDQSingletY23bar);
if(model->ScalarTripletY13Enabled()) {
addToList(21,21,ParticleID::ScalarDQTripletP,
ParticleID::ScalarDQTripletPbar);
addToList(21,21,ParticleID::ScalarDQTriplet0,
ParticleID::ScalarDQTriplet0bar);
addToList(21,21,ParticleID::ScalarDQTripletM,
ParticleID::ScalarDQTripletMbar);
}
VVSSVertex::doinit();
}
diff --git a/Models/Sextet/SextetGGVVVertex.h b/Models/Sextet/SextetGGVVVertex.h
--- a/Models/Sextet/SextetGGVVVertex.h
+++ b/Models/Sextet/SextetGGVVVertex.h
@@ -1,102 +1,104 @@
// -*- C++ -*-
#ifndef HERWIG_SextetGGVVVertex_H
#define HERWIG_SextetGGVVVertex_H
//
// This is the declaration of the SextetGGVVVertex class.
//
#include "ThePEG/Helicity/Vertex/Vector/VVVVVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SextetGGVVVertex class.
*
* @see \ref SextetGGVVVertexInterfaces "The interfaces"
* defined for SextetGGVVVertex.
*/
class SextetGGVVVertex: public Helicity::VVVVVertex {
public:
/**
* The default constructor.
*/
- SextetGGVVVertex() {}
+ SextetGGVVVertex() {
+ colourStructure(ColourStructure::SU3TT6);
+ }
/** Calculate the coupling
*@param q2 The scale at which to evaluate the coupling
*@param part1 The first interacting particle
*@param part2 The second interacting particle
*@param part3 The third interacting particle
*@param part4 The fourth interacting particle
*/
virtual void setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3, tcPDPtr part4);
public:
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
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.
*/
SextetGGVVVertex & operator=(const SextetGGVVVertex &);
private:
/**
* The scale at which the coupling was last evaluated
*/
Energy2 q2Last_;
/**
* The value of the coupling when it was last evaluated
*/
Complex coupLast_;
};
}
#endif /* HERWIG_SextetGGVVVertex_H */
diff --git a/Models/Sextet/SextetGSSVertex.h b/Models/Sextet/SextetGSSVertex.h
--- a/Models/Sextet/SextetGSSVertex.h
+++ b/Models/Sextet/SextetGSSVertex.h
@@ -1,102 +1,104 @@
// -*- C++ -*-
#ifndef HERWIG_SextetGSSVertex_H
#define HERWIG_SextetGSSVertex_H
//
// This is the declaration of the SextetGSSVertex class.
//
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SextetGSSVertex class.
*
* @see \ref SextetGSSVertexInterfaces "The interfaces"
* defined for SextetGSSVertex.
*/
class SextetGSSVertex: public Helicity::VSSVertex {
public:
/**
* The default constructor.
*/
- SextetGSSVertex() {}
+ SextetGSSVertex() {
+ colourStructure(ColourStructure::SU3T6);
+ }
/**
* Calculate the couplings.
* @param q2 The scale \f$q^2\f$ for the coupling at the vertex.
* @param part1 The ParticleData pointer for the first particle.
* @param part2 The ParticleData pointer for the second particle.
* @param part3 The ParticleData pointer for the third particle.
*/
virtual void setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3);
public:
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
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.
*/
SextetGSSVertex & operator=(const SextetGSSVertex &);
private:
/**
* Store the value of the coupling when last evaluated
*/
Complex coupLast_;
/**
* Store the scale at which coupling was last evaluated
*/
Energy2 q2Last_;
};
}
#endif /* HERWIG_SextetGSSVertex_H */
diff --git a/Models/Sextet/SextetGVVVertex.h b/Models/Sextet/SextetGVVVertex.h
--- a/Models/Sextet/SextetGVVVertex.h
+++ b/Models/Sextet/SextetGVVVertex.h
@@ -1,100 +1,102 @@
// -*- C++ -*-
#ifndef THEPEG_SextetGVVVertex_H
#define THEPEG_SextetGVVVertex_H
//
// This is the declaration of the SextetGVVVertex class.
//
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SextetGVVVertex class.
*
* @see \ref SextetGVVVertexInterfaces "The interfaces"
* defined for SextetGVVVertex.
*/
class SextetGVVVertex: public Helicity::VVVVertex {
public:
/**
* The default constructor.
*/
- SextetGVVVertex() {}
+ SextetGVVVertex() {
+ colourStructure(ColourStructure::SU3T6);
+ }
/** Calculate the coupling
*@param q2 The scale at which to evaluate the coupling
*@param part1 The first interacting particle
*@param part2 The second interacting particle
*@param part3 The third interacting particle
*/
virtual void setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3);
public:
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
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.
*/
SextetGVVVertex & operator=(const SextetGVVVertex &);
private:
/**
* Store the value of the coupling when last evaluated
*/
Complex coupLast_;
/**
* Store the scale at which coupling was last evaluated
*/
Energy2 q2Last_;
};
}
#endif /* THEPEG_SextetGVVVertex_H */
diff --git a/Models/Sextet/SextetPSSVertex.h b/Models/Sextet/SextetPSSVertex.h
--- a/Models/Sextet/SextetPSSVertex.h
+++ b/Models/Sextet/SextetPSSVertex.h
@@ -1,102 +1,104 @@
// -*- C++ -*-
#ifndef HERWIG_SextetPSSVertex_H
#define HERWIG_SextetPSSVertex_H
//
// This is the declaration of the SextetPSSVertex class.
//
#include "ThePEG/Helicity/Vertex/Scalar/VSSVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SextetPSSVertex class.
*
* @see \ref SextetPSSVertexInterfaces "The interfaces"
* defined for SextetPSSVertex.
*/
class SextetPSSVertex: public Helicity::VSSVertex {
public:
/**
* The default constructor.
*/
- SextetPSSVertex() {}
+ SextetPSSVertex() {
+ colourStructure(ColourStructure::DELTA);
+ }
/**
* Calculate the couplings.
* @param q2 The scale \f$q^2\f$ for the coupling at the vertex.
* @param part1 The ParticleData pointer for the first particle.
* @param part2 The ParticleData pointer for the second particle.
* @param part3 The ParticleData pointer for the third particle.
*/
virtual void setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3);
public:
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
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.
*/
SextetPSSVertex & operator=(const SextetPSSVertex &);
private:
/**
* Store the value of the coupling when last evaluated
*/
Complex coupLast_;
/**
* Store the scale at which coupling was last evaluated
*/
Energy2 q2Last_;
};
}
#endif /* HERWIG_SextetPSSVertex_H */
diff --git a/Models/Sextet/SextetPVVVertex.h b/Models/Sextet/SextetPVVVertex.h
--- a/Models/Sextet/SextetPVVVertex.h
+++ b/Models/Sextet/SextetPVVVertex.h
@@ -1,100 +1,102 @@
// -*- C++ -*-
#ifndef THEPEG_SextetPVVVertex_H
#define THEPEG_SextetPVVVertex_H
//
// This is the declaration of the SextetPVVVertex class.
//
#include "ThePEG/Helicity/Vertex/Vector/VVVVertex.h"
namespace Herwig {
using namespace ThePEG;
/**
* Here is the documentation of the SextetPVVVertex class.
*
* @see \ref SextetPVVVertexInterfaces "The interfaces"
* defined for SextetPVVVertex.
*/
class SextetPVVVertex: public Helicity::VVVVertex {
public:
/**
* The default constructor.
*/
- SextetPVVVertex() {}
+ SextetPVVVertex() {
+ colourStructure(ColourStructure::DELTA);
+ }
/** Calculate the coupling
*@param q2 The scale at which to evaluate the coupling
*@param part1 The first interacting particle
*@param part2 The second interacting particle
*@param part3 The third interacting particle
*/
virtual void setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3);
public:
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
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.
*/
SextetPVVVertex & operator=(const SextetPVVVertex &);
private:
/**
* Store the value of the coupling when last evaluated
*/
Complex coupLast_;
/**
* Store the scale at which coupling was last evaluated
*/
Energy2 q2Last_;
};
}
#endif /* THEPEG_SextetPVVVertex_H */
diff --git a/Models/StandardModel/SMFFGVertex.cc b/Models/StandardModel/SMFFGVertex.cc
--- a/Models/StandardModel/SMFFGVertex.cc
+++ b/Models/StandardModel/SMFFGVertex.cc
@@ -1,70 +1,71 @@
// -*- C++ -*-
//
// SMFFGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the StandardModelFFGVertex class.
//
#include "SMFFGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/StandardModel/StandardModelBase.h"
using namespace Herwig;
using namespace ThePEG;
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<SMFFGVertex,FFVVertex>
describeHerwigSMFFGVertex("Herwig::SMFFGVertex", "Herwig.so");
void SMFFGVertex::Init() {
static ClassDocumentation<SMFFGVertex> documentation
("The SMFFGVertex class is the implementation of"
"the coupling of the gluon to the Standard Model fermions");
}
// coupling for FFG vertex
#ifndef NDEBUG
void SMFFGVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr bb,tcPDPtr) {
#else
void SMFFGVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr,tcPDPtr) {
#endif
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = -strongCoupling(q2);
_q2last=q2;
}
// the left and right couplings
assert( abs(aa->id()) >= 1 && abs(aa->id()) <= 6 );
assert( aa->id()==-bb->id());
if(aa->id()<0)
norm( _couplast);
else
norm(-_couplast);
left(1.);
right(1.);
}
SMFFGVertex::SMFFGVertex() : _couplast(0.), _q2last(ZERO) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TFUND);
}
void SMFFGVertex::doinit() {
// PDG codes for the particles
for(int ix=1;ix<7;++ix) {
addToList(-ix,ix,21);
}
FFVVertex::doinit();
}
diff --git a/Models/StandardModel/SMFFHVertex.cc b/Models/StandardModel/SMFFHVertex.cc
--- a/Models/StandardModel/SMFFHVertex.cc
+++ b/Models/StandardModel/SMFFHVertex.cc
@@ -1,113 +1,114 @@
// -*- C++ -*-
//
// SMFFHVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMFFHVertex class.
//
#include "SMFFHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Config/Constants.h"
using namespace Herwig;
IBPtr SMFFHVertex::clone() const {
return new_ptr(*this);
}
IBPtr SMFFHVertex::fullclone() const {
return new_ptr(*this);
}
SMFFHVertex::SMFFHVertex() {
// set up for the couplings
_couplast=InvEnergy();
_idlast=0;
_q2last=ZERO;
_masslast=ZERO;
_mw=ZERO;
_fermion = 0;
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SMFFHVertex::doinit() {
if ( !_fermion ) {
// PDG codes for the particles
// the quarks
for(int ix=1;ix<7;++ix) {
addToList(-ix, ix, 25);
}
// the leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix, ix, 25);
}
} else {
addToList(-_fermion,_fermion,25);
}
_theSM = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
if (!_theSM)
throw InitException();
_mw= getParticleData(ThePEG::ParticleID::Wplus)->mass();
FFSVertex::doinit();
}
void SMFFHVertex::persistentOutput(PersistentOStream & os) const {
os << _theSM << ounit(_mw,GeV) << _fermion;
}
void SMFFHVertex::persistentInput(PersistentIStream & is, int) {
is >> _theSM >> iunit(_mw,GeV) >> _fermion;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMFFHVertex,FFSVertex>
describeHerwigSMFFHVertex("Herwig::SMFFHVertex", "Herwig.so");
void SMFFHVertex::Init() {
static ClassDocumentation<SMFFHVertex> documentation
("The SMFFHVertex class is the implementation"
" of the helicity amplitude calculation of the Standard Model Higgs"
" fermion-antiferiom vertex.");
static Parameter<SMFFHVertex,int> interfaceFermion
("Fermion",
"The fermion to couple to. If not set all fermions are considered.",
&SMFFHVertex::_fermion, 0, 0, 16,
false, false, Interface::limited);
}
void SMFFHVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr, tcPDPtr) {
int iferm=abs(aa->id());
// left and right couplings set to one
left (1.);
right(1.);
// first the overall normalisation
if(q2!=_q2last||_couplast==complex<InvEnergy>()) {
_couplast = -0.5*weakCoupling(q2)/_mw;
_q2last=q2;
_idlast=iferm;
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16));
_masslast=_theSM->mass(q2,aa);
}
else if(iferm!=_idlast) {
_idlast=iferm;
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16));
_masslast=_theSM->mass(q2,aa);
}
norm(_couplast*_masslast);
}
diff --git a/Models/StandardModel/SMFFPVertex.cc b/Models/StandardModel/SMFFPVertex.cc
--- a/Models/StandardModel/SMFFPVertex.cc
+++ b/Models/StandardModel/SMFFPVertex.cc
@@ -1,89 +1,90 @@
// -*- C++ -*-
//
// SMFFPVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the StandardModelFFPVertex class.
//
#include "SMFFPVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
SMFFPVertex::SMFFPVertex() : _charge(17,0.0), _couplast(0.), _q2last(0.*GeV2) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SMFFPVertex::doinit() {
// PDG codes for the particles
// the quarks
for(int ix=1;ix<7;++ix) {
addToList(-ix, ix, 22);
}
// the leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix, ix, 22);
}
for(int ix=1;ix<4;++ix) {
_charge[2*ix-1] = generator()->standardModel()->ed();
_charge[2*ix ] = generator()->standardModel()->eu();
_charge[2*ix+9 ] = generator()->standardModel()->ee();
_charge[2*ix+10] = generator()->standardModel()->enu();
}
FFVVertex::doinit();
}
void SMFFPVertex::persistentOutput(PersistentOStream & os) const {
os << _charge;
}
void SMFFPVertex::persistentInput(PersistentIStream & is, int) {
is >> _charge;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SMFFPVertex,FFVVertex>
describeHerwigSMFFPVertex("Herwig::SMFFPVertex", "Herwig.so");
void SMFFPVertex::Init() {
static ClassDocumentation<SMFFPVertex> documentation
("The SMFFPVertex class is the implementation of"
"the coupling of the photon to the Standard Model fermions");
}
// coupling for FFP vertex
#ifndef NDEBUG
void SMFFPVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr bb,tcPDPtr) {
#else
void SMFFPVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr,tcPDPtr) {
#endif
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = -electroMagneticCoupling(q2);
_q2last=q2;
}
norm(_couplast);
// the left and right couplings
int iferm=abs(aa->id());
assert((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16));
assert(aa->id()==-bb->id());
if(aa->id()<0) {
left(_charge[iferm]);
right(_charge[iferm]);
}
else {
left(-_charge[iferm]);
right(-_charge[iferm]);
}
}
diff --git a/Models/StandardModel/SMFFWVertex.cc b/Models/StandardModel/SMFFWVertex.cc
--- a/Models/StandardModel/SMFFWVertex.cc
+++ b/Models/StandardModel/SMFFWVertex.cc
@@ -1,165 +1,166 @@
// -*- C++ -*-
//
// SMFFWVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMFFWVertex class.
//
#include "SMFFWVertex.h"
#include "ThePEG/StandardModel/StandardModelBase.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
SMFFWVertex::SMFFWVertex() :
_diagonal(false), _ckm(3,vector<Complex>(3,0.0)),
_couplast(0.), _q2last(ZERO) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SMFFWVertex::persistentOutput(PersistentOStream & os) const {
os << _diagonal << _ckm;
}
void SMFFWVertex::persistentInput(PersistentIStream & is, int) {
is >> _diagonal >> _ckm;
}
void SMFFWVertex::doinit() {
// particles for outgoing W-
// quarks
for(int ix=1;ix<6;ix+=2) {
for(int iy=2;iy<7;iy+=2) {
bool isOff = iy/2 != (ix+1)/2;
if ( isOff && _diagonal )
continue;
addToList(-ix, iy, -24);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix, ix+1, -24);
}
// particles for outgoing W+
// quarks
for(int ix=2;ix<7;ix+=2) {
for(int iy=1;iy<6;iy+=2) {
bool isOff = ix/2 != (iy+1)/2;
if ( isOff && _diagonal )
continue;
addToList(-ix, iy, 24);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix-1, ix, 24);
}
ThePEG::Helicity::FFVVertex::doinit();
if ( !_diagonal ) {
Ptr<CKMBase>::transient_pointer CKM = generator()->standardModel()->CKM();
// cast the CKM object to the HERWIG one
ThePEG::Ptr<Herwig::StandardCKM>::transient_const_pointer
hwCKM = ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardCKM>::
transient_const_pointer>(CKM);
if(hwCKM) {
vector< vector<Complex > > CKM;
CKM = hwCKM->getUnsquaredMatrix(generator()->standardModel()->families());
for(unsigned int ix=0;ix<3;++ix) {
for(unsigned int iy=0;iy<3;++iy) {
_ckm[ix][iy]=CKM[ix][iy];
}
}
}
else {
throw Exception() << "Must have access to the Herwig::StandardCKM object"
<< "for the CKM matrix in SMFFWVertex::doinit()"
<< Exception::runerror;
}
} else {
_ckm = vector< vector<Complex > >(3,vector<Complex >(3,1.0));
}
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SMFFWVertex,FFVVertex>
describeHerwigSMFFWVertex("Herwig::SMFFWVertex", "Herwig.so");
void SMFFWVertex::Init() {
static ClassDocumentation<SMFFWVertex> documentation
("The SMFFZVertex class is the implementation of"
"the coupling of the W boson to the Standard Model fermions");
static Switch<SMFFWVertex,bool> interfaceDiagonal
("Diagonal",
"Use a diagonal CKM matrix (ignoring the CKM object of the StandardModel).",
&SMFFWVertex::_diagonal, false, false, false);
static SwitchOption interfaceDiagonalYes
(interfaceDiagonal,
"Yes",
"Use a diagonal CKM matrix.",
true);
static SwitchOption interfaceDiagonalNo
(interfaceDiagonal,
"No",
"Use the CKM object as used by the StandardModel.",
false);
}
// coupling for FFW vertex
void SMFFWVertex::setCoupling(Energy2 q2, tcPDPtr aa, tcPDPtr bb, tcPDPtr) {
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = -sqrt(0.5)*weakCoupling(q2);
_q2last=q2;
}
norm(_couplast);
// the left and right couplings
int iferm=abs(aa->id());
int ianti=abs(bb->id());
// quarks
if(iferm>=1 && iferm <=6) {
int iu,id;
// up type first
if(iferm%2==0) {
iu = iferm/2;
id = (ianti+1)/2;
}
// down type first
else {
iu = ianti/2;
id = (iferm+1)/2;
}
assert( iu>=1 && iu<=3 && id>=1 && id<=3);
left(_ckm[iu-1][id-1]);
right(0.);
}
// leptons
else if(iferm>=11 && iferm <=16) {
left(1.);
right(0.);
}
else
assert(false);
}
diff --git a/Models/StandardModel/SMFFZVertex.cc b/Models/StandardModel/SMFFZVertex.cc
--- a/Models/StandardModel/SMFFZVertex.cc
+++ b/Models/StandardModel/SMFFZVertex.cc
@@ -1,90 +1,91 @@
// -*- C++ -*-
//
// SMFFZVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMFFZVertex class.
//
#include "SMFFZVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
void SMFFZVertex::persistentOutput(PersistentOStream & os) const {
os << _gl << _gr;
}
void SMFFZVertex::persistentInput(PersistentIStream & is, int) {
is >> _gl >> _gr;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SMFFZVertex,FFVVertex>
describeHerwigSMFFZVertex("Herwig::SMFFZVertex", "Herwig.so");
void SMFFZVertex::Init() {
static ClassDocumentation<SMFFZVertex> documentation
("The SMFFZVertex class is the implementation of"
"the coupling of the Z boson to the Standard Model fermions");
}
void SMFFZVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr,tcPDPtr) {
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = -electroMagneticCoupling(q2);
_q2last=q2;
}
norm(_couplast);
// the left and right couplings
int iferm=abs(aa->id());
if((iferm>=1 && iferm<=6)||(iferm>=11 &&iferm<=16)) {
left(_gl[iferm]);
right(_gr[iferm]);
}
else
throw HelicityConsistencyError() << "SMFFZVertex::setCoupling "
<< "Unknown particle in Z vertex"
<< Exception::runerror;
}
SMFFZVertex::SMFFZVertex() : _gl(17,0.0), _gr(17,0.0),
_couplast(0.0), _q2last(ZERO) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SMFFZVertex::doinit() {
// PDG codes for the particles
// the quarks
for(int ix=1;ix<7;++ix) {
addToList(-ix, ix, 23);
}
// the leptons
for(int ix=11;ix<17;++ix) {
addToList(-ix, ix, 23);
}
tcSMPtr sm = generator()->standardModel();
double sw2 = sin2ThetaW();
double fact = 0.25/sqrt(sw2*(1.-sw2));
for(int ix=1;ix<4;++ix) {
_gl[2*ix-1] = fact*(sm->vd() + sm->ad() );
_gl[2*ix ] = fact*(sm->vu() + sm->au() );
_gl[2*ix+9 ] = fact*(sm->ve() + sm->ae() );
_gl[2*ix+10] = fact*(sm->vnu() + sm->anu());
_gr[2*ix-1] = fact*(sm->vd() - sm->ad() );
_gr[2*ix ] = fact*(sm->vu() - sm->au() );
_gr[2*ix+9 ] = fact*(sm->ve() - sm->ae() );
_gr[2*ix+10] = fact*(sm->vnu() - sm->anu());
}
FFVVertex::doinit();
}
diff --git a/Models/StandardModel/SMGGGGVertex.cc b/Models/StandardModel/SMGGGGVertex.cc
--- a/Models/StandardModel/SMGGGGVertex.cc
+++ b/Models/StandardModel/SMGGGGVertex.cc
@@ -1,60 +1,61 @@
// -*- C++ -*-
//
// SMGGGGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMGGGGVertex class.
//
#include "SMGGGGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
SMGGGGVertex::SMGGGGVertex() : _couplast(0.),_q2last() {
orderInGs(2);
orderInGem(0);
+ colourStructure(ColourStructure::SU3FF);
}
void SMGGGGVertex::doinit() {
// particles
addToList(21,21,21,21);
VVVVVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<SMGGGGVertex,VVVVVertex>
describeHerwigSMGGGGVertex("Herwig::SMGGGGVertex", "Herwig.so");
void SMGGGGVertex::Init() {
static ClassDocumentation<SMGGGGVertex> documentation
("The SMGGGGVertex class is the implementation of the"
" Standard Model quartic gluon coupling");
}
// couplings for the GGGG vertex
void SMGGGGVertex::setCoupling(Energy2 q2,tcPDPtr,tcPDPtr,
tcPDPtr,tcPDPtr) {
// set the order and type
setType(1);
setOrder(0,1,2,3);
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = sqr(strongCoupling(q2));
_q2last=q2;
}
norm(_couplast);
}
diff --git a/Models/StandardModel/SMGGGVertex.cc b/Models/StandardModel/SMGGGVertex.cc
--- a/Models/StandardModel/SMGGGVertex.cc
+++ b/Models/StandardModel/SMGGGVertex.cc
@@ -1,54 +1,55 @@
// -*- C++ -*-
//
// SMGGGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMGGGVertex class.
//
#include "SMGGGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
SMGGGVertex::SMGGGVertex() : _couplast(0.), _q2last(0.*GeV2) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3F);
}
void SMGGGVertex::doinit() {
// the particles
addToList(21,21,21);
VVVVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<SMGGGVertex,Helicity::VVVVertex>
describeHerwigSMGGGVertex("Herwig::SMGGGVertex", "Herwig.so");
void SMGGGVertex::Init() {
static ClassDocumentation<SMGGGVertex> documentation
("The SMGGGVertex class is the implementation"
" of the Standard Model triple gluon vertex.");
}
// couplings for the GGG vertex
void SMGGGVertex::setCoupling(Energy2 q2,tcPDPtr,tcPDPtr, tcPDPtr) {
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = strongCoupling(q2);
_q2last=q2;
}
norm(_couplast);
}
diff --git a/Models/StandardModel/SMHGGVertex.cc b/Models/StandardModel/SMHGGVertex.cc
--- a/Models/StandardModel/SMHGGVertex.cc
+++ b/Models/StandardModel/SMHGGVertex.cc
@@ -1,225 +1,226 @@
// -*- C++ -*-
//
// SMHGGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMHGGVertex class.
//
#include "SMHGGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Looptools/clooptools.h"
using namespace Herwig;
using namespace ThePEG;
SMHGGVertex::SMHGGVertex()
:_couplast(0.),_q2last(ZERO),_mw(),massopt(1),_minloop(6),
_maxloop(6),_CoefRepresentation(1) {
orderInGs(2);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
void SMHGGVertex::doinit() {
//PDG codes for particles at vertices
addToList(21,21,25);
_theSM = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
if(!_theSM)
throw InitException();
_mw = getParticleData(ThePEG::ParticleID::Wplus)->mass();
VVSLoopVertex::doinit();
// code to test the partial width
// Energy mh = getParticleData(25)->mass();
// Complex I(0.);
// for(long ix=int(_minloop);ix<=int(_maxloop);++ix) {
// tcPDPtr qrk = getParticleData(ix);
// Energy mt = (2 == massopt) ? _theSM->mass(sqr(mh),qrk) : qrk->mass();
// double lambda = sqr(mt/mh);
// Complex fl;
// if(lambda>=0.25) {
// fl = -2.*sqr(asin(0.5/sqrt(lambda)));
// }
// else {
// double etap = 0.5+sqrt(0.25-lambda);
// double etam = 0.5-sqrt(0.25-lambda);
// fl = 0.5*sqr(log(etap/etam))-0.5*sqr(Constants::pi)
// -Complex(0.,1.)*Constants::pi*log(etap/etam);
// }
// I += 3.*(2.*lambda+lambda*(4.*lambda-1)*fl);
// }
// Energy width = sqr(weakCoupling(sqr(mh))*sqr(strongCoupling(sqr(mh))))/36./8.*sqr(mh/_mw)*mh
// /sqr(4.*sqr(Constants::pi))*std::norm(I)/Constants::pi;
// cerr << "testing anal " << width/GeV << "\n";
if(loopToolsInitialized()) Looptools::ltexi();
}
void SMHGGVertex::persistentOutput(PersistentOStream & os) const {
os << _theSM << ounit(_mw,GeV) << massopt
<< _minloop << _maxloop << _CoefRepresentation;
}
void SMHGGVertex::persistentInput(PersistentIStream & is, int) {
is >> _theSM >> iunit(_mw,GeV) >> massopt
>> _minloop >> _maxloop >> _CoefRepresentation;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMHGGVertex,VVSLoopVertex>
describeHerwigSMHGGVertex("Herwig::SMHGGVertex", "Herwig.so");
void SMHGGVertex::Init() {
static ClassDocumentation<SMHGGVertex> documentation
("This class implements the h->g,g vertex");
static Parameter<SMHGGVertex,int> interfaceMinQuarkInLoop
("MinQuarkInLoop",
"The minimum flavour of the quarks to include in the loops",
&SMHGGVertex::_minloop, 6, 1, 6,
false, false, Interface::limited);
static Parameter<SMHGGVertex,int> interfaceMaxQuarkInLoop
("MaxQuarkInLoop",
"The maximum flavour of the quarks to include in the loops",
&SMHGGVertex::_maxloop, 6, 1, 6,
false, false, Interface::limited);
static Switch<SMHGGVertex,unsigned int> interfaceMassOption
("LoopMassScheme",
"Switch for the treatment of the masses in the loops ",
&SMHGGVertex::massopt, 1, false, false);
static SwitchOption interfaceHeavyMass
(interfaceMassOption,
"PoleMasses",
"The loop is calculcated with the pole quark masses",
1);
static SwitchOption interfaceNormalMass
(interfaceMassOption,
"RunningMasses",
"running quark masses are taken in the loop",
2);
static SwitchOption interfaceInfiniteTopMass
(interfaceMassOption,
"InfiniteTopMass",
"the loop consists of an infinitely massive top quark",
3);
static Switch<SMHGGVertex,unsigned int> interfaceScheme
("CoefficientScheme",
"Which scheme for the tensor coefficients is applied",
&SMHGGVertex::_CoefRepresentation, 1, false, false);
static SwitchOption interfaceSchemeSimplified
(interfaceScheme,
"Simplified",
"Represection suitable for the simplified the H-g-g and H-gamma-gamma vertices",
1);
static SwitchOption interfaceSchemeGeneral
(interfaceScheme,
"General",
"Represection suitable for the Passarino-Veltman tensor reduction scheme",
2);
}
void SMHGGVertex::setCoupling(Energy2 q2, tcPDPtr part2, tcPDPtr part3, tcPDPtr part1) {
assert(part1 && part2 && part3);
assert(part1->id() == ParticleID::h0 &&
part2->id() == ParticleID::g && part3->id() == ParticleID::g );
int Qminloop = _minloop;
int Qmaxloop = _maxloop;
if (_maxloop < _minloop) {
Qmaxloop=_minloop;
Qminloop=_maxloop;
}
if(massopt==3) {
if(q2 != _q2last) {
double g = weakCoupling(q2);
double gs2 = sqr(strongCoupling(q2));
_couplast = UnitRemoval::E * gs2 * g / 16. / _mw/ sqr(Constants::pi);
_q2last = q2;
}
norm(_couplast);
Complex loop(2./3.);
a00( loop); a11(0.0); a12(0.0);
a21(-loop); a22(0.0); aEp(0.0);
return;
}
switch (_CoefRepresentation) {
case 1: {
if(q2 != _q2last||_couplast==0.) {
double g = weakCoupling(q2);
double gs2 = sqr(strongCoupling(q2));
_couplast = UnitRemoval::E * gs2 * g / 16. / _mw/ sqr(Constants::pi);
_q2last = q2;
}
norm(_couplast);
Complex loop(0.);
for ( int i = Qminloop; i <= Qmaxloop; ++i ) {
tcPDPtr qrk = getParticleData(i);
Energy mass = (2 == massopt) ? _theSM->mass(q2,qrk) : qrk->mass();
loop += Af(sqr(mass)/invariant(0,0));
}
a00(loop);
a11(0.0);
a12(0.0);
a21(-loop);
a22(0.0);
aEp(0.0);
break;
}
case 2: {
if (q2 != _q2last) {
Looptools::clearcache();
_couplast = 0.25*sqr(strongCoupling(q2))*weakCoupling(q2);
_q2last = q2;
}
norm(_couplast);
int delta = Qmaxloop - Qminloop + 1;
type.resize(delta,PDT::SpinUnknown);
masses.resize(delta,ZERO);
couplings.clear();
for (int i = 0; i < delta; ++i) {
tcPDPtr q = getParticleData(_minloop+i);
type[i] = PDT::Spin1Half;
masses[i] = (2 == massopt) ? _theSM->mass(q2,q) : q->mass();
const double ratio = masses[i]/_mw;
couplings.push_back(make_pair(ratio, ratio));
}
setNParticles(delta);
VVSLoopVertex::setCoupling(q2, part1, part2, part3);
break;
}
}
}
Complex SMHGGVertex::Af(double tau) const {
return tau*(4.- W2(tau)*(1.-4.*tau));
}
Complex SMHGGVertex::W2(double lambda) const {
double pi = Constants::pi;
if (0.0 == lambda) return 0.0;
else if (lambda < 0.0) return 4.*sqr(asinh(0.5*sqrt(-1./lambda)));
double root(0.5*sqrt(1./lambda));
Complex ac(0.);
// formulae from NPB297,221
if(root < 1.) {
ac = -sqr(asin(root));
}
else {
double ex = acosh(root);
ac = sqr(ex) - 0.25*sqr(pi) - pi*ex*Complex(0.,1.);
}
return 4.*ac;
}
diff --git a/Models/StandardModel/SMHHHVertex.cc b/Models/StandardModel/SMHHHVertex.cc
--- a/Models/StandardModel/SMHHHVertex.cc
+++ b/Models/StandardModel/SMHHHVertex.cc
@@ -1,71 +1,72 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMHHHVertex class.
//
#include "SMHHHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
SMHHHVertex::SMHHHVertex() : ratio_(ZERO), couplast_(0.), q2last_(ZERO) {
orderInGem(1);
orderInGs (0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr SMHHHVertex::clone() const {
return new_ptr(*this);
}
IBPtr SMHHHVertex::fullclone() const {
return new_ptr(*this);
}
void SMHHHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(ratio_,GeV);
}
void SMHHHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(ratio_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMHHHVertex,SSSVertex>
describeHerwigSMHHHVertex("Herwig::SMHHHVertex", "Herwig.so");
void SMHHHVertex::Init() {
static ClassDocumentation<SMHHHVertex> documentation
("The SMHHHVertex class implements the triple Higgs"
" coupling in the Standard Model.");
}
void SMHHHVertex::doinit() {
addToList(25,25,25);
SSSVertex::doinit();
ratio_ = -1.5*sqr(getParticleData(ParticleID::h0)->mass())/
getParticleData(ParticleID::Wplus)->mass();
}
#ifndef NDEBUG
void SMHHHVertex::setCoupling(Energy2 q2,tcPDPtr part1,tcPDPtr part2,tcPDPtr part3) {
#else
void SMHHHVertex::setCoupling(Energy2 q2,tcPDPtr,tcPDPtr,tcPDPtr) {
#endif
assert(part1->id()==ParticleID::h0 &&
part2->id()==ParticleID::h0 &&
part3->id()==ParticleID::h0 );
if(q2!=q2last_||couplast_==0.) {
couplast_ = weakCoupling(q2)*ratio_*UnitRemoval::InvE;
q2last_=q2;
}
norm(couplast_);
}
diff --git a/Models/StandardModel/SMHPPVertex.cc b/Models/StandardModel/SMHPPVertex.cc
--- a/Models/StandardModel/SMHPPVertex.cc
+++ b/Models/StandardModel/SMHPPVertex.cc
@@ -1,285 +1,286 @@
// -*- C++ -*-
//
// SMHPPVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMHPPVertex class.
//
#include "SMHPPVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Looptools/clooptools.h"
using namespace Herwig;
using namespace ThePEG;
void SMHPPVertex::persistentOutput(PersistentOStream & os) const {
os << _theSM << ounit(_mw,GeV) << _massopt << _minloop << _maxloop
<< _CoefRepresentation;
}
void SMHPPVertex::persistentInput(PersistentIStream & is, int) {
is >> _theSM >> iunit(_mw, GeV) >> _massopt >> _minloop >> _maxloop
>> _CoefRepresentation;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMHPPVertex,VVSLoopVertex>
describeHerwigSMHPPVertex("Herwig::SMHPPVertex", "Herwig.so");
void SMHPPVertex::Init() {
static ClassDocumentation<SMHPPVertex> documentation
("This class implements the h0->gamma,gamma vertex.");
static Parameter<SMHPPVertex,int> interfaceMinQuarkInLoop
("MinQuarkInLoop",
"The minimum flavour of the quarks to include in the loops",
&SMHPPVertex::_minloop, 6, 1, 6,
false, false, Interface::limited);
static Parameter<SMHPPVertex,int> interfaceMaxQuarkInLoop
("MaxQuarkInLoop",
"The maximum flavour of the quarks to include in the loops",
&SMHPPVertex::_maxloop, 6, 1, 6,
false, false, Interface::limited);
static Switch<SMHPPVertex,unsigned int> interfaceMassOption
("LoopMassScheme",
"Switch for the treatment of the masses in the loops ",
&SMHPPVertex::_massopt, 2, false, false);
static SwitchOption interfaceHeavyMass
(interfaceMassOption,
"PoleMasses",
"The loop is calculcated with the pole quark masses",
1);
static SwitchOption interfaceNormalMass
(interfaceMassOption,
"RunningMasses",
"running quark masses are taken in the loop",
2);
static Switch<SMHPPVertex,unsigned int> interfaceScheme
("CoefficientScheme",
"Which scheme for the tensor coefficients is applied",
&SMHPPVertex::_CoefRepresentation, 1, false, false);
static SwitchOption interfaceSchemeSimplified
(interfaceScheme,
"Simplified",
"Represection suitable for the simplified the H-g-g and H-gamma-gamma vertices",
1);
static SwitchOption interfaceSchemeGeneral
(interfaceScheme,
"General",
"Represection suitable for the Passarino-Veltman tensor reduction scheme",
2);
}
void SMHPPVertex::setCoupling(Energy2 q2, tcPDPtr part2,
tcPDPtr part3, tcPDPtr part1) {
assert( part1->id() == ParticleID::h0 &&
part2->id() == ParticleID::gamma && part3->id() == ParticleID::gamma );
int Qminloop = _minloop;
int Qmaxloop = _maxloop;
if (_maxloop < _minloop) {
Qmaxloop=_minloop;
Qminloop=_maxloop;
}
switch (_CoefRepresentation) {
case 1: {
if(q2 != _q2last||_couplast==0.) {
double g = weakCoupling(q2);
double e2 = sqr(electroMagneticCoupling(q2));
_couplast = UnitRemoval::E * e2 * g / 8. / _mw/ sqr(Constants::pi);
_q2last = q2;
}
norm(_couplast);
Complex loop(0.);
// quark loops
for ( int i = Qminloop; i <= Qmaxloop; ++i ) {
tcPDPtr qrk = getParticleData(i);
Energy mass = (2 == _massopt) ? _theSM->mass(q2,qrk) : qrk->mass();
Charge charge = qrk->charge();
loop += 3.*sqr(charge/ThePEG::Units::eplus) * Af(sqr(mass)/invariant(0,0));
}
// lepton loops
int Lminloop = 3; // still fixed value
int Lmaxloop = 3; // still fixed value
for (int i = Lminloop; i <= Lmaxloop; ++i) {
tcPDPtr lpt = getParticleData(9 + 2*i);
Energy mass = (2 == _massopt) ? _theSM->mass(q2,lpt) : lpt->mass();
Charge charge = lpt->charge();
loop += sqr(charge/ThePEG::Units::eplus) * Af(sqr(mass)/invariant(0,0));
}
// W loop
loop += Aw(sqr(_mw)/invariant(0,0));
a00(loop);
a11(0.0);
a12(0.0);
a21(-loop);
a22(0.0);
aEp(0.0);
break;
}
case 2: {
if(q2 != _q2last||_couplast==0.) {
Looptools::clearcache();
double e = electroMagneticCoupling(q2);
_couplast = pow(e,3)/sqrt(sin2ThetaW());
_q2last = q2;
}
norm(_couplast);
// quarks
int delta = Qmaxloop - Qminloop + 1;
type.resize(delta,PDT::SpinUnknown);
masses.resize(delta,ZERO);
for (int i = 0; i < delta; ++i) {
tcPDPtr q = getParticleData(_minloop+i);
type[i] = PDT::Spin1Half;
masses[i] = (2 == _massopt) ? _theSM->mass(q2,q) : q->mass();
double copl = -masses[i]*3.*sqr(q->iCharge()/3.)/_mw/2.;
couplings.push_back(make_pair(copl, copl));
}
// tau
type.push_back(PDT::Spin1Half);
tcPDPtr tau = getParticleData(ParticleID::tauminus);
masses.push_back(_theSM->mass(q2,tau));
double copl = -masses.back()*sqr(tau->iCharge()/3.)/_mw/2.;
couplings.push_back(make_pair(copl, copl));
// W
type.push_back(PDT::Spin1);
masses.push_back(_mw);
const double mw = UnitRemoval::InvE*_mw;
couplings.push_back(make_pair(mw,mw));
setNParticles(delta+2);
VVSLoopVertex::setCoupling(q2, part1, part2, part3);
break;
}
}
}
Complex SMHPPVertex::Af(const double tau) const {
return tau*(4. - W2(tau)*(1. - 4.*tau));
}
Complex SMHPPVertex::Aw(const double tau) const {
return 0.5*(-3.*W2(tau)*tau*(4.*tau - 2.) - 12.*tau - 2.);
}
Complex SMHPPVertex::W2(double lambda) const {
double pi = Constants::pi;
if (0.0 == lambda)
return 0.0;
if (lambda < 0.0)
return 4.*sqr(asinh(0.5*sqrt(-1./lambda)));
double root(0.5*sqrt(1./lambda));
Complex ac(0.);
// formulae from NPB297,221
if(root < 1.) {
ac = -sqr(asin(root));
}
else {
double ex = acosh(root);
ac = sqr(ex) - 0.25*sqr(pi) - pi*ex*Complex(0.,1.);
}
return 4.*ac;
}
SMHPPVertex::SMHPPVertex()
:_couplast(0.),_q2last(),_mw(),_massopt(1),
_minloop(6),_maxloop(6),_CoefRepresentation(1) {
orderInGs(0);
orderInGem(3);
+ colourStructure(ColourStructure::SINGLET);
}
// functions for loops for testing
// namespace {
// Complex F0(double tau) {
// Complex ft;
// if(tau>=1.)
// ft = sqr(asin(1./sqrt(tau)));
// else {
// double etap = 1.+sqrt(1.-tau);
// double etam = 1.-sqrt(1.-tau);
// ft = -0.25*sqr(log(etap/etam)-Constants::pi*Complex(0.,1.));
// }
// return tau*(1.-tau*ft);
// }
// Complex FHalf(double tau,double eta) {
// Complex ft;
// if(tau>=1.)
// ft = sqr(asin(1./sqrt(tau)));
// else {
// double etap = 1.+sqrt(1.-tau);
// double etam = 1.-sqrt(1.-tau);
// ft = -0.25*sqr(log(etap/etam)-Constants::pi*Complex(0.,1.));
// }
// return -2.*tau*(eta+(1.-tau*eta)*ft);
// }
// Complex F1(double tau) {
// Complex ft;
// if(tau>=1.)
// ft = sqr(asin(1./sqrt(tau)));
// else {
// double etap = 1.+sqrt(1.-tau);
// double etam = 1.-sqrt(1.-tau);
// ft = -0.25*sqr(log(etap/etam)-Constants::pi*Complex(0.,1.));
// }
// return 2.+3.*tau+3.*tau*(2.-tau)*ft;
// }
// }
void SMHPPVertex::doinit() {
//PDG codes for particles at vertices
addToList(22,22,25);
_theSM = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
if( !_theSM )
throw InitException()
<< "SMHGGVertex::doinit() - The pointer to the SM object is null."
<< Exception::abortnow;
_mw = getParticleData(ThePEG::ParticleID::Wplus)->mass();
VVSLoopVertex::doinit();
// // code to test the partial width
// Energy mh = getParticleData(25)->mass();
// Complex I(0.);
// for(long ix=int(_minloop);ix<=int(_maxloop);++ix) {
// tcPDPtr qrk = getParticleData(ix);
// Energy mt = (2 == _massopt) ? _theSM->mass(sqr(mh),qrk) : qrk->mass();
// double tau = sqr(2.*mt/mh);
// I += 3.*sqr(double(qrk->iCharge())/3.)*FHalf(tau,1.);
// cerr << "testing half " << FHalf(tau,1) << " " << Af(0.25*tau) << "\n";
// }
// for(long ix=15;ix<=15;++ix) {
// tcPDPtr qrk = getParticleData(ix);
// Energy mt = (2 == _massopt) ? _theSM->mass(sqr(mh),qrk) : qrk->mass();
// double tau = sqr(2.*mt/mh);
// I += sqr(double(qrk->iCharge())/3.)*FHalf(tau,1.);
// }
// I += F1(sqr(2.*_mw/mh));
// Energy width = sqr(weakCoupling(sqr(mh))*sqr(electroMagneticCoupling(sqr(mh))))
// /1024./pow(Constants::pi,5)/16.*sqr(mh/_mw)*mh*std::norm(I);
// cerr << "testing anal " << width/GeV << "\n";
if(loopToolsInitialized()) Looptools::ltexi();
}
diff --git a/Models/StandardModel/SMHZPVertex.cc b/Models/StandardModel/SMHZPVertex.cc
--- a/Models/StandardModel/SMHZPVertex.cc
+++ b/Models/StandardModel/SMHZPVertex.cc
@@ -1,187 +1,188 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMHZPVertex class.
//
#include "SMHZPVertex.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"
using namespace Herwig;
SMHZPVertex::SMHZPVertex()
:_couplast(0.),_q2last(),_mw(),_mz(),_massopt(1),
_minloop(6),_maxloop(6) {
orderInGs(0);
orderInGem(3);
kinematics(true);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr SMHZPVertex::clone() const {
return new_ptr(*this);
}
IBPtr SMHZPVertex::fullclone() const {
return new_ptr(*this);
}
void SMHZPVertex::doinit() {
GeneralVVSVertex::doinit();
//PDG codes for particles at vertices
addToList(23,22,25);
_theSM = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
if( !_theSM )
throw InitException()
<< "SMHGGVertex::doinit() - The pointer to the SM object is null."
<< Exception::abortnow;
_mw = getParticleData(ThePEG::ParticleID::Wplus)->mass();
_mz = getParticleData(ThePEG::ParticleID::Z0)->mass();
GeneralVVSVertex::doinit();
}
void SMHZPVertex::persistentOutput(PersistentOStream & os) const {
os << _theSM << ounit(_mw,GeV) << ounit(_mz,GeV) << _massopt
<< _minloop << _maxloop;
}
void SMHZPVertex::persistentInput(PersistentIStream & is, int) {
is >> _theSM >> iunit(_mw, GeV) >> iunit(_mz,GeV) >> _massopt
>> _minloop >> _maxloop;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMHZPVertex,GeneralVVSVertex>
describeHerwigSMHZPVertex("Herwig::SMHZPVertex", "libHerwig.so");
void SMHZPVertex::Init() {
static ClassDocumentation<SMHZPVertex> documentation
("The SMHZPVertex class provides a simple implementation of the "
"Higgs-Z-Photon loop looping to allow the calculation of the "
"associated Higgs decay mode H -> Z gamma.");
static Parameter<SMHZPVertex,int> interfaceMinQuarkInLoop
("MinQuarkInLoop",
"The minimum flavour of the quarks to include in the loops",
&SMHZPVertex::_minloop, 6, 1, 6,
false, false, Interface::limited);
static Parameter<SMHZPVertex,int> interfaceMaxQuarkInLoop
("MaxQuarkInLoop",
"The maximum flavour of the quarks to include in the loops",
&SMHZPVertex::_maxloop, 6, 1, 6,
false, false, Interface::limited);
static Switch<SMHZPVertex,unsigned int> interfaceMassOption
("LoopMassScheme",
"Switch for the treatment of the masses in the loops ",
&SMHZPVertex::_massopt, 2, false, false);
static SwitchOption interfaceHeavyMass
(interfaceMassOption,
"PoleMasses",
"The loop is calculcated with the pole quark masses",
1);
static SwitchOption interfaceNormalMass
(interfaceMassOption,
"RunningMasses",
"running quark masses are taken in the loop",
2);
}
void SMHZPVertex::setCoupling(Energy2 q2, tcPDPtr part2,
tcPDPtr part3, tcPDPtr part1) {
if(part3->id()==ParticleID::Z0) swap(part2,part3);
assert( part1->id() == ParticleID::h0 &&
part2->id() == ParticleID::Z0 && part3->id() == ParticleID::gamma );
int Qminloop = _minloop;
int Qmaxloop = _maxloop;
if (_maxloop < _minloop) swap(Qmaxloop,Qminloop);
double cw = sqrt(1.-sin2ThetaW()),sw=sqrt(sin2ThetaW()),tw = sw/cw;
if(q2 != _q2last||_couplast==0.) {
double g = weakCoupling(q2);
double e2 = sqr(electroMagneticCoupling(q2));
_couplast = UnitRemoval::E * e2 * g / 16. / _mw/ sqr(Constants::pi);
_q2last = q2;
}
norm(_couplast);
Complex loop(0.);
// quark loops
for ( int i = Qminloop; i <= Qmaxloop; ++i ) {
tcPDPtr qrk = getParticleData(i);
Energy mass = (2 == _massopt) ? _theSM->mass(q2,qrk) : qrk->mass();
double charge = i%2==0 ?
generator()->standardModel()->eu() : generator()->standardModel()->ed();
double gv = i%2==0 ?
generator()->standardModel()->vu() : generator()->standardModel()->vd();
double tau = 0.25*invariant(0,0)/sqr(mass), lambda(0.25*sqr(_mz/mass));
loop += 3.*charge*gv *(I1(tau,lambda)-I2(tau,lambda))/(sw*cw);
}
// lepton loops
int Lminloop = 3; // still fixed value
int Lmaxloop = 3; // still fixed value
for (int i = Lminloop; i <= Lmaxloop; ++i) {
tcPDPtr lpt = getParticleData(9 + 2*i);
Energy mass = (2 == _massopt) ? _theSM->mass(q2,lpt) : lpt->mass();
double charge = generator()->standardModel()->ee();
double gv = generator()->standardModel()->ve();
double tau = 0.25*invariant(0,0)/sqr(mass), lambda(0.25*sqr(_mz/mass));
loop += charge*gv*(I1(tau,lambda)-I2(tau,lambda))/(sw*cw);
}
// W loop
double tau = 0.25*invariant(0,0)/sqr(_mw), lambda(0.25*sqr(_mz/_mw));
loop += ( 4.*(3.-sqr(tw))*I2(tau,lambda) +
((1.+2.*tau)*sqr(tw)-(5.+2.*tau))*I1(tau,lambda))/tw;
a00(loop);
a11(0.0);
a12(0.0);
a21(-loop);
a22(0.0);
aEp(0.0);
// test of the width calculation
// Energy mh = getParticleData(25)->mass();
// Energy pre = sqr(weakCoupling(q2))*pow(electroMagneticCoupling(q2),4)*mh*sqr(mh/_mw)
// /128./16./pow(Constants::pi,5)*pow(double(1.-sqr(_mz/mh)),3)*
// std::real(std::norm(loop));
}
Complex SMHZPVertex::I1(double tau,double lambda) const {
return (-0.5+0.5/(tau-lambda)*(f(tau)-f(lambda))+
lambda/(tau-lambda)*(g(tau)-g(lambda)))/(tau-lambda);
}
Complex SMHZPVertex::I2(double tau,double lambda) const {
return 0.5/(tau-lambda)*(f(tau)-f(lambda));
}
Complex SMHZPVertex::f(double tau) const {
if(tau>0 && tau<= 1.) {
return sqr(asin(sqrt(tau)));
}
else if(tau>1.) {
double lx = log(sqrt(tau)+sqrt(tau-1));
return -sqr(lx)+0.25*sqr(Constants::pi)+Complex(0.,1.)*Constants::pi*lx;
}
else
assert(false);
}
Complex SMHZPVertex::g(double tau) const {
if(tau>0 && tau<= 1.) {
return sqrt((1.-tau)/tau)*asin(sqrt(tau));
}
else if(tau>1.) {
double lx = log(sqrt(tau)+sqrt(tau-1));
double root = sqrt((tau-1.)/tau);
return root*(lx-0.5*Complex(0,1)*Constants::pi);
}
else
assert(false);
}
diff --git a/Models/StandardModel/SMWWHHVertex.cc b/Models/StandardModel/SMWWHHVertex.cc
--- a/Models/StandardModel/SMWWHHVertex.cc
+++ b/Models/StandardModel/SMWWHHVertex.cc
@@ -1,74 +1,75 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMWWHHVertex class.
//
#include "SMWWHHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
SMWWHHVertex::SMWWHHVertex() : ratio_(0.), couplast_(0.), q2last_(ZERO) {
orderInGem(2);
orderInGs (0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr SMWWHHVertex::clone() const {
return new_ptr(*this);
}
IBPtr SMWWHHVertex::fullclone() const {
return new_ptr(*this);
}
void SMWWHHVertex::persistentOutput(PersistentOStream & os) const {
os << ratio_;
}
void SMWWHHVertex::persistentInput(PersistentIStream & is, int) {
is >> ratio_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMWWHHVertex,Helicity::VVSSVertex>
describeHerwigSMWWHHVertex("Herwig::SMWWHHVertex", "Herwig.so");
void SMWWHHVertex::Init() {
static ClassDocumentation<SMWWHHVertex> documentation
("The SMWWHHVertex class implements the coupling of two electroweeak"
" gauge bosons and the Higgs boson in the Standard Model.");
}
void SMWWHHVertex::doinit() {
addToList( 23, 23, 25, 25);
addToList( 24,-24, 25, 25);
VVSSVertex::doinit();
ratio_ = 1./(1.-sin2ThetaW());
}
void SMWWHHVertex::setCoupling(Energy2 q2,
tcPDPtr part1,tcPDPtr,
#ifndef NDEBUG
tcPDPtr part3,tcPDPtr part4) {
#else
tcPDPtr,tcPDPtr) {
#endif
assert(part3->id()==ParticleID::h0 && part4->id()==ParticleID::h0 );
if(q2!=q2last_||couplast_==0.) {
couplast_ = sqr(weakCoupling(q2));
q2last_=q2;
}
if(part1->id()==ParticleID::Z0) {
norm(0.5*couplast_*ratio_);
}
else {
norm(0.5*couplast_);
}
}
diff --git a/Models/StandardModel/SMWWHVertex.cc b/Models/StandardModel/SMWWHVertex.cc
--- a/Models/StandardModel/SMWWHVertex.cc
+++ b/Models/StandardModel/SMWWHVertex.cc
@@ -1,71 +1,72 @@
// -*- C++ -*-
//
// SMWWHVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the WWHVertex class.
//
#include "SMWWHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
SMWWHVertex::SMWWHVertex()
: _couplast(0.), _q2last(ZERO), _mw(ZERO), _zfact(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void SMWWHVertex::doinit() {
addToList(24,-24, 25);
addToList(23, 23, 25);
// parameters
_mw = getParticleData(ThePEG::ParticleID::Wplus)->mass();
_zfact = 1./(1.-sin2ThetaW());
// base class
VVSVertex::doinit();
}
void SMWWHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(_mw,GeV) << _zfact;
}
void SMWWHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(_mw,GeV) >> _zfact;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMWWHVertex,VVSVertex>
describeHerwigSMWWHVertex("Herwig::SMWWHVertex", "Herwig.so");
void SMWWHVertex::Init() {
static ClassDocumentation<SMWWHVertex> documentation
("The SMWWHVertex class is the implementation"
" of the helicity amplitude calculation for the coupling of the Standard"
" Model electroweak gauge bosons to the Higgs.");
}
void SMWWHVertex::setCoupling(Energy2 q2,tcPDPtr aa,tcPDPtr, tcPDPtr) {
int ibos=abs(aa->id());
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = weakCoupling(q2) * UnitRemoval::InvE * _mw;
_q2last=q2;
}
if(ibos==24) norm(_couplast);
else if(ibos==23) norm(_couplast*_zfact);
else
throw HelicityConsistencyError() << "SMWWHVertex::setCoupling "
<< "Invalid particles in WWH Vertex"
<< Exception::runerror;
}
diff --git a/Models/StandardModel/SMWWWVertex.cc b/Models/StandardModel/SMWWWVertex.cc
--- a/Models/StandardModel/SMWWWVertex.cc
+++ b/Models/StandardModel/SMWWWVertex.cc
@@ -1,89 +1,90 @@
// -*- C++ -*-
//
// SMWWWVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMWWWVertex class.
//
#include "SMWWWVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
void SMWWWVertex::persistentOutput(PersistentOStream & os) const {
os << _zfact;
}
void SMWWWVertex::persistentInput(PersistentIStream & is, int) {
is >> _zfact;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMWWWVertex,Helicity::VVVVertex>
describeHerwigSMWWWVertex("Herwig::SMWWWVertex", "Herwig.so");
void SMWWWVertex::Init() {
static ClassDocumentation<SMWWWVertex> documentation
("The SMWWWVertex class is the implementation of the "
"Standard Model triple electroweak boson coupling.");
}
// couplings for the WWW vertex
void SMWWWVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b, tcPDPtr c) {
int ida=a->id();
int idb=b->id();
int idc=c->id();
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = electroMagneticCoupling(q2);
_q2last=q2;
}
// W- W+ photon and cylic perms
if((ida==-24 && idb== 24 && idc== 22) ||
(ida== 22 && idb==-24 && idc== 24) ||
(ida== 24 && idb== 22 && idc==-24) ) norm(_couplast);
// W+ W- photon (anticylic perms of above)
else if((ida== 24 && idb==-24 && idc== 22) ||
(ida== 22 && idb== 24 && idc==-24) ||
(ida==-24 && idb== 22 && idc== 24) ) norm(-_couplast);
// W- W+ Z and cylic perms
else if((ida==-24 && idb== 24 && idc== 23) ||
(ida== 23 && idb==-24 && idc== 24) ||
(ida== 24 && idb== 23 && idc==-24) ) norm(_couplast*_zfact);
// W+ W- Z (anticylic perms of above)
else if((ida== 24 && idb==-24 && idc== 23) ||
(ida== 23 && idb== 24 && idc==-24) ||
(ida==-24 && idb== 23 && idc== 24) ) norm(-_couplast*_zfact);
else
throw Helicity::HelicityConsistencyError()
<< "SMWWWVertex::setCoupling "
<< "Invalid particles in WWW Vertex"
<< a->PDGName() << " " << b->PDGName() << " " << c->PDGName()
<< Exception::runerror;
}
SMWWWVertex::SMWWWVertex() : _zfact(0.),_couplast(0.),
_q2last(sqr(Constants::MaxEnergy)) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void SMWWWVertex::doinit() {
addToList(24, -24, 22);
addToList(24, -24, 23);
VVVVertex::doinit();
// factor for the Z vertex
double sw2=sin2ThetaW();
_zfact = sqrt((1.-sw2)/sw2);
}
diff --git a/Models/StandardModel/SMWWWWVertex.cc b/Models/StandardModel/SMWWWWVertex.cc
--- a/Models/StandardModel/SMWWWWVertex.cc
+++ b/Models/StandardModel/SMWWWWVertex.cc
@@ -1,167 +1,168 @@
// -*- C++ -*-
//
// SMWWWWVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SMWWWWVertex class.
//
#include "SMWWWWVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
using namespace ThePEG;
SMWWWWVertex::SMWWWWVertex()
: _couplast(0.0), _q2last(sqr(Constants::MaxEnergy)),
_vfact(4,0.0), _sw2(0.), _cw2(0.) {
orderInGem(2);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void SMWWWWVertex::doinit() {
// particles
addToList(24, -24, 24, -24);
addToList(23, 24, 23, -24);
addToList(22, 24, 22, -24);
addToList(22, 24, 23, -24);
VVVVVertex::doinit();
// couplings
_sw2 = sin2ThetaW();
_cw2 = 1.-_sw2;
double sw = sqrt(_sw2);
double cw = sqrt(_cw2);
_vfact[0] = -1./_sw2;
_vfact[1] = _cw2/_sw2;
_vfact[2] = 1.;
_vfact[3] = cw/sw;
// pointer for intermediate particles
_gamma = getParticleData(ThePEG::ParticleID::gamma);
_Z0 = getParticleData(ThePEG::ParticleID::Z0);
_wplus = getParticleData(ThePEG::ParticleID::Wplus);
_wminus = getParticleData(ThePEG::ParticleID::Wminus);
}
void SMWWWWVertex::persistentOutput(PersistentOStream & os) const {
os << _gamma << _Z0 << _wplus << _wminus
<< _vfact << _sw2 << _cw2;
}
void SMWWWWVertex::persistentInput(PersistentIStream & is, int) {
is >> _gamma >> _Z0 >> _wplus >> _wminus
>> _vfact >> _sw2 >> _cw2;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SMWWWWVertex,VVVVVertex>
describeHerwigSMWWWWVertex("Herwig::SMWWWWVertex", "Herwig.so");
void SMWWWWVertex::Init() {
static ClassDocumentation<SMWWWWVertex> documentation
("The SMWWWWVertex class is the implementation of the"
" Standard Model quartic electroweka gauge boson coupling.");
}
// couplings for the WWWW vertex
void SMWWWWVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,
tcPDPtr c,tcPDPtr d) {
// id's of the particles
long id[4]={a->id(),b->id(),c->id(),d->id()};
// order the particles
int ngamma(0),nz(0);
int iorder[4];
for(int ix=0;ix<4;++ix) {
if (id[ix]==22) ++ngamma;
else if (id[ix]==23) ++nz;
}
// if photons or Z's
if(ngamma!=0 || nz!=0) {
int iy=0;
// put the photons first
for(int ix=0;iy<ngamma&&ix<4;++ix) {
if(id[ix]==22) {
iorder[iy]=ix;
++iy;
}
}
// then the Z bosons
for(int ix=0;iy<ngamma+nz&&ix<4;++ix) {
if(id[ix]==23) {
iorder[iy]=ix;
++iy;
}
}
// then the W+
for(int ix=0;iy<3&&ix<4;++ix) {
if(id[ix]==24) {
iorder[iy]=ix;
++iy;
}
}
assert(iy==3);
// finally the W-
for(int ix=0;iy<4&&ix<4;++ix) {
if(id[ix]==-24) {
iorder[iy]=ix;
++iy;
}
}
assert(iy==4);
}
else {
int iy=0;
// first the W+
for(int ix=0;iy<3&&ix<4;++ix) {
if(id[ix]==24) {
iorder[iy]=ix;
++iy;
}
}
assert(iy==2);
// finally the W-
for(int ix=0;iy<4&&ix<4;++ix) {
if(id[ix]==-24) {
iorder[iy]=ix;
++iy;
}
}
assert(iy==4);
setIntermediate(_gamma,_Z0,_sw2,_cw2);
}
setOrder(iorder[0],iorder[1],iorder[2],iorder[3]);
setType(2);
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = sqr(electroMagneticCoupling(q2));
_q2last=q2;
}
// id's of the first two particles
int ida(0),idb(0);
if(iorder[0]==0) ida = abs(a->id());
else if(iorder[0]==1) ida = abs(b->id());
else if(iorder[0]==2) ida = abs(c->id());
else if(iorder[0]==3) ida = abs(d->id());
if(iorder[1]==0) idb = abs(a->id());
else if(iorder[1]==1) idb = abs(b->id());
else if(iorder[1]==2) idb = abs(c->id());
else if(iorder[1]==3) idb = abs(d->id());
// WWWW coupling
if(ida==24) norm(_vfact[0]*_couplast);
// ZZWW coupling
else if(ida==23&&idb==23) norm(_vfact[1]*_couplast);
// gamma gamma WW coupling
else if(ida==22&&idb==22) norm(_couplast);
// gamma Z WW coupling
else if(ida==22&&idb==23) norm(_vfact[3]*_couplast);
else assert(false);
}
diff --git a/Models/StandardModel/StandardModel.cc b/Models/StandardModel/StandardModel.cc
--- a/Models/StandardModel/StandardModel.cc
+++ b/Models/StandardModel/StandardModel.cc
@@ -1,200 +1,207 @@
// -*- C++ -*-
//
// StandardModel.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the StandardModel class.
//
#include "StandardModel.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/General/ModelGenerator.h"
#include "ThePEG/Repository/BaseRepository.h"
using namespace Herwig;
StandardModel::StandardModel() {}
StandardModel::~StandardModel() {}
StandardModel::StandardModel(const StandardModel & x)
: StandardModelBase(x),
FFZVertex_ (x.FFZVertex_),
FFPVertex_ (x.FFPVertex_) , FFGVertex_ (x.FFGVertex_) ,
FFWVertex_ (x.FFWVertex_) , FFHVertex_ (x.FFHVertex_) ,
WWHVertex_ (x.WWHVertex_) ,
GGGVertex_ (x.GGGVertex_) ,
WWWVertex_ (x.WWWVertex_) , GGGGVertex_(x.GGGGVertex_),
WWWWVertex_(x.WWWWVertex_), HGGVertex_ (x.HGGVertex_) ,
HPPVertex_ (x.HPPVertex_) , HHHVertex_ (x.HHHVertex_) ,
WWHHVertex_ (x.WWHHVertex_) ,
vertexList_(x.vertexList_), extraVertices_(x.extraVertices_),
- runningMass_(x.runningMass_),modelGenerator_(x.modelGenerator_)
+ runningMass_(x.runningMass_),modelGenerator_(x.modelGenerator_),
+ couplings_(x.couplings_)
{}
IBPtr StandardModel::clone() const {
return new_ptr(*this);
}
IBPtr StandardModel::fullclone() const {
return new_ptr(*this);
}
void StandardModel::doinit() {
if(runningMass_) {
runningMass_->init();
}
//add Standard Model vertices
if ( registerDefaultVertices() ) {
addVertex(FFZVertex_);
addVertex(FFPVertex_);
addVertex(FFGVertex_);
addVertex(FFWVertex_);
addVertex(vertexFFH());
addVertex(vertexWWH());
addVertex(GGGVertex_);
addVertex(WWWVertex_);
addVertex(GGGGVertex_);
addVertex(WWWWVertex_);
addVertex(vertexHGG());
addVertex(HPPVertex_);
if(HHHVertex_ ) addVertex(HHHVertex_);
if(WWHHVertex_) addVertex(WWHHVertex_);
}
+ if(couplings_.find("QED")==couplings_.end()) {
+ couplings_["QED"] = make_pair(1,99);
+ }
+ if(couplings_.find("QCD")==couplings_.end()) {
+ couplings_["QCD"] = make_pair(2,99);
+ }
StandardModelBase::doinit();
}
void StandardModel::persistentOutput(PersistentOStream & os) const {
os << FFZVertex_ <<FFPVertex_ << FFGVertex_ << FFWVertex_
<< FFHVertex_ << WWHVertex_ << GGGGVertex_ << WWWWVertex_
<< GGGVertex_ << WWWVertex_ << HGGVertex_ << HPPVertex_
<< HHHVertex_ << WWHHVertex_
<< runningMass_ << vertexList_ << extraVertices_ << modelGenerator_;
}
void StandardModel::persistentInput(PersistentIStream & is, int) {
is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_ >> FFWVertex_
>> FFHVertex_ >> WWHVertex_ >> GGGGVertex_ >> WWWWVertex_
>> GGGVertex_ >> WWWVertex_ >> HGGVertex_ >> HPPVertex_
>> HHHVertex_ >> WWHHVertex_
>> runningMass_ >> vertexList_ >> extraVertices_ >> modelGenerator_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<StandardModel,StandardModelBase>
describeHerwigStandardModel("Herwig::StandardModel", "Herwig.so");
void StandardModel::Init() {
static Reference<StandardModel,AbstractFFVVertex> interfaceVertexFFZ
("Vertex/FFZ",
"Reference to the Standard Model FFZ Vertex",
&StandardModel::FFZVertex_, false, false, true, false);
static Reference<StandardModel,AbstractFFVVertex> interfaceVertexFFP
("Vertex/FFP",
"Reference to the Standard Model FFP Vertex",
&StandardModel::FFPVertex_, false, false, true, false);
static Reference<StandardModel,AbstractFFVVertex> interfaceVertexFFG
("Vertex/FFG",
"Reference to the Standard Model FFG Vertex",
&StandardModel::FFGVertex_, false, false, true, false);
static Reference<StandardModel,AbstractFFVVertex> interfaceVertexFFW
("Vertex/FFW",
"Reference to the Standard Model FFW Vertex",
&StandardModel::FFWVertex_, false, false, true, false);
static Reference<StandardModel,AbstractFFSVertex> interfaceVertexFFH
("Vertex/FFH",
"Reference to the Standard Model FFH Vertex.",
&StandardModel::FFHVertex_, false, false, true, false);
static Reference<StandardModel,AbstractVVVVertex> interfaceVertexGGG
("Vertex/GGG",
"Reference to the Standard Model GGG Vertex",
&StandardModel::GGGVertex_, false, false, true, false);
static Reference<StandardModel,AbstractVVVVertex> interfaceVertexWWW
("Vertex/WWW",
"Reference to the Standard Model WWW Vertex",
&StandardModel::WWWVertex_, false, false, true, false);
static Reference<StandardModel,AbstractVVSVertex> interfaceVertexWWH
("Vertex/WWH",
"Reference to the Standard Model WWH Vertex",
&StandardModel::WWHVertex_, false, false, true, false);
static Reference<StandardModel,AbstractVVVVVertex> interfaceVertexWWWW
("Vertex/WWWW",
"Reference to the Standard Model WWWW Vertex",
&StandardModel::WWWWVertex_, false, false, true, false);
static Reference<StandardModel,AbstractVVVVVertex> interfaceVertexGGGG
("Vertex/GGGG",
"Reference to the Standard Model GGGG Vertex",
&StandardModel::GGGGVertex_, false, false, true, false);
static Reference<StandardModel,AbstractVVSVertex> interfaceVertexHGG
("Vertex/HGG",
"Reference to the StandardModel HGG Vertex",
&StandardModel::HGGVertex_, false, false, true, false);
static Reference<StandardModel,AbstractVVSVertex> interfaceVertexHPP
("Vertex/HPP",
"Reference to StandardModel HPPVertex",
&StandardModel::HPPVertex_, false, false, true, false);
static Reference<StandardModel,AbstractSSSVertex> interfaceVertexHHH
("Vertex/HHH",
"Reference to the Standard Model HHHVertex",
&StandardModel::HHHVertex_, false, false, true, true);
static Reference<StandardModel,AbstractVVSSVertex> interfaceVertexWWHH
("Vertex/WWHH",
"Reference to the Standard Model WWHHVertex",
&StandardModel::WWHHVertex_, false, false, true, true);
static RefVector<StandardModel,VertexBase> interfaceExtraVertices
("ExtraVertices",
"Additional vertices to be considered in automatic ME construction.",
&StandardModel::extraVertices_, -1, true, false, true, false, false);
static Reference<StandardModel,RunningMassBase> interfaceRunningMass
("RunningMass",
"Reference to the running mass object",
&StandardModel::runningMass_, false, false, true, false);
static Reference<StandardModel,Herwig::ModelGenerator> interfaceModelGenerator
("ModelGenerator",
"Pointer to ModelGenerator class",
&StandardModel::modelGenerator_, false, false, true, true);
static ClassDocumentation<StandardModel> documentation
("The StandardModel class inherits from StandardModelBase"
"and supplies additional couplings and access to the StandardModel"
"vertices for helicity amplitude calculations" );
}
void StandardModel::resetMass(long id, Energy mass,tPDPtr part) {
if(!part) part = getParticleData(id);
if(!part) return;
const InterfaceBase * ifb = BaseRepository::FindInterface(part, "NominalMass");
ostringstream os;
os << setprecision(12) << abs(mass/GeV);
ifb->exec(*part, "set", os.str());
}
diff --git a/Models/StandardModel/StandardModel.h b/Models/StandardModel/StandardModel.h
--- a/Models/StandardModel/StandardModel.h
+++ b/Models/StandardModel/StandardModel.h
@@ -1,458 +1,478 @@
// -*- C++ -*-
//
// StandardModel.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_StandardModel_H
#define HERWIG_StandardModel_H
//
// This is the declaration of the StandardModel class.
#include "ThePEG/StandardModel/StandardModelBase.h"
#include "Herwig/Models/StandardModel/RunningMassBase.h"
#include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVVVVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractSSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractVVSSVertex.h"
#include "ThePEG/Helicity/Vertex/AbstractSSSSVertex.h"
#include "Herwig/Models/General/ModelGenerator.fh"
#include "StandardModel.fh"
namespace Herwig {
using namespace ThePEG;
using namespace ThePEG::Helicity;
/** \ingroup Models
*
* This is the Herwig StandardModel class which inherits from ThePEG
* Standard Model class and implements additional Standard Model couplings,
* access to vertices for helicity amplitude calculations etc.
*
* @see StandardModelBase
*/
class StandardModel: public StandardModelBase {
/**
* Some typedefs for the pointers.
*/
//@{
/**
* Pointer to the RunningMassBase object
*/
typedef Ptr<Herwig::RunningMassBase>::pointer runPtr;
/**
* Transient pointer to the RunningMassBase object
*/
typedef Ptr<Herwig::RunningMassBase>::transient_pointer trunPtr;
//@}
public:
/** @name Standard constructors and destructors. */
//@{
/**
* Default constructor
*/
StandardModel();
/**
* Copy-constructor.
*/
StandardModel(const StandardModel &);
/**
* Destructor
*/
virtual ~StandardModel();
//@}
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* Standard Init function used to initialize the interfaces.
*/
static void Init();
protected:
/**
* Should the default vertices be considered for generic diagrams
*/
virtual bool registerDefaultVertices() const { return true; }
public:
/**
* The left and right couplings of the Z^0 including sin and cos theta_W.
*/
//@{
/**
* The left-handed coupling of a neutrino
*/
double lnu() const {
return 0.25/sqrt(sin2ThetaW()*(1.-sin2ThetaW()))*(vnu()+anu());
}
/**
* The left-handed coupling of a charged lepton.
*/
double le() const {
return 0.25/sqrt(sin2ThetaW()*(1.-sin2ThetaW()))*(ve()+ae());
}
/**
* The left-handed coupling of an up type quark.
*/
double lu() const {
return 0.25/sqrt(sin2ThetaW()*(1.-sin2ThetaW()))*(vu()+au());
}
/**
* The left-handed coupling of a down type quark.
*/
double ld() const {
return 0.25/sqrt(sin2ThetaW()*(1.-sin2ThetaW()))*(vd()+ad());
}
/**
* The right-handed coupling of a neutrino
*/
double rnu() const {
return 0.25/sqrt(sin2ThetaW()*(1.-sin2ThetaW()))*(vnu()-anu());
}
/**
* The right-handed coupling of a charged lepton.
*/
double re() const {
return 0.25/sqrt(sin2ThetaW()*(1.-sin2ThetaW()))*(ve()-ae());
}
/**
* The right-handed coupling of an up type quark.
*/
double ru() const {
return 0.25/sqrt(sin2ThetaW()*(1.-sin2ThetaW()))*(vu()-au());
}
/**
* The right-handed coupling of a down type quark.
*/
double rd() const {
return 0.25/sqrt(sin2ThetaW()*(1.-sin2ThetaW()))*(vd()-ad());
}
//@}
/**
* Pointers to the objects handling the vertices.
*/
//@{
/**
* Pointer to the fermion-fermion-Z vertex
*/
virtual tAbstractFFVVertexPtr vertexFFZ() const {
return FFZVertex_;
}
/**
* Pointer to the fermion-fermion-photon vertex
*/
virtual tAbstractFFVVertexPtr vertexFFP() const {
return FFPVertex_;
}
/**
* Pointer to the fermion-fermion-gluon vertex
*/
virtual tAbstractFFVVertexPtr vertexFFG() const {
return FFGVertex_;
}
/**
* Pointer to the fermion-fermion-W vertex
*/
virtual tAbstractFFVVertexPtr vertexFFW() const {
return FFWVertex_;
}
/**
* Pointer to the fermion-fermion-Higgs vertex
*/
virtual tAbstractFFSVertexPtr vertexFFH() const {
return FFHVertex_;
}
/**
* Pointer to the triple gluon vertex
*/
virtual tAbstractVVVVertexPtr vertexGGG() const {
return GGGVertex_;
}
/**
* Pointer to the triple electroweak gauge boson vertex.
*/
virtual tAbstractVVVVertexPtr vertexWWW() const {
return WWWVertex_;
}
/**
* Pointer to the two electroweak gauge boson Higgs vertex.
*/
virtual tAbstractVVSVertexPtr vertexWWH() const {
return WWHVertex_;
}
/**
* Pointer to the quartic electroweak gauge boson vertex.
*/
virtual tAbstractVVVVVertexPtr vertexWWWW() const {
return WWWWVertex_;
}
/**
* Pointer to the quartic gluon vertex
*/
virtual tAbstractVVVVVertexPtr vertexGGGG() const {
return GGGGVertex_;
}
/**
* Pointer to the quartic gluon vertex
*/
virtual tAbstractVVSVertexPtr vertexHGG() const {
return HGGVertex_;
}
/**
* Pointer to the quartic gluon vertex
*/
virtual tAbstractVVSVertexPtr vertexHPP() const {
return HPPVertex_;
}
/**
* Pointer to the triple Higgs vertex
*/
virtual tAbstractSSSVertexPtr vertexHHH() const {
return HHHVertex_;
}
/**
* Pointer to the WWHH vertex
*/
virtual tAbstractVVSSVertexPtr vertexWWHH() const {
return WWHHVertex_;
}
/**
* Total number of vertices
*/
unsigned int numberOfVertices() const {
return vertexList_.size() + extraVertices_.size();
}
/**
* Access to a vertex from the list
*/
tVertexBasePtr vertex(size_t ix) const {
const size_t S = vertexList_.size();
if ( ix < S )
return vertexList_[ix];
else
return extraVertices_[ix - S];
}
//@}
/**
* Return the running mass for a given scale \f$q^2\f$ and particle type.
* @param scale The scale \f$q^2\f$.
* @param part The ParticleData object for the particle
*/
Energy mass(Energy2 scale,tcPDPtr part) const {
return runningMass_->value(scale,part);
}
/**
* Return a pointer to the object handling the running mass.
*/
trunPtr massPtr() const {
return runningMass_;
}
+
+ /**
+ * Set the couplings in the model
+ */
+ const map<string,pair<unsigned int,int> > & couplings() const {
+ return couplings_;
+ }
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:
/**
* Initialize this object after the setup phase before saving and
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
//@}
protected:
/**
* Add a vertex to the list
*/
void addVertex(VertexBasePtr in) {
if ( in )
vertexList_.push_back(in);
}
/**
* Helper function to reset the mass of a ParticleData object
* in BSM models.
*/
void resetMass(long id, Energy mass,tPDPtr particle=tPDPtr());
+protected:
+
+ /**
+ * Set the couplings in the model
+ */
+ void setCouplings(string name,pair<unsigned int,int> vals) {
+ couplings_[name] = vals;
+ }
+
private:
/**
* Private and non-existent assignment operator.
*/
StandardModel & operator=(const StandardModel &);
private:
/**
* Pointers to the vertices for Standard Model helicity amplitude
* calculations.
*/
//@{
/**
* Pointer to the fermion-fermion-Z vertex
*/
AbstractFFVVertexPtr FFZVertex_;
/**
* Pointer to the fermion-fermion-photon vertex
*/
AbstractFFVVertexPtr FFPVertex_;
/**
* Pointer to the fermion-fermion-gluon vertex
*/
AbstractFFVVertexPtr FFGVertex_;
/**
* Pointer to the fermion-fermion-W vertex
*/
AbstractFFVVertexPtr FFWVertex_;
/**
* Pointer to the fermion-fermion-Higgs vertex
*/
AbstractFFSVertexPtr FFHVertex_;
/**
* Pointer to the two electroweak gauge boson Higgs vertex.
*/
AbstractVVSVertexPtr WWHVertex_;
/**
* Pointer to the triple gluon vertex
*/
AbstractVVVVertexPtr GGGVertex_;
/**
* Pointer to the triple electroweak gauge boson vertex.
*/
AbstractVVVVertexPtr WWWVertex_;
/**
* Pointer to the quartic gluon vertex
*/
AbstractVVVVVertexPtr GGGGVertex_;
/**
* Pointer to the quartic electroweak gauge boson vertex.
*/
AbstractVVVVVertexPtr WWWWVertex_;
/**
* Pointer to higgs-gluon-gluon vertex
*/
AbstractVVSVertexPtr HGGVertex_;
/**
* Pointer to higgs-gamma-gamma vertex
*/
AbstractVVSVertexPtr HPPVertex_;
/**
* Pointer to triple Higgs vertex
*/
AbstractSSSVertexPtr HHHVertex_;
/**
* Pointer to WWHH vertex
*/
AbstractVVSSVertexPtr WWHHVertex_;
/**
* Full list of vertices as a vector to allow searching
*/
vector<VertexBasePtr> vertexList_;
/**
* Additional vertices to be considered in automatic ME construction
*/
vector<VertexBasePtr> extraVertices_;
//@}
/**
* The running mass.
*/
runPtr runningMass_;
/**
* Pointer to ModelGenerator Class
*/
ModelGeneratorPtr modelGenerator_;
+ /**
+ * Couplings in the model
+ */
+ map<string,pair<unsigned int,int> > couplings_;
};
}
#endif /* HERWIG_StandardModel_H */
diff --git a/Models/Susy/NMSSM/NMSSMFFHVertex.cc b/Models/Susy/NMSSM/NMSSMFFHVertex.cc
--- a/Models/Susy/NMSSM/NMSSMFFHVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMFFHVertex.cc
@@ -1,164 +1,165 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMFFHVertex class.
//
#include "NMSSMFFHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "NMSSM.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
NMSSMFFHVertex::NMSSMFFHVertex() : _mw(0.*MeV), _sinb(0.), _cosb(0.),
_tanb(0.), _idlast(make_pair(0,0)),
_q2last(0.*MeV2),
_masslast(make_pair(0.*MeV,0*MeV)),
_couplast(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void NMSSMFFHVertex::persistentOutput(PersistentOStream & os) const {
os << _mixS << _mixP << ounit(_mw,GeV)
<< _sinb << _cosb << _tanb << _sw << _theSM;
}
void NMSSMFFHVertex::persistentInput(PersistentIStream & is, int) {
is >> _mixS >> _mixP >> iunit(_mw,GeV)
>> _sinb >> _cosb >> _tanb >> _sw >> _theSM;
}
void NMSSMFFHVertex::doinit() {
// the quarks and neutral higgs
int in[5]={25,35,45,36,46};
for(unsigned int iy=0;iy<5;++iy)
for(int ix=1;ix<7;++ix)
addToList( -ix, ix, in[iy] );
// leptons and neutral higgs
for(unsigned int iy=0;iy<5;++iy)
for(int ix=11;ix<17;ix+=2)
addToList( -ix, ix, in[iy] );
// the quarks and the charged higgs
//H-
for(int ix=0;ix<3;++ix)
addToList(2*ix+2, -2*ix-1, -37);
//H+
for(int ix=0;ix<3;++ix)
addToList(-(2*ix+2), 2*ix+1, 37);
// the leptons and the charged higgs
//H-
for(int ix=0;ix<3;++ix)
addToList( 2*ix+12, -2*ix-11, -37 );
//H+
for(int ix=0;ix<3;++ix)
addToList( -(2*ix+12), 2*ix+11, 37 );
// cast to NMSSM model
tcNMSSMPtr model=dynamic_ptr_cast<tcNMSSMPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must have the NMSSM Model in NMSSMFFHVertex::doinit()"
<< Exception::runerror;
_theSM = model;
// sin theta_W
double sw2=_theSM->sin2ThetaW();
_sw = sqrt(sw2);
// get the mixing matrices
_mixS=model->CPevenHiggsMix();
if(!_mixS) throw InitException() << "Mixing matrix for CP-even neutral Higgs"
<< " bosons is not set in NMSSMFFHVertex::doinit()"
<< Exception::runerror;
_mixP=model->CPoddHiggsMix();
if(!_mixP) throw InitException() << "Mixing matrix for CP-odd neutral Higgs"
<< " bosons is not set in NMSSMFFHVertex::doinit()"
<< Exception::runerror;
// Mass of the W boson
_mw=getParticleData(ParticleID::Wplus)->mass();
// sin and cos beta
_tanb = model->tanBeta();
double beta = atan(_tanb);
_sinb=sin(beta);
_cosb=cos(beta);
// base class
FFSVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMFFHVertex,FFSVertex>
describeHerwigNMSSMFFHVertex("Herwig::NMSSMFFHVertex", "HwSusy.so HwNMSSM.so");
void NMSSMFFHVertex::Init() {
static ClassDocumentation<NMSSMFFHVertex> documentation
("The NMSSMFFHVertex class implements the vertex for the couplings"
" of the Higgs bosons of the NMSSM to Standard Model fermions");
}
//calulate the couplings
void NMSSMFFHVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b, tcPDPtr c) {
int ihiggs=c->id();
int id(abs(a->id()));
Complex output(1.);
// neutral Higgs
if(ihiggs==25||ihiggs==35||ihiggs==45||ihiggs==36||ihiggs==46) {
if(_idlast.first!=id||q2!=_q2last) {
_idlast.first=id;
_masslast.first = _theSM->mass(q2,a);
}
output = _masslast.first/_mw;
// CP-even
if(ihiggs==25||ihiggs==35||ihiggs==45) {
int iloc = (ihiggs-25)/10;
output *= (id%2==0) ? (*_mixS)(iloc,1)/_sinb : (*_mixS)(iloc,0)/_cosb;
left(1.); right(1.);
}
// CP-odd
else {
int iloc = (ihiggs-36)/10;
output *= (id%2==0) ? (*_mixP)(iloc,1)/_sinb : (*_mixP)(iloc,0)/_cosb;
left(1.); right(-1.);
output *= Complex(0., 1.);
}
}
// Charged higgs
else if(abs(ihiggs)==37) {
output *= -sqrt(2.);
int id2=abs(b->id());
if(id2<id) {
swap(id,id2);
swap(a,b);
}
if(_idlast.first!=id||_idlast.second!=id2||q2!=_q2last) {
_idlast.first =id ;
_idlast.second=id2;
_masslast.first = _theSM->mass(q2,a);
_masslast.second = _theSM->mass(q2,b);
}
double rgt = _masslast.first *_tanb/_mw;
double lft = _masslast.second/_tanb/_mw;
if(ihiggs>0) swap(lft,rgt);
right(rgt);
left (lft);
}
else {
throw Exception() << "Unknown Higgs boson, PDG code = " << ihiggs
<< "in NMSSMFFHVertex::setCoupling()"
<< Exception::runerror;
}
// prefactor
if(q2!=_q2last) {
_couplast = 0.5*weakCoupling(q2);
_q2last=q2;
}
norm(-_couplast*output);
}
diff --git a/Models/Susy/NMSSM/NMSSMGGHVertex.cc b/Models/Susy/NMSSM/NMSSMGGHVertex.cc
--- a/Models/Susy/NMSSM/NMSSMGGHVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMGGHVertex.cc
@@ -1,208 +1,209 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMGGHVertex class.
//
#include "NMSSMGGHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/Susy/NMSSM/NMSSM.h"
#include "Herwig/Looptools/clooptools.h"
using namespace Herwig;
NMSSMGGHVertex::NMSSMGGHVertex() : _sw(0.), _cw(0.), _mw(0.*MeV),
_mz(0.*MeV),_lambdaVEV(0.*MeV), _lambda(0.), _v1(0.*MeV),
_v2(0.*MeV), _triTp(0.*MeV), _triBt(0.*MeV),
_sb(0.), _cb(0.), _masslast(make_pair(0.*MeV,0.*MeV)),
_q2last(0.*MeV2), _couplast(0.), _coup(0.),
_hlast(0), _recalc(true) {
orderInGem(1);
orderInGs(2);
+ colourStructure(ColourStructure::DELTA);
}
void NMSSMGGHVertex::doinit() {
addToList(21,21,25);
addToList(21,21,35);
addToList(21,21,36);
addToList(21,21,45);
addToList(21,21,46);
_theSM = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
if( !_theSM ) {
throw InitException() << "NMSSMGGHVertex::doinit - The SM pointer is null!"
<< Exception::abortnow;
}
// SM parameters
_sw = sqrt(sin2ThetaW());
_cw = sqrt(1. - sin2ThetaW());
_mw = getParticleData(24)->mass();
_mz = getParticleData(23)->mass();
_top = getParticleData(6);
_bt = getParticleData(5);
//NMSSM parameters
tcNMSSMPtr nmssm = dynamic_ptr_cast<tcNMSSMPtr>(_theSM);
_mixS = nmssm->CPevenHiggsMix();
_mixP = nmssm->CPoddHiggsMix();
_mixQt = nmssm->stopMix();
_mixQb = nmssm->sbottomMix();
double beta = atan(nmssm->tanBeta());
_sb = sin(beta);
_cb = cos(beta);
_v1 = sqrt(2.)*_mw*_cb;
_v2 = sqrt(2.)*_mw*_sb;
_lambda = nmssm->lambda();
_lambdaVEV = nmssm->lambdaVEV();
_triTp = nmssm->topTrilinear();
_triBt = nmssm->bottomTrilinear();
// resize vectors here and use setNParticles method
// to the set the actual number in the loop.
// Also only the top mass hass to be calculated at runtime
masses.resize(6, Energy());
masses[0] = getParticleData(6)->mass();
masses[1] = getParticleData(5)->mass();
masses[2] = getParticleData(1000005)->mass();
masses[3] = getParticleData(2000005)->mass();
masses[4] = getParticleData(1000006)->mass();
masses[5] = getParticleData(2000006)->mass();
type.resize(6, PDT::Spin0);
type[0] = PDT::Spin1Half;
type[1] = PDT::Spin1Half;
couplings.resize(6);
VVSLoopVertex::doinit();
if(loopToolsInitialized()) Looptools::ltexi();
}
void NMSSMGGHVertex::persistentOutput(PersistentOStream & os) const {
os << _theSM << _sw << _cw << ounit(_mw, GeV) << ounit(_mz, GeV)
<< ounit(_lambdaVEV,GeV) << _lambda << ounit(_v1,GeV) << ounit(_v2,GeV)
<< ounit(_triTp,GeV) << ounit(_triBt,GeV)
<< _top << _bt << _mixS << _mixP << _mixQt << _mixQb << _sb << _cb;
}
void NMSSMGGHVertex::persistentInput(PersistentIStream & is, int) {
is >> _theSM >> _sw >> _cw >> iunit(_mw, GeV) >> iunit(_mz, GeV)
>> iunit(_lambdaVEV,GeV) >> _lambda >> iunit(_v1,GeV) >> iunit(_v2,GeV)
>> iunit(_triTp,GeV) >> iunit(_triBt,GeV)
>> _top >> _bt >> _mixS >> _mixP >> _mixQt >> _mixQb >> _sb >> _cb;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMGGHVertex,VVSLoopVertex>
describeHerwigNMSSMGGHVertex("Herwig::NMSSMGGHVertex", "HwSusy.so HwNMSSM.so");
void NMSSMGGHVertex::Init() {
static ClassDocumentation<NMSSMGGHVertex> documentation
("The effective coupling of a higgs to a pair of gluons in the "
"NMSSM.");
}
void NMSSMGGHVertex::setCoupling(Energy2 q2, tcPDPtr p1, tcPDPtr p2,
tcPDPtr p3) {
long hid(p3->id());
if( q2 != _q2last ) {
Looptools::clearcache();
_couplast = sqr(strongCoupling(q2));
_coup = weakCoupling(q2);
_q2last = q2;
_recalc = true;
}
norm(_couplast*_coup);
// scalar higgs bosons
if( hid != _hlast ) {
_hlast = hid;
_recalc = true;
if( hid % 5 == 0 ) {
// location of the higgs
int iloc = (hid - 25)/10;
// 6 particles in the loop
setNParticles(6);
// top and bottom quark masses
Energy mt = _theSM->mass(q2, _top);
Energy mb = _theSM->mass(q2, _bt);
Complex c(0.);
// couplings for the top quark loop
c = -0.25*mt*(*_mixS)(iloc, 1)/_sb/_mw;
couplings[0] = make_pair(c,c);
masses[0] = mt;
// couplings for the bottom quark loop
c = -0.25*mb*(*_mixS)(iloc, 0)/_cb/_mw;
couplings[1] = make_pair(c,c);
masses[1] = mb;
// sbottoms
double f1 = mb/_mw/_cb;
complex<Energy> f2 = 0.5*_mz/_cw*
( - _cb*(*_mixS)(iloc,0) + _sb*(*_mixS)(iloc,1));
complex<Energy> cpl;
for(unsigned int ix=0;ix<2;++ix) {
cpl = -f2*( (1. - 2.*sqr(_sw)/3.)*(*_mixQb)(ix, 0)*(*_mixQb)(ix, 0)
+ 2.*sqr(_sw)*(*_mixQb)(ix, 1)*(*_mixQb)(ix, 1)/3.)
- f1*mb*(*_mixS)(iloc,0)
*((*_mixQb)(ix, 0)*(*_mixQb)(ix, 0) + (*_mixQb)(ix, 1)*(*_mixQb)(ix, 1))
- 0.5*f1*(-_lambdaVEV*(*_mixS)(iloc,1) - _lambda*_v2*(*_mixS)(iloc,2)/_coup
+ _triBt*(*_mixS)(iloc,0))*((*_mixQb)(ix, 1)*(*_mixQb)(ix, 0)
+ (*_mixQb)(ix, 0)*(*_mixQb)(ix, 1));
couplings[2+ix] = make_pair(0.5*cpl*UnitRemoval::InvE,0.5*cpl*UnitRemoval::InvE);
}
// stop
f1 = mt/_mw/_sb;
for(unsigned int ix=0;ix<2;++ix) {
cpl =+f2*( (1. - 4.*sqr(_sw)/3.)*(*_mixQt)(ix, 0)*(*_mixQt)(ix, 0)
+ 4.*sqr(_sw)*(*_mixQt)(ix, 1)*(*_mixQt)(ix, 1)/3.)
- f1*mt*(*_mixS)(iloc,1)
*((*_mixQt)(ix, 0)*(*_mixQt)(ix, 0)
+ (*_mixQt)(ix, 1)*(*_mixQt)(ix, 1))
- 0.5*f1*(-_lambdaVEV*(*_mixS)(iloc,0) - _lambda*_v1*(*_mixS)(iloc,2)/_coup
+ _triTp*(*_mixS)(iloc,1))*((*_mixQt)(ix, 1)*(*_mixQt)(ix, 0)
+ (*_mixQt)(ix, 0)*(*_mixQt)(ix, 1));
couplings[4+ix] = make_pair(0.5*cpl*UnitRemoval::InvE,0.5*cpl*UnitRemoval::InvE);
}
}
// pseudoscalar higgs bosons
else {
// location of the higgs
int iloc = (hid - 36)/10;
// 2 particles in the loop
setNParticles(2);
// top and bottom quark masses
Energy mt = _theSM->mass(q2, _top);
Energy mb = _theSM->mass(q2, _bt);
Complex c(0.);
// top quark couplings
c = Complex(0.,-1.)*0.25*mt*(*_mixP)(iloc, 1)/_sb/_mw;
couplings[0] = make_pair(-c,c);
masses[0] = mt;
// bottom quark couplings
c = Complex(0., -1.)*0.25*mb*(*_mixP)(iloc, 0)/_cb/_mw;
couplings[1] = make_pair(-c,c);
masses[1] = mb;
}
}
if( _recalc ) {
VVSLoopVertex::setCoupling(q2, p1, p2, p3);
_recalc = false;
}
}
diff --git a/Models/Susy/NMSSM/NMSSMGOGOHVertex.cc b/Models/Susy/NMSSM/NMSSMGOGOHVertex.cc
--- a/Models/Susy/NMSSM/NMSSMGOGOHVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMGOGOHVertex.cc
@@ -1,292 +1,293 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMGOGOHVertex class.
//
#include "NMSSMGOGOHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "NMSSM.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
NMSSMGOGOHVertex::NMSSMGOGOHVertex() : _lambda(0.), _kappa(0.), _sinb(0.),
_cosb(0.), _sw(0.), _cw(0.),
_q2last(0.*MeV2), _couplast(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void NMSSMGOGOHVertex::persistentOutput(PersistentOStream & os) const {
os << _mixV << _mixU << _mixN << _mixS << _mixP << _lambda << _kappa << _sinb
<< _cosb << _sw << _cw;
}
void NMSSMGOGOHVertex::persistentInput(PersistentIStream & is, int) {
is >> _mixV >> _mixU >> _mixN >> _mixS >> _mixP >> _lambda >> _kappa >> _sinb
>> _cosb >> _sw >> _cw;
}
void NMSSMGOGOHVertex::doinit() {
int ieven[3]={25,35,45};
int iodd [2]={36,46};
long ichar[2]={1000024,1000037};
long ineut[5]={1000022,1000023,1000025,1000035,1000045};
// CP-even charginos
for(unsigned int ix=0;ix<2;++ix) {
for(unsigned int iy=0;iy<2;++iy) {
for(unsigned int iz=0;iz<3;++iz) {
addToList(-ichar[ix], ichar[iy], ieven[iz]);
}
}
}
// CP-odd charginos
for(unsigned int ix=0;ix<2;++ix) {
for(unsigned int iy=0;iy<2;++iy) {
for(unsigned int iz=0;iz<2;++iz) {
addToList(-ichar[ix], ichar[iy], iodd [iz]);
}
}
}
// CP-even neutralinos
for(unsigned int ix=0;ix<5;++ix) {
for(unsigned int iy=0;iy<5;++iy) {
for(unsigned int iz=0;iz<3;++iz) {
addToList( ineut[ix], ineut[iy], ieven[iz]);
}
}
}
// CP-odd neutralinos
for(unsigned int ix=0;ix<5;++ix) {
for(unsigned int iy=0;iy<5;++iy) {
for(unsigned int iz=0;iz<2;++iz) {
addToList( ineut[ix], ineut[iy], iodd[iz]);
}
}
}
// charged higgs
for(unsigned int ix=0;ix<5;++ix) {
for(unsigned int iy=0;iy<2;++iy) {
addToList(ineut[ix], -ichar[iy], 37);
addToList(ineut[ix], ichar[iy], -37);
}
}
tcNMSSMPtr model=dynamic_ptr_cast<tcNMSSMPtr>(generator()->standardModel());
// SM parameters
// sin theta_W
double sw2=sin2ThetaW();
_cw=sqrt(1.0 - sw2);
_sw=sqrt(sw2);
if(!model)
throw InitException() << "Must have the NMSSM Model in "
<< "NMSSMGOGOHVertex::doinit()"
<< Exception::runerror;
// get the mixing matrices
// higgs
_mixS=model->CPevenHiggsMix();
if(!_mixS)
throw InitException() << "Mixing matrix for CP-even neutral Higgs"
<< " bosons is not set in NMSSMGOGOHVertex::doinit()"
<< Exception::runerror;
_mixP=model->CPoddHiggsMix();
if(!_mixP)
throw InitException() << "Mixing matrix for CP-odd neutral Higgs"
<< " bosons is not set in NMSSMGOGOHVertex::doinit()"
<< Exception::runerror;
// charginos
_mixU = model->charginoUMix();
_mixV = model->charginoVMix();
if(!_mixU || !_mixV)
throw InitException() << "NMSSMGOGOHVertex::doinit - "
<< "A mixing matrix pointer is null. U: "
<< _mixU << " V: " << _mixV
<< Exception::abortnow;
// neutralinos
_mixN = model->neutralinoMix();
if(!_mixN)
throw InitException() << "NMSSMGOGOHVertex::doinit - The neutralino "
<< "mixing matrix pointer is null."
<< Exception::abortnow;
// kappa and lambda couplings
_lambda = model->lambda();
_kappa = model->kappa();
// sin and cos beta
double beta = atan(model->tanBeta());
_sinb=sin(beta);
_cosb=cos(beta);
FFSVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMGOGOHVertex,FFSVertex>
describeHerwigNMSSMGOGOHVertex("Herwig::NMSSMGOGOHVertex", "HwSusy.so HwNMSSM.so");
void NMSSMGOGOHVertex::Init() {
static ClassDocumentation<NMSSMGOGOHVertex> documentation
("The NMSSMGOGOHVertex class implements the couplings of the Higgs bosons"
" of the NMSSM and the electroweak gauginos");
}
void NMSSMGOGOHVertex::setCoupling(Energy2 q2,tcPDPtr part1,tcPDPtr part2,
tcPDPtr part3) {
long id1(part1->id()), id2(part2->id()),
id3(part3->id()), ihigg(0), ig1(0), ig2(0);
if( abs(id1) == 25 || abs(id1) == 35 || abs(id1) == 45 ||
abs(id1) == 36 || abs(id1) == 46 || abs(id1) == 37 ) {
ihigg = id1;
ig1 = id2;
ig2 = id3;
}
else if( abs(id2) == 25 || abs(id2) == 35 ||
abs(id2) == 45 ||abs(id2) == 36 ||abs(id2) == 46 || abs(id2) == 37 ) {
ihigg = id2;
ig1 = id1;
ig2 = id3;
}
else if( abs(id3) ==25 || abs(id3) == 35 ||
abs(id3) == 45 ||abs(id3) == 36 ||abs(id3) == 46 || abs(id3) == 37 ) {
ihigg = id3;
ig1 = id1;
ig2 = id2;
}
else {
throw HelicityConsistencyError()
<< "NMSSMGOGOHVertex::setCoupling - There is no higgs particle in "
<< "this vertex. Particles: " << id1 << " " << id2 << " " << id3
<< Exception::runerror;
return;
}
// weak coupling
if(q2!=_q2last) {
_couplast = weakCoupling(q2);
_q2last = q2;
}
double rt = sqrt(0.5);
// CP-even neutral higgs
if(ihigg == 25 || ihigg == 35 || ihigg == 45) {
int iloc = (ihigg - 25)/10;
// chargino
if(abs(ig1) == 1000024 || abs(ig1) == 1000037) {
if( ig1 < 0 ) swap(ig1, ig2);
int ic1 = abs(ig1)==1000024 ? 0 : 1;
int ic2 = abs(ig2)==1000024 ? 0 : 1;
Complex coupL = -_lambda*rt*conj((*_mixS)(iloc,2)*(*_mixU)(ic1,1)*(*_mixV)(ic2,1))
-_couplast*rt*(conj((*_mixS)(iloc,0)*(*_mixU)(ic1,1)*(*_mixV)(ic2,0) +
(*_mixS)(iloc,1)*(*_mixU)(ic1,0)*(*_mixV)(ic2,1)));
Complex coupR = -_lambda*rt*(*_mixS)(iloc,2)*(*_mixU)(ic2,1)*(*_mixV)(ic1,1)
-_couplast*rt*((*_mixS)(iloc,0)*(*_mixU)(ic2,1)*(*_mixV)(ic1,0)+
(*_mixS)(iloc,1)*(*_mixU)(ic2,0)*(*_mixV)(ic1,1));
left(coupL);
right(coupR);
norm(1.0);
}
// neutralino
else {
int in1 = (ig1 < 1000024) ? (ig1 - 1000022) : (ig1 - 1000005)/10;
int in2 = (ig2 < 1000024) ? (ig2 - 1000022) : (ig2 - 1000005)/10;
Complex us1 = (*_mixS)(iloc, 0), us2 = (*_mixS)(iloc, 1);
Complex us3 = (*_mixS)(iloc, 2);
Complex ni1 = (*_mixN)(in1,0), nj1 = (*_mixN)(in2,0);
Complex ni2 = (*_mixN)(in1,1), nj2 = (*_mixN)(in2,1);
Complex ni3 = (*_mixN)(in1,3), nj3 = (*_mixN)(in2,3);
Complex ni4 = (*_mixN)(in1,2), nj4 = (*_mixN)(in2,2);
Complex ni5 = (*_mixN)(in1,4), nj5 = (*_mixN)(in2,4);
Complex YL =
- _lambda*rt*(us2*(ni4*nj5 + ni5*nj4) +
us1*(ni3*nj5 + ni5*nj3) +
us3*(ni3*nj4 + ni4*nj3))
+ sqrt(2.)*_kappa*us3*ni5*nj5
- _couplast*0.5*(us2*(ni2*nj3 + ni3*nj2) -
us1*(ni2*nj4 + ni4*nj2))
+ _couplast*0.5*_sw*(us2*(ni1*nj3 + ni3*nj1) -
us1*(ni1*nj4 + ni4*nj1) )/_cw;
left(-conj(YL));
right(-YL);
norm(1.0);
}
}
// CP-odd neutral higgs
else if(ihigg==36||ihigg==46) {
int iloc = (ihigg-36)/10;
// chargino
if(abs(ig1)==1000024||abs(ig1)==1000037) {
if( ig1 < 0 ) swap(ig1, ig2);
int ic1 = abs(ig1)==1000024 ? 0 : 1;
int ic2 = abs(ig2)==1000024 ? 0 : 1;
Complex QL = Complex(0,-1.0)*
(_lambda*rt*conj((*_mixP)(iloc,2)*(*_mixU)(ic1,1)*(*_mixV)(ic2,1))
-_couplast*rt*conj(((*_mixP)(iloc,0)*(*_mixU)(ic1,1)*(*_mixV)(ic2,0) +
(*_mixP)(iloc,1)*(*_mixU)(ic1,0)*(*_mixV)(ic2,1))));
Complex QR = Complex(0,-1.0)*
(_lambda*rt*(*_mixP)(iloc,2)*(*_mixU)(ic2,1)*(*_mixV)(ic1,1)
-_couplast*rt*((*_mixP)(iloc,0)*(*_mixU)(ic2,1)*(*_mixV)(ic1,0) +
(*_mixP)(iloc,1)*(*_mixU)(ic2,0)*(*_mixV)(ic1,1)));
left(QL);
right(-QR);
norm(1.);
}
// neutralino
else {
int in1 = (ig1 < 1000024) ? (ig1 - 1000022) : (ig1 - 1000005)/10;
int in2 = (ig2 < 1000024) ? (ig2 - 1000022) : (ig2 - 1000005)/10;
Complex up1 = (*_mixP)(iloc, 0), up2 = (*_mixP)(iloc, 1);
Complex up3 = (*_mixP)(iloc, 2);
Complex ni1 = (*_mixN)(in1,0), nj1 = (*_mixN)(in2,0);
Complex ni2 = (*_mixN)(in1,1), nj2 = (*_mixN)(in2,1);
Complex ni3 = (*_mixN)(in1,2), nj3 = (*_mixN)(in2,2);
Complex ni4 = (*_mixN)(in1,3), nj4 = (*_mixN)(in2,3);
Complex ni5 = (*_mixN)(in1,4), nj5 = (*_mixN)(in2,4);
Complex AL =
_lambda*rt*(up2*(ni3*nj5 + ni5*nj3) +
up1*(ni4*nj5 + ni5*nj4) +
up3*(ni3*nj4 + ni4*nj3))
- sqrt(2.)*_kappa*up3*ni5*nj5
- _couplast*0.5*(up2*(ni2*nj4 + ni4*nj2) -
up1*(ni2*nj3 + ni3*nj2))
+ _couplast*0.5*_sw*(up2*(ni1*nj4 + ni4*nj1) -
up1*(ni1*nj3 + ni3*nj1))/_cw;
AL *= Complex(0.0, -1.0);
left(conj(AL));
right(AL);
norm(1.);
}
}
// charged higgs
else {
if (abs(ig1) == 1000024 || abs(ig1) == 1000037) swap (ig1,ig2);
int in = (abs(ig1) < 1000024) ? (ig1-1000022) : (ig1-1000005)/10;
int ic = (abs(ig2) == 1000024) ? 0 : 1;
Complex QpR = _lambda*_cosb*(*_mixU)(ic,1)*(*_mixN)(in,4)
-_sinb*_couplast*(rt*(*_mixU)(ic,1)*(_sw*(*_mixN)(in,0)/_cw + (*_mixN)(in,1))
- (*_mixU)(ic,0)*(*_mixN)(in,2));
Complex QpL = _lambda*_sinb*(*_mixV)(ic,1)*(*_mixN)(in,4)
+ _couplast*_cosb*(rt*(*_mixV)(ic,1)
*(_sw*(*_mixN)(in,0)/_cw + (*_mixN)(in,1))
+ (*_mixV)(ic,0)*(*_mixN)(in,3));
QpL = conj(QpL);
if(ihigg > 0) {
left (QpL);
right(QpR);
norm(-1.);
}
else {
left (conj(QpR));
right(conj(QpL));
norm(-1.);
}
}
}
diff --git a/Models/Susy/NMSSM/NMSSMHHHVertex.cc b/Models/Susy/NMSSM/NMSSMHHHVertex.cc
--- a/Models/Susy/NMSSM/NMSSMHHHVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMHHHVertex.cc
@@ -1,277 +1,278 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMHHHVertex class.
//
#include "NMSSMHHHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "NMSSM.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
NMSSMHHHVertex::NMSSMHHHVertex() : _mw(0.*MeV), _mz(0.*MeV), _sw2(0.),
_cw(0.), _lambda(0.), _kappa(0.) ,
_lambdaVEV(0.*MeV), _theAl(0.*MeV),
_theAk(0.*MeV), _sb(0.), _cb(0.),
_s2b(0.), _c2b(0.), _vu(0.*MeV),
_vd(0.*MeV), _s(0.*MeV), _q2last(0.*MeV2),
_glast(0.), _MQ3(0.*MeV), _MU2(0.*MeV),
_includeRadiative(false) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void NMSSMHHHVertex::doinit() {
// PDG codes for the particles in vertex _vd
//CP-even Higgs
addToList(25, 35, 45);
for( unsigned int i = 25; i <= 45; i += 10 ) {
addToList(i, i, 25);
addToList(i, i, 35);
addToList(i, i, 45);
//Charged Higgs
addToList(i, 37, -37);
//CP-odd Higgs
addToList(i, 36, 36);
addToList(i, 36, 46);
addToList(i, 46, 36);
addToList(i, 46, 46);
}
_theSM = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
tcNMSSMPtr nmssm = dynamic_ptr_cast<tcNMSSMPtr>(_theSM);
if( !nmssm )
throw InitException() << "NMSSMHHHVertex::doinit - The model object is"
<< "not the NMSSM object."
<< Exception::runerror;
//SM parameters
_mw = getParticleData(24)->mass();
_mz = getParticleData(23)->mass();
_sw2 = sin2ThetaW();
_cw = sqrt(1. - _sw2);
//NMSSM parameters
_mixS = nmssm->CPevenHiggsMix();
_mixP = nmssm->CPoddHiggsMix();
if( !_mixS || !_mixP )
throw InitException() << "NMSSMHHHVertex::doinit - One of the mixing matrix "
<< "pointers is null, cannot continue. S: "
<< _mixS << " P: " << _mixP << Exception::runerror;
_lambda = nmssm->lambda();
_kappa = nmssm->kappa();
_lambdaVEV = nmssm->lambdaVEV();
_theAl = nmssm->trilinearLambda();
_theAk = nmssm->trilinearKappa();
_MQ3 = nmssm->MQ3();
_MU2 = nmssm->MU2();
double beta = atan(nmssm->tanBeta());
_sb = sin(beta);
_cb = cos(beta);
_vd = sqrt(2)*_mw*_cb;
_vu = sqrt(2)*_mw*_sb;
_s = _lambdaVEV/_lambda;
SSSVertex::doinit();
}
void NMSSMHHHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(_mw, GeV) << ounit(_mz,GeV)
<< _sw2 << _cw << _lambda << _includeRadiative
<< _kappa << ounit(_lambdaVEV,GeV) << ounit(_theAl, GeV)
<< ounit(_theAk,GeV) << _sb << _cb << _s2b << _c2b
<< ounit(_vu,GeV) << ounit(_vd,GeV) << ounit(_s,GeV) << _mixS << _mixP
<< ounit(_MQ3,GeV) << ounit(_MU2,GeV) << _theSM;
}
void NMSSMHHHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(_mw, GeV) >> iunit(_mz,GeV)
>> _sw2 >> _cw >> _lambda >> _includeRadiative
>> _kappa >> iunit(_lambdaVEV,GeV) >> iunit(_theAl, GeV)
>> iunit(_theAk,GeV) >> _sb >> _cb >> _s2b >> _c2b
>> iunit(_vu,GeV) >> iunit(_vd,GeV) >> iunit(_s,GeV)>> _mixS >> _mixP
>> iunit(_MQ3,GeV) >> iunit(_MU2,GeV) >> _theSM;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMHHHVertex,SSSVertex>
describeHerwigNMSSMHHHVertex("Herwig::NMSSMHHHVertex", "HwSusy.so HwNMSSM.so");
void NMSSMHHHVertex::Init() {
static ClassDocumentation<NMSSMHHHVertex> documentation
("This is the triple Higgs coupling in the NMSSM.");
static Switch<NMSSMHHHVertex,bool> interfaceIncludeRadiativeCorrections
("IncludeRadiativeCorrections",
"Include radiative corrections in the vertex",
&NMSSMHHHVertex::_includeRadiative, false, false, false);
static SwitchOption interfaceIncludeRadiativeCorrectionsYes
(interfaceIncludeRadiativeCorrections,
"Yes",
"Include the radiative terms",
true);
static SwitchOption interfaceIncludeRadiativeCorrectionsNo
(interfaceIncludeRadiativeCorrections,
"No",
"Don't include them",
false);
}
//calulate couplings
void NMSSMHHHVertex::setCoupling(Energy2 q2,tcPDPtr p1,tcPDPtr p2,
tcPDPtr p3) {
using Constants::pi;
long higgs[3] = {p1->id(), p2->id(), p3->id()};
unsigned int ns(0), np(0), nc(0);
for( int i = 0; i < 3; ++i ) {
if( higgs[i] == 25 || higgs[i] == 35 || higgs[i] == 45 )
++ns;
else if( higgs[i] == 36 || higgs[i] == 46 )
++np;
else if( abs(higgs[i]) == 37 )
++nc;
}
//check three Higgs in vertex
assert( ns + np + nc == 3 );
if( q2 != _q2last ) {
_q2last = q2;
_glast = weakCoupling(q2);
_mb = _theSM->mass(q2,getParticleData(5));
_mt = _theSM->mass(q2,getParticleData(6));
}
//define VEV's
double rt = sqrt(0.5);
Energy _mtpole = getParticleData(6)->mass();
Energy2 Qstsb = _MQ3*_MU2;
double radlog(0.);
if(_includeRadiative) {
radlog = Qstsb/sqr(_mtpole);
assert(radlog!=0.);
radlog = log(radlog);
}
complex<Energy> coupling;
//CP even Higgs
if( ns == 3 ) {
unsigned int a = (higgs[0] - 25)/10;
unsigned int b = (higgs[1] - 25)/10;
unsigned int c = (higgs[2] - 25)/10;
coupling =
sqr(_lambda)*rt*(_vu*(usMix(a,b,c,1,0,0) + usMix(a,b,c,1,2,2))/_glast +
_vd*(usMix(a,b,c,0,1,1) + usMix(a,b,c,0,2,2))/_glast +
_s *(usMix(a,b,c,2,1,1) + usMix(a,b,c,2,0,0)))
- _lambda*_kappa*rt*(_vu*usMix(a,b,c,0,2,2)/_glast +
_vd*usMix(a,b,c,2,1,2)/_glast + 2.*_s*usMix(a,b,c,1,0,2))
+ sqr(_kappa)/rt*_s*usMix(a,b,c,2,2,2)
- _lambda*_theAl*rt*usMix(a,b,c,1,0,2)
+ _kappa*_theAk*rt/3.*usMix(a,b,c,2,2,2)
+ sqr(_glast)*0.25*rt/sqr(_cw)*(_vu*(usMix(a,b,c,1,1,1) -
usMix(a,b,c,1,0,0))/_glast -
_vd*(usMix(a,b,c,0,1,1) -
usMix(a,b,c,0,0,0))/_glast);
// additional radiative terms
if(_includeRadiative) {
complex <Energy> radtop = usMix(a,b,c,1,1,1)*3.0*sqrt(2.0)*radlog
*sqr(_mt)*sqr(_mt)*sqr(_glast)*_glast/
(16.0*sqr(pi)*_vu*_vu*_vu);
complex <Energy> radbot= usMix(a,b,c,0,0,0)*3.0*sqrt(2.0)*radlog
*sqr(_mb)*sqr(_mb)*sqr(_glast)*_glast
/(16.0*sqr(pi)*_vd*_vd*_vd);
coupling += radbot + radtop;
}
}
//CP even, CP odd Vertex
else if(ns == 1 && np == 2) {
unsigned int a(0), b(0), c(0);
if( higgs[0] == 25 || higgs[0] == 35 || higgs[0] == 45 ) {
a = (higgs[0] - 25)/10;
b = (higgs[1] - 36)/10;
c = (higgs[2] - 36)/10;
}
else if(higgs[1] == 25 || higgs[1] == 35 || higgs[1] == 45 ) {
a = (higgs[1] - 25)/10;
b = (higgs[0] - 36)/10;
c = (higgs[2] - 36)/10;
}
else {
a = (higgs[2] - 25)/10;
b = (higgs[0] - 36)/10;
c = (higgs[1] - 36)/10;
}
coupling =
sqr(_lambda)*rt*(_vu*(upMix(a,b,c,1,0,0) + upMix(a,b,c,1,2,2))/_glast +
_vd*(upMix(a,b,c,0,1,1) + upMix(a,b,c,0,2,2))/_glast +
_s *(upMix(a,b,c,2,1,1) + upMix(a,b,c,2,0,0)))
+ _lambda*_kappa*rt*(_vu*(upMix(a,b,c,0,2,2)
- 2.*upMix(a,b,c,2,0,2))/_glast +
_vd*(upMix(a,b,c,1,2,2)
- 2.*upMix(a,b,c,2,1,2))/_glast
+ 2.*_s*(upMix(a,b,c,2,1,0)
- upMix(a,b,c,1,0,2) - upMix(a,b,c,0,1,2)))
+ sqr(_kappa)/rt*_s*upMix(a,b,c,2,2,2)
+_lambda*_theAl*rt*(upMix(a,b,c,1,0,2)
+ upMix(a,b,c,0,1,2) + upMix(a,b,c,2,1,0))
- _kappa*_theAk*rt*upMix(a,b,c,2,2,2)
+ sqr(_glast)*0.25*rt/sqr(_cw)*(_vu*(upMix(a,b,c,1,1,1) -
upMix(a,b,c,1,0,0))/_glast -
_vd*(upMix(a,b,c,0,1,1) -
upMix(a,b,c,0,0,0))/_glast);
if(_includeRadiative) {
complex <Energy> radtop = upMix(a,b,c,1,1,1)*3.0*sqrt(2.0)*radlog*
sqr(_mt)*sqr(_mt)*sqr(_glast)*_glast/
(16.0*sqr(pi)*_vu*_vu*_vu);
complex <Energy> radbot= upMix(a,b,c,0,0,0)*3.0*sqrt(2.0)*radlog*
sqr(_mb)*sqr(_mb)*sqr(_glast)*_glast
/(16.0*sqr(pi)*_vd*_vd*_vd);
coupling += radbot + radtop;
}
}
//Charged Higgs
else {
unsigned int a(0);
if( higgs[0] == 25 || higgs[0] == 35 || higgs[0] == 45 )
a = (higgs[0] - 25)/10;
else if(higgs[1] == 25 || higgs[1] == 35 || higgs[1] == 45 )
a = (higgs[1] - 25)/10;
else
a = (higgs[2] - 25)/10;
coupling =
sqr(_lambda)*rt*2.*(_s*((*_mixS)(a,2)*sqr(_cb) + (*_mixS)(a,2)*sqr(_sb))
- (_vu*(*_mixS)(a,0)/_glast +
_vd*(*_mixS)(a,1)/_glast)*_sb*_cb)
+_lambda*_sb*_cb*2.*(*_mixS)(a,2)*(_kappa*_s/rt + rt*_theAl)
+ sqr(_glast)*0.5*rt*_sw2/sqr(_cw)*((_vu*(*_mixS)(a,1)/_glast -
_vd*(*_mixS)(a,0)/_glast)*sqr(_cb) +
(_vd*(*_mixS)(a,0)/_glast -
_vu*(*_mixS)(a,1)/_glast)*sqr(_sb))
+ sqr(_glast)*0.5*rt*(_vu*((*_mixS)(a,1)*sqr(_cb) +
(*_mixS)(a,1)*sqr(_sb) +
2.*(*_mixS)(a,0)*_cb*_sb)/_glast
+ _vd*((*_mixS)(a,0)*sqr(_cb) +
(*_mixS)(a,0)*sqr(_sb)
+ 2.*(*_mixS)(a,1)*_sb*_cb)/_glast);
if(_includeRadiative) {
complex <Energy> radtop =(*_mixS)(a,1)*sqr(_sb)*6.0*sqrt(2.0)*radlog*
sqr(_mt)*sqr(_mt)*sqr(_glast)*_glast/
(16.0*sqr(pi)*_vu*_vu*_vu);
complex <Energy> radbot=(*_mixS)(a,0)*sqr(_cb)*6.0*sqrt(2.0)*radlog*
sqr(_mb)*sqr(_mb)*sqr(_glast)*_glast
/(16.0*sqr(pi)*_vd*_vd*_vd);
complex <Energy> temp2 = _vu*((*_mixS)(a,1)*sqr(_cb) +
(*_mixS)(a,0)*_sb*_cb)/_glast+
_vd*((*_mixS)(a,1)*_sb*_cb +
(*_mixS)(a,0)*sqr(_sb))/_glast;
complex <Energy> radtopbot= temp2*6.0*sqrt(2.0)*radlog*
sqr(_mt)*sqr(_mb)*sqr(_glast)*sqr(_glast)
/(16.0*sqr(pi)*sqr(_vu)*sqr(_vd));
coupling += radbot + radtop + radtopbot;
}
}
norm(-coupling * UnitRemoval::InvE);
}
diff --git a/Models/Susy/NMSSM/NMSSMHSFSFVertex.cc b/Models/Susy/NMSSM/NMSSMHSFSFVertex.cc
--- a/Models/Susy/NMSSM/NMSSMHSFSFVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMHSFSFVertex.cc
@@ -1,388 +1,389 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMHSFSFVertex class.
//
#include "NMSSMHSFSFVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "NMSSM.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
NMSSMHSFSFVertex::NMSSMHSFSFVertex() :
_triTp(0.*MeV), _triBt(0.*MeV), _triTa(0.*MeV), _lambda(0.),
_lambdaVEV(0.*MeV), _v1(0.*MeV), _v2(0.*MeV), _sw(0.), _cw(0.),
_mw(0.*MeV), _mz(0.*MeV), _sb(0.), _cb(0.), _tb(0.), _q2last(0.*MeV2),
_couplast(0.), _masslast(make_pair(0.*MeV,0.*MeV)), _idlast(make_pair(0,0)) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void NMSSMHSFSFVertex::persistentOutput(PersistentOStream & os) const {
os << _theSM << _mixS << _mixP << _mixTp << _mixBt << _mixTa
<< ounit(_triTp,GeV) << ounit(_triBt,GeV) << ounit(_triTa,GeV)
<< _lambda << ounit(_lambdaVEV,GeV) << ounit(_v1,GeV) << ounit(_v2,GeV)
<< _sw << _cw << ounit(_mw,GeV) << ounit(_mz,GeV) << _sb << _cb
<< _tb;
}
void NMSSMHSFSFVertex::persistentInput(PersistentIStream & is, int) {
is >> _theSM >> _mixS >> _mixP >> _mixTp >> _mixBt >> _mixTa
>> iunit(_triTp,GeV) >> iunit(_triBt,GeV) >> iunit(_triTa,GeV)
>> _lambda >> iunit(_lambdaVEV,GeV) >> iunit(_v1,GeV) >> iunit(_v2,GeV)
>> _sw >> _cw >> iunit(_mw,GeV) >> iunit(_mz,GeV) >> _sb >> _cb >> _tb;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMHSFSFVertex,Helicity::SSSVertex>
describeHerwigNMSSMHSFSFVertex("Herwig::NMSSMHSFSFVertex", "HwSusy.so HwNMSSM.so");
void NMSSMHSFSFVertex::Init() {
static ClassDocumentation<NMSSMHSFSFVertex> documentation
("The coupling of Higgs bosons to sfermions in the MSSM.");
}
void NMSSMHSFSFVertex::doinit() {
//CP even
int even[3] = {25, 35, 45};
for(size_t h = 0; h < 3; ++h ) {
//squarks
for(long q = 1; q < 7; ++q) {
//11
addToList(even[h], -1000000 - q, 1000000 + q);
//22
addToList(even[h], -2000000 - q, 2000000 + q);
//12
addToList(even[h], -1000000 - q, 2000000 + q);
//21
addToList(even[h], -2000000 - q, 1000000 + q);
}
//sleptons
for(long l = 11; l < 17; ++l) {
//11
addToList(even[h], -1000000 - l, 1000000 + l);
//no right handed sneutrinos
if( l % 2 != 0 ) {
//22
addToList(even[h], -2000000 - l, 2000000 + l);
//12
addToList(even[h], -1000000 - l, 2000000 + l);
//21
addToList(even[h], -2000000 - l, 1000000 + l);
}
}
}
//CP odd
int odd[2] = {36, 46};
for(size_t h = 0; h < 2; ++h ) {
//squarks
for(long q = 1; q < 7; ++q) {
//12
addToList(odd[h], -1000000 - q, 2000000 + q);
//21
addToList(odd[h], -2000000 - q, 1000000 + q);
}
//sleptons
for(long l = 11; l < 16; l += 2) {
//12
addToList(odd[h], -1000000 - l, 2000000 + l);
//21
addToList(odd[h], -2000000 - l, 1000000 + l);
}
}
//charged higgs
//squarks
for(long q = 1; q < 4; ++q ) {
//H-
//LL
addToList(-37, -2*q - 999999, 2*q + 1000000);
//RR
addToList(-37, -2*q - 1999999, 2*q + 2000000);
//LR
addToList(-37, -2*q - 999999, 2*q + 2000000);
//RL
addToList(-37, -2*q - 1999999, 2*q + 1000000);
//H+
//LL
addToList(37, -2*q - 1000000, 2*q + 999999);
//RR
addToList(37, -2*q - 2000000, 2*q + 1999999);
//LR
addToList(37, -2*q - 1000000, 2*q + 1999999);
//RL
addToList(37, -2*q - 2000000, 2*q + 999999);
}
//sleptons
//easier as there are no right handed sneutrinos
for(long l = 11; l <= 15; l +=2 ) {
//H-
//LL
addToList(-37, -l - 1000000, l + 1000001);
//RL
addToList(-37, -l - 2000000, l + 1000001);
//H+
//LL
addToList(+37, -l - 1000001, l + 1000000);
//RL
addToList(+37, -l - 1000001, l + 2000000);
}
_theSM = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
tcNMSSMPtr nmssm = dynamic_ptr_cast<tcNMSSMPtr>(_theSM);
if( !nmssm )
throw InitException() << "NMSSMHSFSFVertex::doinit() - The model pointer "
<< "in this vertex is not an NMSSM one as it "
<< "should be." << Exception::runerror;
_mixS = nmssm->CPevenHiggsMix();
_mixP = nmssm->CPoddHiggsMix();
_mixTp = nmssm->stopMix();
_mixBt = nmssm->sbottomMix();
_mixTa = nmssm->stauMix();
if( !_mixS || !_mixP || !_mixTp || !_mixBt || !_mixTa )
throw InitException()
<< "NMSSMHSFSFVertex::doinit() - One of the mixing matrix pointers is "
<< "null, cannot continue. CP-even: " << _mixS << " CP-odd: " << _mixP
<< " ~t: " << _mixTp << " ~b: " << _mixBt << " ~tau: " << _mixTa
<< Exception::runerror;
_triTp = nmssm->topTrilinear();
_triBt = nmssm->bottomTrilinear();
_triTa = nmssm->tauTrilinear();
_lambda = nmssm->lambda();
_lambdaVEV = nmssm->lambdaVEV();
_sw = sin2ThetaW();
_cw = sqrt( 1. - _sw);
_sw = sqrt(_sw);
_mw = getParticleData(24)->mass();
_mz = getParticleData(23)->mass();
_tb = nmssm->tanBeta();
double beta = atan(_tb);
_sb = sin(beta);
_cb = cos(beta);
_v1 = sqrt(2.)*_mw*_cb;
_v2 = sqrt(2.)*_mw*_sb;
SSSVertex::doinit();
}
void NMSSMHSFSFVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3) {
// extract particle ids
long higgs(part1->id()), isf1(part2->id()), isf2(part3->id());
// higgs first
if(abs(isf1)<100) swap(higgs,isf1);
if(abs(isf2)<100) swap(higgs,isf2);
// squark second
if(isf1<0) swap(isf1,isf2);
// check higgs
assert( higgs == 25 || higgs == 35 || higgs == 45 ||
higgs == 36 || higgs == 46 || abs(higgs) == 37 );
// abs of antisquark and check
isf2 *=-1;
assert(isf1>0&&isf2>0);
// running coupling
if( q2 != _q2last ) {
_q2last = q2;
_couplast = weakCoupling(q2);
}
//charged higgs
if( abs(higgs) == 37 ) {
norm(_couplast*chargedHiggs(q2, isf1, isf2));
return;
}
// neutral higgs
// L/R states of the sfermions
unsigned int alpha = ( isf1 > 2000000 ) ? 1 : 0;
unsigned int beta = ( isf2 > 2000000 ) ? 1 : 0;
// id nad mass of corresponding SM fermion
long smid = ( alpha == 0 ) ? isf1 - 1000000 : isf1 - 2000000;
if( q2 != _q2last || smid != _idlast.first) {
_idlast.first = smid;
_masslast.first = _theSM->mass(q2, getParticleData(smid));
}
double f1 = _masslast.first/_mw;
complex<Energy> af(ZERO);
Complex m1a(0.), m1b(0.), m2a(0.), m2b(0.);
// mixing for down type squarks and charged sleptons
if( smid % 2 != 0 ) {
f1 /= _cb;
// sbottom
if( smid == 5 ) {
m1a = (*_mixBt)(alpha, 0);
m1b = (*_mixBt)(alpha, 1);
m2a = (*_mixBt)(beta , 0) ;
m2b = (*_mixBt)(beta , 1);
af = _triBt;
}
// stau
else if( smid == 15 ) {
m1a = (*_mixTa)(alpha, 0);
m1b = (*_mixTa)(alpha, 1);
m2a = (*_mixTa)(beta , 0) ;
m2b = (*_mixTa)(beta , 1);
af = _triTa;
}
// 1st 2 generations
else {
m1a = (alpha == 0) ? 1. : 0.;
m1b = (alpha == 0) ? 0. : 1.;
m2a = (beta == 0) ? 1. : 0.;
m2b = (beta == 0) ? 0. : 1.;
af = ZERO;
}
}
// mixing for up type squarks and sneutrions
else {
f1 /= _sb;
// stop
if( smid == 6 ) {
m1a = (*_mixTp)(alpha, 0);
m1b = (*_mixTp)(alpha, 1);
m2a = (*_mixTp)(beta , 0);
m2b = (*_mixTp)(beta , 1);
af = _triTp;
}
// everything else
else {
m1a = (alpha == 0) ? 1. : 0.;
m1b = (alpha == 0) ? 0. : 1.;
m2a = (beta == 0) ? 1. : 0.;
m2b = (beta == 0) ? 0. : 1.;
af = 0.*MeV;
}
}
// scalar higgs bosons
complex<Energy> fact(ZERO);
if( higgs == 25 || higgs == 35 || higgs == 45 ) {
int iloc = (higgs - 25)/10;
complex<Energy> f2 = 0.5*_mz*( - _cb*(*_mixS)(iloc,0)
+ _sb*(*_mixS)(iloc,1))/_cw;
// down type squarks and charged sleptons
if( smid % 2 != 0 ) {
double ef = (smid < 7) ? -1./3. : -1.;
fact = - f2*( (1. + 2.*ef*sqr(_sw))*m1a*m2a - 2.*ef*sqr(_sw)*m1b*m2b)
- f1*_masslast.first*(*_mixS)(iloc,0)*(m1a*m2a + m1b*m2b)
- 0.5*f1*(( - _lambdaVEV*(*_mixS)(iloc,1)
- _lambda*_v2*(*_mixS)(iloc,2)/_couplast
+ af*(*_mixS)(iloc,0)) *
(m2a*m1b + m1a*m2b) );
}
// up type squarks and sneutrinos
else {
double ef = (smid < 7) ? 2./3. : 0.;
fact = +f2*( (1. - 2.*ef*sqr(_sw))*m1a*m2a + 2.*ef*sqr(_sw)*m1b*m2b )
- f1*_masslast.first*(*_mixS)(iloc,1)*(m1a*m2a + m1b*m2b)
- 0.5*f1*(( - _lambdaVEV*(*_mixS)(iloc,0)
- _lambda*_v1*(*_mixS)(iloc,2)/_couplast
+ af*(*_mixS)(iloc,1) ) *
(m2a*m1b + m1a*m2b));
}
}
// pseudo scalar
else if( higgs == 36 || higgs == 46 ) {
int iloc = (higgs - 36)/10;
// down type squarks and charged sleptons
if( smid % 2 != 0 ) {
fact = -0.5*f1*Complex(0.0,1.0)*
( _lambdaVEV*(*_mixP)(iloc,1) +
_lambda*_v2*(*_mixP)(iloc,2)/_couplast +
af*(*_mixP)(iloc,0) );
}
// up-type squarks and sneutrinos
else {
fact =-0.5*f1*Complex(0.0,1.0)*
( _lambdaVEV *(*_mixP)(iloc,0) +
_lambda*_v1*(*_mixP)(iloc,2)/_couplast +
af*(*_mixP)(iloc,1));
}
if(alpha<beta) fact *= -1.;
}
norm(_couplast*fact*UnitRemoval::InvE);
}
Complex NMSSMHSFSFVertex::chargedHiggs(Energy2 q2, long id1, long id2) {
//have id1 as up-type
if( id1 % 2 != 0) swap(id1, id2);
// sfermion L/R states
unsigned int alpha = ( id1/1000000 == 2 ) ? 1 : 0;
unsigned int beta = ( id2/1000000 == 2 ) ? 1 : 0;
// type of quarks
long utype = (alpha == 0) ? id1 - 1000000 : id1 - 2000000;
long dtype = ( beta == 0) ? id2 - 1000000 : id2 - 2000000;
// compute the running masses
if( q2 != _q2last || id1 != _idlast.first || id2 != _idlast.second) {
_idlast.first = id1;
_idlast.second = id2;
_masslast.first = _theSM->mass(q2, getParticleData(utype) );
_masslast.second = _theSM->mass(q2, getParticleData(dtype) );
}
Energy2 facta = 2.*sqr(_mw)*_sb*_cb;
complex<Energy2> coupling(ZERO);
// sleptons
if( dtype == 11 || dtype == 13 || dtype == 15) {
Complex l1b = 0., l2b = 0.;
complex<Energy> tri(ZERO);
// 1st 2 generations
if (dtype == 11 || dtype == 13) {
l1b = (beta == 0) ? 1.0 : 0.0;
l2b = (beta == 0) ? 0.0 : 1.0;
}
// stau
else {
l1b = (*_mixTa)(beta, 0) ;
l2b = (*_mixTa)(beta, 1);
tri = _triTa;
}
coupling = ( l1b*(sqr(_masslast.second)*_tb - facta) +
l2b*_masslast.second*(tri*_tb + _lambdaVEV) );
}
// squarks
else {
Complex q1a(0.0), q1b(0.0), q2a(0.0), q2b(0.0);
complex<Energy> triD(ZERO), triU(ZERO);
// up-type bit
// stop
if(utype == 6){
q1a = (*_mixTp)(alpha, 0) ;
q2a = (*_mixTp)(alpha, 1);
triU = _triTp;
}
// light
else{
q1a = (alpha == 0) ? 1.0 : 0.0;
q2a = (alpha == 0) ? 0.0 : 1.0;
}
// down-type bit
// sbottom
if(dtype == 5){
q1b = (*_mixBt)(beta, 0) ;
q2b = (*_mixBt)(beta, 1);
triD = _triBt;
}
// light
else{
q1b = (beta == 0) ? 1.0 : 0.0;
q2b = (beta == 0) ? 0.0 : 1.0;
}
Energy mfu = _masslast.first;
Energy mfd = _masslast.second;
coupling = ( q1a*q1b*((sqr(mfd)*_tb + sqr(mfu)/_tb) - facta)
+ q2a*q2b*mfu*mfd*(_tb + (1./_tb))
+ q1a*q2b*mfd*(triD*_tb + _lambdaVEV)
+ q2a*q1b*mfu*(triU/_tb + _lambdaVEV));
}
return coupling * UnitRemoval::InvE/_mw/sqrt(2.);
}
diff --git a/Models/Susy/NMSSM/NMSSMPPHVertex.cc b/Models/Susy/NMSSM/NMSSMPPHVertex.cc
--- a/Models/Susy/NMSSM/NMSSMPPHVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMPPHVertex.cc
@@ -1,283 +1,284 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMPPHVertex class.
//
#include "NMSSMPPHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Models/Susy/NMSSM/NMSSM.h"
#include "Herwig/Looptools/clooptools.h"
using namespace Herwig;
NMSSMPPHVertex::NMSSMPPHVertex()
: _sw(0.), _cw(0.), _mw(0.*MeV),
_mz(0.*MeV),_lambdaVEV(0.*MeV), _lambda(0.),
_triTp(0.*MeV), _triBt(0.*MeV),
_sb(0.), _cb(0.),
_kappa(0.),_vu(ZERO),_vd(ZERO),_s(ZERO),_theAl(ZERO),
_masslast(make_pair(0.*MeV,0.*MeV)),_q2last(0.*MeV2),
_couplast(0.), _coup(0.), _hlast(0), _recalc(true) {
orderInGem(3);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void NMSSMPPHVertex::doinit() {
addToList(22,22,25);
addToList(22,22,35);
addToList(22,22,36);
addToList(22,22,45);
addToList(22,22,46);
_theSM = dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel());
if( !_theSM ) {
throw InitException() << "NMSSMPPHVertex::doinit - The SM pointer is null!"
<< Exception::abortnow;
}
// SM parameters
_sw = sqrt(sin2ThetaW());
_cw = sqrt(1. - sin2ThetaW());
_mw = getParticleData(24)->mass();
_mz = getParticleData(23)->mass();
_top = getParticleData(6);
_bt = getParticleData(5);
_tau = getParticleData(15);
//NMSSM parameters
tcNMSSMPtr nmssm = dynamic_ptr_cast<tcNMSSMPtr>(_theSM);
_mixS = nmssm->CPevenHiggsMix();
_mixP = nmssm->CPoddHiggsMix();
_mixQt = nmssm->stopMix();
_mixQb = nmssm->sbottomMix();
_mixLt = nmssm->stauMix();
double beta = atan(nmssm->tanBeta());
_sb = sin(beta);
_cb = cos(beta);
_lambda = nmssm->lambda();
_lambdaVEV = nmssm->lambdaVEV();
_triTp = nmssm->topTrilinear();
_triBt = nmssm->bottomTrilinear();
_triTa = nmssm->tauTrilinear();
_vd = sqrt(2)*_mw*_cb;
_vu = sqrt(2)*_mw*_sb;
_s = _lambdaVEV/_lambda;
_theAl = nmssm->trilinearLambda();
_kappa = nmssm->kappa();
_mixU = nmssm->charginoUMix();
_mixV = nmssm->charginoVMix();
// resize vectors here and use setNParticles method
// to the set the actual number in the loop.
// Also only the top mass hass to be calculated at runtime
masses.resize(13, Energy());
masses[ 0] = getParticleData( 6)->mass();
masses[ 1] = getParticleData( 5)->mass();
masses[ 2] = getParticleData(15)->mass();
masses[ 3] = getParticleData(ParticleID::SUSY_chi_1plus)->mass();
masses[ 4] = getParticleData(ParticleID::SUSY_chi_2plus)->mass();
masses[ 5] = _mw;
masses[ 6] = getParticleData(ParticleID::Hplus)->mass();
masses[ 7] = getParticleData(1000005)->mass();
masses[ 8] = getParticleData(2000005)->mass();
masses[ 9] = getParticleData(1000006)->mass();
masses[10] = getParticleData(2000006)->mass();
masses[11] = getParticleData(1000015)->mass();
masses[12] = getParticleData(2000015)->mass();
type.resize(13, PDT::Spin0);
type[0] = PDT::Spin1Half;
type[1] = PDT::Spin1Half;
type[2] = PDT::Spin1Half;
type[3] = PDT::Spin1Half;
type[4] = PDT::Spin1Half;
type[5] = PDT::Spin1;
couplings.resize(13);
VVSLoopVertex::doinit();
if(loopToolsInitialized()) Looptools::ltexi();
}
void NMSSMPPHVertex::persistentOutput(PersistentOStream & os) const {
os << _theSM << _sw << _cw << ounit(_mw, GeV) << ounit(_mz, GeV)
<< ounit(_lambdaVEV,GeV) << _lambda
<< ounit(_triTp,GeV) << ounit(_triBt,GeV) << ounit(_triTa,GeV)
<< _top << _bt << _tau << _mixS << _mixP << _mixU << _mixV
<< _mixQt << _mixQb << _mixLt << _sb << _cb << _kappa
<< ounit(_vu,GeV) << ounit(_vd,GeV) << ounit(_s,GeV) << ounit(_theAl,GeV);
}
void NMSSMPPHVertex::persistentInput(PersistentIStream & is, int) {
is >> _theSM >> _sw >> _cw >> iunit(_mw, GeV) >> iunit(_mz, GeV)
>> iunit(_lambdaVEV,GeV) >> _lambda
>> iunit(_triTp,GeV) >> iunit(_triBt,GeV) >> iunit(_triTa,GeV)
>> _top >> _bt >> _tau >> _mixS >> _mixP >> _mixU >> _mixV
>> _mixQt >> _mixQb >> _mixLt >> _sb >> _cb >> _kappa
>> iunit(_vu,GeV) >> iunit(_vd,GeV) >> iunit(_s,GeV) >> iunit(_theAl,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMPPHVertex,VVSLoopVertex>
describeHerwigNMSSMPPHVertex("Herwig::NMSSMPPHVertex", "HwSusy.so HwNMSSM.so");
void NMSSMPPHVertex::Init() {
static ClassDocumentation<NMSSMPPHVertex> documentation
("The effective coupling of a higgs to a pair of gluons in the "
"NMSSM.");
}
void NMSSMPPHVertex::setCoupling(Energy2 q2, tcPDPtr p1, tcPDPtr p2,
tcPDPtr p3) {
long hid(p3->id());
double rt = sqrt(0.5);
if( q2 != _q2last ) {
Looptools::clearcache();
_couplast = sqr(electroMagneticCoupling(q2));
_coup = weakCoupling(q2);
_q2last = q2;
_recalc = true;
}
norm(_couplast*_coup);
// scalar higgs bosons
if( hid != _hlast ) {
_hlast = hid;
_recalc = true;
// top and bottom quark masses
Energy mt = _theSM->mass(q2, _top);
Energy mb = _theSM->mass(q2, _bt);
Energy mtau = _theSM->mass(q2, _tau);
// scalar
if( hid % 5 == 0 ) {
// location of the higgs
int iloc = (hid - 25)/10;
// 6 particles in the loop
setNParticles(13);
Complex c(0.);
// couplings for the top quark loop
c = -1.5*sqr(_theSM->eu())* mt*(*_mixS)(iloc, 1)/_sb/_mw;
couplings[0] = make_pair(c,c);
masses[0] = mt;
// couplings for the bottom quark loop
c = -1.5*sqr(_theSM->ed())* mb*(*_mixS)(iloc, 0)/_cb/_mw;
couplings[1] = make_pair(c,c);
masses[1] = mb;
// couplings for the tau lepton loop
c = -0.5*sqr(_theSM->ee())*mtau*(*_mixS)(iloc, 0)/_cb/_mw;
couplings[2] = make_pair(c,c);
masses[2] = mtau;
// charginos
for(unsigned int ic=0;ic<2;++ic) {
c = -_lambda/_coup*rt*(*_mixS)(iloc,2)*(*_mixU)(ic,1)*(*_mixV)(ic,1)
-rt*((*_mixS)(iloc,0)*(*_mixU)(ic,1)*(*_mixV)(ic,0) +
(*_mixS)(iloc,1)*(*_mixU)(ic,0)*(*_mixV)(ic,1));
couplings[3+ic] = make_pair(c,c);
}
// W boson
c = UnitRemoval::InvE*_mw*
(_cb*(*_mixS)(iloc,0)+_sb*(*_mixS)(iloc,1));
couplings[5] = make_pair(c,c);
// charged Higgs
complex<Energy> cpl;
cpl = sqr(_lambda)*rt*2.*(_s*((*_mixS)(iloc,2)*sqr(_cb) + (*_mixS)(iloc,2)*sqr(_sb))
- (_vu*(*_mixS)(iloc,0)/_coup +
_vd*(*_mixS)(iloc,1)/_coup)*_sb*_cb)
+_lambda*_sb*_cb*2*(*_mixS)(iloc,2)*(_kappa*_s/rt + rt*_theAl)
+ sqr(_coup)*0.5*rt*sqr(_sw)/sqr(_cw)*((_vu*(*_mixS)(iloc,1)/_coup -
_vd*(*_mixS)(iloc,0)/_coup)*sqr(_cb) +
(_vd*(*_mixS)(iloc,0)/_coup -
_vu*(*_mixS)(iloc,1)/_coup)*sqr(_sb))
+ sqr(_coup)*0.5*rt*(_vu*((*_mixS)(iloc,1)*sqr(_cb) +
(*_mixS)(iloc,1)*sqr(_sb) +
2.*(*_mixS)(iloc,0)*_cb*_sb)/_coup
+ _vd*((*_mixS)(iloc,0)*sqr(_cb) +
(*_mixS)(iloc,0)*sqr(_sb)
+ 2.*(*_mixS)(iloc,1)*_sb*_cb)/_coup);
cpl /= -_coup;
couplings[6] = make_pair(cpl*UnitRemoval::InvE,cpl*UnitRemoval::InvE);
// sbottoms
double f1 = mb/_mw/_cb;
complex<Energy> f2 = 0.5*_mz/_cw*
( - _cb*(*_mixS)(iloc,0) + _sb*(*_mixS)(iloc,1));
for(unsigned int ix=0;ix<2;++ix) {
cpl = -f2*( (1. - 2.*sqr(_sw)/3.)*(*_mixQb)(ix, 0)*(*_mixQb)(ix, 0)
+ 2.*sqr(_sw)*(*_mixQb)(ix, 1)*(*_mixQb)(ix, 1)/3.)
- f1*mb*(*_mixS)(iloc,0)
*((*_mixQb)(ix, 0)*(*_mixQb)(ix, 0) + (*_mixQb)(ix, 1)*(*_mixQb)(ix, 1))
- 0.5*f1*(-_lambdaVEV*(*_mixS)(iloc,1) - _lambda*_vu*(*_mixS)(iloc,2)/_coup
+ _triBt*(*_mixS)(iloc,0))*((*_mixQb)(ix, 1)*(*_mixQb)(ix, 0)
+ (*_mixQb)(ix, 0)*(*_mixQb)(ix, 1));
cpl *= 3.*sqr(_theSM->ed());
couplings[7+ix] = make_pair(cpl*UnitRemoval::InvE,cpl*UnitRemoval::InvE);
}
// stop
f1 = mt/_mw/_sb;
for(unsigned int ix=0;ix<2;++ix) {
cpl =+f2*( (1. - 4.*sqr(_sw)/3.)*(*_mixQt)(ix, 0)*(*_mixQt)(ix, 0)
+ 4.*sqr(_sw)*(*_mixQt)(ix, 1)*(*_mixQt)(ix, 1)/3.)
- f1*mt*(*_mixS)(iloc,1)
*((*_mixQt)(ix, 0)*(*_mixQt)(ix, 0)
+ (*_mixQt)(ix, 1)*(*_mixQt)(ix, 1))
- 0.5*f1*(-_lambdaVEV*(*_mixS)(iloc,0) - _lambda*_vd*(*_mixS)(iloc,2)/_coup
+ _triTp*(*_mixS)(iloc,1))*((*_mixQt)(ix, 1)*(*_mixQt)(ix, 0)
+ (*_mixQt)(ix, 0)*(*_mixQt)(ix, 1));
cpl *= 3.*sqr(_theSM->eu());
couplings[9+ix] = make_pair(cpl*UnitRemoval::InvE,cpl*UnitRemoval::InvE);
} // sbottoms
f1 = mtau/_mw/_cb;
for(unsigned int ix=0;ix<2;++ix) {
cpl = -f2*( (1. - 2.*sqr(_sw))*(*_mixLt)(ix, 0)*(*_mixLt)(ix, 0)
+ 2.*sqr(_sw)*(*_mixLt)(ix, 1)*(*_mixLt)(ix, 1))
- f1*mtau*(*_mixS)(iloc,0)
*((*_mixLt)(ix, 0)*(*_mixLt)(ix, 0) + (*_mixLt)(ix, 1)*(*_mixLt)(ix, 1))
- 0.5*f1*(-_lambdaVEV*(*_mixS)(iloc,1) - _lambda*_vu*(*_mixS)(iloc,2)/_coup
+ _triTa*(*_mixS)(iloc,0))*((*_mixLt)(ix, 1)*(*_mixLt)(ix, 0)
+ (*_mixLt)(ix, 0)*(*_mixLt)(ix, 1));
cpl *= sqr(_theSM->ee());
couplings[11+ix] = make_pair(cpl*UnitRemoval::InvE,cpl*UnitRemoval::InvE);
}
}
// pseudoscalar higgs bosons
else {
// location of the higgs
int iloc = (hid - 36)/10;
// 2 particles in the loop
setNParticles(5);
Complex c(0.);
// top quark couplings
c = Complex(0., 1.)*1.5*sqr(_theSM->eu())* mt*(*_mixP)(iloc, 1)/_sb/_mw;
couplings[0] = make_pair(c,-c);
masses[0] = mt;
// bottom quark couplings
c = Complex(0., 1.)*1.5*sqr(_theSM->ed())* mb*(*_mixP)(iloc, 0)/_cb/_mw;
couplings[1] = make_pair(c,-c);
masses[1] = mb;
// tau lepton couplings
c = Complex(0., 1.)*0.5*sqr(_theSM->ee())*mtau*(*_mixP)(iloc, 0)/_cb/_mw;
couplings[2] = make_pair(c,-c);
masses[2] = mtau;
// charginos
for(unsigned int ic=0;ic<2;++ic) {
c = Complex(0,-1.0)*
(_lambda/_coup*rt*(*_mixP)(iloc,2)*(*_mixU)(ic,1)*(*_mixV)(ic,1)
-rt*((*_mixP)(iloc,0)*(*_mixU)(ic,1)*(*_mixV)(ic,0)
+ (*_mixP)(iloc,1)*(*_mixU)(ic,0)*(*_mixV)(ic,1)));
couplings[3+ic] = make_pair(-c,c);
}
}
}
if( _recalc ) {
VVSLoopVertex::setCoupling(q2, p1, p2, p3);
_recalc = false;
}
}
diff --git a/Models/Susy/NMSSM/NMSSMWHHVertex.cc b/Models/Susy/NMSSM/NMSSMWHHVertex.cc
--- a/Models/Susy/NMSSM/NMSSMWHHVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMWHHVertex.cc
@@ -1,157 +1,158 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMWHHVertex class.
//
#include "NMSSMWHHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "NMSSM.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
NMSSMWHHVertex::NMSSMWHHVertex() : _sinb(0.), _cosb(0.), _sw(0.), _cw(0.),
_q2last(0.*MeV2), _couplast(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void NMSSMWHHVertex::doinit() {
// codes for the neutral higgs
//CP even
int ieven[3]={25,35,45};
//CP odd
int iodd [2]={36,46};
// Z CP even CP odd
for(unsigned int ix=0;ix<3;++ix)
for(unsigned int iy=0;iy<2;++iy)
addToList( 23, ieven[ix], iodd[iy] );
// W H+ CP even
for(unsigned int ix=0;ix<3;++ix)
addToList( -24, 37, ieven[ix] );
// W+ H- CP even
for(unsigned int ix=0;ix<3;++ix)
addToList( 24, -37, ieven[ix] );
// W H+ CP odd
for(unsigned int ix=0;ix<2;++ix)
addToList( -24, 37, iodd[ix] );
//W+ H- CP odd
for(unsigned int ix=0;ix<2;++ix)
addToList( 24, -37, iodd[ix] );
// Charged higgs Z/gamma
addToList( 22, 37, -37 );
addToList( 23, 37, -37 );
// cast to NMSSM model
tcNMSSMPtr model=dynamic_ptr_cast<tcNMSSMPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must have the NMSSM Model in NMSSMFFHVertex::doinit()"
<< Exception::runerror;
// sin theta_W
double sw2 = sin2ThetaW();
_sw = sqrt(sw2);
_cw = sqrt(1.-sw2);
// get the mixing matrices
_mixS=model->CPevenHiggsMix();
if(!_mixS) throw InitException() << "Mixing matrix for CP-even neutral Higgs"
<< " bosons is not set in NMSSMWHHVertex::doinit()"
<< Exception::runerror;
_mixP=model->CPoddHiggsMix();
if(!_mixP) throw InitException() << "Mixing matrix for CP-odd neutral Higgs"
<< " bosons is not set in NMSSMWHHVertex::doinit()"
<< Exception::runerror;
// sin and cos beta
double beta = atan(model->tanBeta());
_sinb = sin(beta);
_cosb = cos(beta);
// base class
VSSVertex::doinit();
}
void NMSSMWHHVertex::persistentOutput(PersistentOStream & os) const {
os << _sinb << _cosb << _sw << _cw << _mixS << _mixP;
}
void NMSSMWHHVertex::persistentInput(PersistentIStream & is, int) {
is >> _sinb >> _cosb >> _sw >> _cw >> _mixS >> _mixP;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMWHHVertex,VSSVertex>
describeHerwigNMSSMWHHVertex("Herwig::NMSSMWHHVertex", "HwSusy.so HwNMSSM.so");
void NMSSMWHHVertex::Init() {
static ClassDocumentation<NMSSMWHHVertex> documentation
("The NMSSMWHHVertex class implements the coupling of an electroweak"
" gauge boson with two Higgs bosons in the NMSSM.");
}
//calulate the couplings
void NMSSMWHHVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr b,tcPDPtr c) {
// weak coupling
if(q2!=_q2last) {
_couplast = weakCoupling(q2);
_q2last=q2;
}
// gauge bosons
int ibos= a->id();
int ih1 = b->id();
int ih2 = c->id();
Complex fact;
if(ibos==ParticleID::Z0) {
fact = 0.5/_cw;
// Z H+ H-
if(abs(ih1)==37) {
fact *= (sqr(_cw)-sqr(_sw));
if(ih1<0) fact *=-1.;
}
// Z CP even CP odd
else {
if(ih1%10==6) {
fact *= -1.;
swap(ih1,ih2);
}
int is = (ih1-25)/10;
int ip = (ih2-36)/10;
fact *= Complex(0.,1.)*((*_mixS)(is,1)*(*_mixP)(ip,1)-
(*_mixS)(is,0)*(*_mixP)(ip,0));
}
}
// gamma CP even CP odd
else if(ibos==ParticleID::gamma) {
fact = ih1>0 ? _sw : -_sw;
}
// W boson
else {
fact = 0.5;
if(abs(ih2)==37) {
swap(ih1,ih2);
fact*=-1;
}
// H+ CP even
if(ih2%5==0) {
int is = (ih2-25)/10;
fact *= (_cosb*(*_mixS)(is,1)-_sinb*(*_mixS)(is,0));
if(ibos<0) fact*=-1;
}
// H+ CP odd
else {
int ip = (ih2-36)/10;
fact *=-Complex(0.,1.)*(_cosb*(*_mixP)(ip,1)+_sinb*(*_mixP)(ip,0));
}
}
//output the coupling
norm(_couplast*fact);
}
diff --git a/Models/Susy/NMSSM/NMSSMWWHHVertex.cc b/Models/Susy/NMSSM/NMSSMWWHHVertex.cc
--- a/Models/Susy/NMSSM/NMSSMWWHHVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMWWHHVertex.cc
@@ -1,175 +1,176 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMWWHHVertex class.
//
#include "NMSSMWWHHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "NMSSM.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
NMSSMWWHHVertex::NMSSMWWHHVertex() : couplast_(0.),q2last_(ZERO),
sw_(0.), cw_(0.), sb_(0.), cb_(0.) {
orderInGem(2);
orderInGs (0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr NMSSMWWHHVertex::clone() const {
return new_ptr(*this);
}
IBPtr NMSSMWWHHVertex::fullclone() const {
return new_ptr(*this);
}
void NMSSMWWHHVertex::persistentOutput(PersistentOStream & os) const {
os << sw_ << cw_ << sb_ << cb_ << mixS_ << mixP_;
}
void NMSSMWWHHVertex::persistentInput(PersistentIStream & is, int) {
is >> sw_ >> cw_ >> sb_ >> cb_ >> mixS_ >> mixP_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMWWHHVertex,Helicity::VVSSVertex>
describeHerwigNMSSMWWHHVertex("Herwig::NMSSMWWHHVertex", "NMSSMWWHHVertex.so");
void NMSSMWWHHVertex::Init() {
static ClassDocumentation<NMSSMWWHHVertex> documentation
("The NMSSMWWHHVertex class implements the coupling of"
" two electroweak and two Higgs bosons in the NMSSM.");
}
void NMSSMWWHHVertex::doinit() {
int scalar[3]={25,35,45};
int pseudo[2]={36,46};
// scalar higgs bosons
for(unsigned int i=0;i<3;++i) {
// pair of scalars
for(unsigned int j=0;j<3;++j) {
addToList( 24,-24,scalar[i],scalar[j]);
addToList( 23, 23,scalar[i],scalar[j]);
}
// scalar charged
addToList( 22, 24,scalar[i],-37);
addToList( 22,-24,scalar[i], 37);
addToList( 23, 24,scalar[i],-37);
addToList( 23,-24,scalar[i], 37);
}
// pair of pseudoscalars
for(unsigned int i=0;i<2;++i) {
for(unsigned int j=0;j<2;++j) {
addToList( 24,-24,pseudo[i],pseudo[j]);
addToList( 23, 23,pseudo[i],pseudo[j]);
}
// pseudo charged
addToList( 22, 24,pseudo[i],-37);
addToList( 22,-24,pseudo[i], 37);
addToList( 23, 24,pseudo[i],-37);
addToList( 23,-24,pseudo[i], 37);
}
addToList( 24,-24, 37,-37);
addToList( 23, 23, 37,-37);
addToList( 22, 23, 37,-37);
addToList( 22, 22, 37,-37);
// cast to NMSSM model
tcNMSSMPtr model=dynamic_ptr_cast<tcNMSSMPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must have the NMSSM Model in NMSSMWWHHVertex::doinit()"
<< Exception::runerror;
// sin and cos theta_W
sw_ = sqrt( sin2ThetaW());
cw_ = sqrt(1.-sin2ThetaW());
// get the mixing matrices
mixS_ = model->CPevenHiggsMix();
if(!mixS_) throw InitException() << "Mixing matrix for CP-even neutral Higgs"
<< " bosons is not set in NMSSMWWHHVertex::doinit()"
<< Exception::runerror;
mixP_ = model->CPoddHiggsMix();
if(!mixP_) throw InitException() << "Mixing matrix for CP-odd neutral Higgs"
<< " bosons is not set in NMSSMWWHHVertex::doinit()"
<< Exception::runerror;
// sin and cos beta
double beta = atan(model->tanBeta());
sb_ = sin(beta);
cb_ = cos(beta);
// base class
VVSSVertex::doinit();
}
void NMSSMWWHHVertex::setCoupling(Energy2 q2,tcPDPtr part1,tcPDPtr part2,
tcPDPtr part3, tcPDPtr part4) {
if(q2!=q2last_||couplast_==0.) {
couplast_ = sqr(electroMagneticCoupling(q2));
q2last_=q2;
}
int ibos1 = part1->id(), ibos2 = part2->id();
int isca1 = part3->id(), isca2 = part4->id();
Complex fact(1.);
if(abs(ibos1)==abs(ibos2)) {
fact *= 0.5/sqr(sw_);
if(ibos1==ParticleID::Z0) fact /= sqr(cw_);
// charged
if(abs(isca1)==37) {
if(ibos1==ParticleID::Z0) fact *= sqr(sqr(cw_)-sqr(sw_));
else if(ibos1==ParticleID::gamma) fact = 2.;
}
// pair of scalars
else if((isca1-5)%10==0) {
unsigned int i = (isca1-25)/10;
unsigned int j = (isca2-25)/10;
fact *= (*mixS_)(i,0)*(*mixS_)(j,0)+(*mixS_)(i,1)*(*mixS_)(j,1);
}
// pair of pseudoscalars
else if((isca1-6)%10==0) {
unsigned int i = (isca1-36)/10;
unsigned int j = (isca2-36)/10;
fact *= (*mixP_)(i,0)*(*mixP_)(j,0)+(*mixP_)(i,1)*(*mixP_)(j,1);
}
else
assert(false);
}
else if(abs(ibos1)==ParticleID::Wplus ||
abs(ibos2)==ParticleID::Wplus) {
if(abs(ibos1)==ParticleID::gamma ||
abs(ibos2)==ParticleID::gamma) {
fact *= -0.5/sw_;
}
else {
fact *= 0.5/cw_;
}
if((isca1-5)%10==0) {
unsigned int i = (isca1-25)/10;
fact *= sb_*(*mixS_)(i,0) - cb_*(*mixS_)(i,1);
}
else if((isca2-5)%10==0) {
unsigned int i = (isca2-25)/10;
fact *= sb_*(*mixS_)(i,0) - cb_*(*mixS_)(i,1);
}
else if((isca1-6)%10==0) {
unsigned int i = (isca1-36)/10;
fact *= sb_*(*mixP_)(i,0) + cb_*(*mixP_)(i,1);
fact *= isca2==ParticleID::Hplus ? -Complex(0.,1.) : Complex(0.,1.);
}
else if((isca2-6)%10==0) {
unsigned int i = (isca2-36)/10;
fact *= sb_*(*mixP_)(i,0) + cb_*(*mixP_)(i,1);
fact *= isca1==ParticleID::Hplus ? -Complex(0.,1.) : Complex(0.,1.);
}
else
assert(false);
}
else {
fact = (sqr(cw_)-sqr(sw_))/cw_/sw_;
}
// set the coupling
norm(couplast_*fact);
}
diff --git a/Models/Susy/NMSSM/NMSSMWWHVertex.cc b/Models/Susy/NMSSM/NMSSMWWHVertex.cc
--- a/Models/Susy/NMSSM/NMSSMWWHVertex.cc
+++ b/Models/Susy/NMSSM/NMSSMWWHVertex.cc
@@ -1,92 +1,93 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the NMSSMWWHVertex class.
//
#include "NMSSMWWHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "NMSSM.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
NMSSMWWHVertex::NMSSMWWHVertex()
: _couplast(0.), _q2last(), _mw(), _zfact(0.), _sinb(0.),_cosb(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void NMSSMWWHVertex::doinit() {
int id[3]={25,35,45};
// PDG codes for the particles in the vertex
for(unsigned int ix=0;ix<3;++ix) {
// Higgs WW
addToList( 24, -24, id[ix] );
//Higgs ZZ
addToList( 23, 23, id[ix] );
}
// SM parameters
_mw = getParticleData(ThePEG::ParticleID::Wplus)->mass();
double sw2 = sin2ThetaW();
_zfact = 1./(1.-sw2);
// NMSSM parameters
tcNMSSMPtr model=dynamic_ptr_cast<tcNMSSMPtr>(generator()->standardModel());
if(!model)
throw InitException() << "Must have the NMSSM Model in NMSSMWWHVertex::doinit()"
<< Exception::runerror;
// get the mixing matrices
_mixS=model->CPevenHiggsMix();
if(!_mixS) throw InitException() << "Mixing matrix for CP-even neutral Higgs"
<< " bosons is not set in NMSSMWWHVertex::doinit()"
<< Exception::runerror;
// sin and cos beta
double beta = atan(model->tanBeta());
_sinb=sin(beta);
_cosb=cos(beta);
// base class
VVSVertex::doinit();
}
void NMSSMWWHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(_mw,GeV) << _zfact << _sinb << _cosb << _mixS;
}
void NMSSMWWHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(_mw,GeV) >> _zfact >> _sinb >> _cosb >> _mixS;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<NMSSMWWHVertex,VVSVertex>
describeHerwigNMSSMWWHVertex("Herwig::NMSSMWWHVertex", "HwSusy.so HwNMSSM.so");
void NMSSMWWHVertex::Init() {
static ClassDocumentation<NMSSMWWHVertex> documentation
("The NMSSMWWHVertex class implements the coupling of two electroweak gauge"
" bosons with the Higgs bosons of the NMSSM");
}
//calulate couplings
void NMSSMWWHVertex::setCoupling(Energy2 q2,tcPDPtr a,tcPDPtr, tcPDPtr c) {
// ID of gauge bosons
int ibos=abs(a->id());
// ID of Higgs
int ihiggs = (c->id()-25)/10;
// first the overall normalisation
if(q2!=_q2last) {
_couplast = weakCoupling(q2)*_mw*UnitRemoval::InvE;
_q2last=q2;
}
// higgs mixing factor
Complex hmix = _cosb*(*_mixS)(ihiggs,0)+_sinb*(*_mixS)(ihiggs,1);
// couplings
if(ibos==24) norm(_couplast*hmix);
else if(ibos==23) norm(_couplast*hmix*_zfact);
else assert(false);
}
diff --git a/Models/Susy/RPV/RPVFFSVertex.cc b/Models/Susy/RPV/RPVFFSVertex.cc
--- a/Models/Susy/RPV/RPVFFSVertex.cc
+++ b/Models/Susy/RPV/RPVFFSVertex.cc
@@ -1,825 +1,826 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RPVFFSVertex class.
//
#include "RPVFFSVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
namespace {
unsigned int neutralinoIndex(long id) {
if(id> 1000000)
return id<1000025 ? id-1000022 : (id-1000005)/10;
else if(abs(id)<=16)
return (abs(id)-4)/2;
else
return id-13;
}
unsigned int charginoIndex(long id) {
return abs(id)>1000000 ? (abs(id)-1000024)/13 : (abs(id)-7)/2;
}
}
RPVFFSVertex::RPVFFSVertex() : interactions_(0), mw_(ZERO),
_q2last(ZERO), _couplast(0.),
_leftlast(0.),_rightlast(0.),
_id1last(0), _id2last(0), _id3last(0),
yukawa_(true),
_sw(0.), _cw(0.),_sb(0.), _cb(0.),
vd_(ZERO), vu_(ZERO),
_massLast(make_pair(ZERO,ZERO)) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
IBPtr RPVFFSVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVFFSVertex::fullclone() const {
return new_ptr(*this);
}
void RPVFFSVertex::doinit() {
// cast the model to the RPV one
model_ = dynamic_ptr_cast<tRPVPtr>(generator()->standardModel());
if( !model_ ) throw InitException() << "RPVFFSVertex::doinit() - "
<< "The pointer to the MSSM object is null!"
<< Exception::abortnow;
// get the various mixing matrices
_stop = model_->stopMix();
_sbot = model_->sbottomMix();
_stau = model_->stauMix();
_nmix = model_->neutralinoMix();
_umix = model_->charginoUMix();
_vmix = model_->charginoVMix();
_mixH = model_->CPevenHiggsMix();
_mixP = model_->CPoddHiggsMix();
_mixC = model_->ChargedHiggsMix();
if(!_stop || !_sbot ) throw InitException() << "RPVFFSVertex::doinit() - "
<< "A squark mixing matrix pointer is null."
<< " stop: " << _stop << " sbottom: "
<< _sbot << Exception::abortnow;
if(!_nmix) throw InitException() << "RPVFFSVertex::doinit() - "
<< "A gaugino mixing matrix pointer is null."
<< " N: " << _nmix << " U: " << _umix
<< " V: " << _vmix << Exception::abortnow;
if(! ( _stau || (!_stau&& _mixC->size().first>1)))
throw InitException() << "RPVFFSVertex::doinit() - "
<< "Must have either the stau mixing matrix or it"
<< " must be part of the charged Higgs boson mixing."
<< Exception::abortnow;
// various interactions
// scalar Higgs bosons
vector<long> h0(2);
h0[0] = 25; h0[1] = 35;
if(_mixH&&_mixH->size().first>2) {
h0.push_back(1000012); h0.push_back(1000014); h0.push_back(1000016);
}
// pseudoscalar Higgs bosons
vector<long> a0(1,36);
if(_mixP&&_mixP->size().first>1) {
a0.push_back(1000017); a0.push_back(1000018); a0.push_back(1000019);
}
// charged Higgs bosons
vector<long> hp(1,37);
if(_mixC->size().first>1) {
hp.push_back(-1000011); hp.push_back(-1000013); hp.push_back(-1000015);
hp.push_back(-2000011); hp.push_back(-2000013); hp.push_back(-2000015);
}
// neutralinos
vector<long> neu(4);
neu[0] = 1000022; neu[1] = 1000023;
neu[2] = 1000025; neu[3] = 1000035;
if(_nmix->size().first>4) {
if(model_->majoranaNeutrinos()) {
neu.push_back(17);
neu.push_back(18);
neu.push_back(19);
}
else {
neu.push_back(12);
neu.push_back(14);
neu.push_back(16);
}
}
// charginos
vector<long> chg(2);
chg[0] = 1000024; chg[1] = 1000037;
if(_umix->size().first>2) {
chg.push_back(-11); chg.push_back(-13); chg.push_back(-15);
}
// FFH
if(interactions_==0||interactions_==1) {
// quarks neutral scalar
for ( unsigned int h = 0; h < h0.size(); ++h ) {
for(long ix=1;ix<7;++ix) addToList(-ix,ix,h0[h]);
}
// quarks neutral pseudoscalar
for ( unsigned int h = 0; h < a0.size(); ++h ) {
for(long ix=1;ix<7;++ix) addToList(-ix,ix,a0[h]);
}
// quarks charged higgs
for(unsigned int h=0;h<hp.size();++h) {
for(long ix=1;ix<6;ix+=2) {
//outgoing H+
addToList(-ix-1, ix, hp[h]);
//outgoing H-
addToList(-ix ,ix+1,-hp[h]);
}
}
// charged leptons neutral scalar
for ( unsigned int h = 0; h < h0.size(); ++h ) {
for(long ix=11;ix<16;ix+=2) addToList(-ix,ix,h0[h]);
}
// charged leptons neutral pseudoscalar
for ( unsigned int h = 0; h < a0.size(); ++h ) {
for(long ix=11;ix<16;ix+=2) addToList(-ix,ix,a0[h]);
}
// charged higgs to leptons, no mixing
if(_nmix->size().first<=4) {
for(unsigned int h=0;h<hp.size();++h) {
for(long ix=11;ix<16;ix+=2) {
//outgoing H+
addToList(-ix-1, ix, hp[h]);
//outgoing H-
addToList(-ix ,ix+1,-hp[h]);
}
}
}
}
// GOGOH
if(interactions_==0||interactions_==2) {
// neutral scalar Higgs neutralino
for(unsigned int i=0;i<h0.size();++i) {
for(unsigned int j = 0; j < neu.size(); ++j) {
for(unsigned int k = j; k < neu.size(); ++k) {
addToList(neu[j], neu[k], h0[i]);
}
}
}
// neutral pseudoscalar Higgs neutralino
for(unsigned int i=0;i<a0.size();++i) {
for(unsigned int j = 0; j < neu.size(); ++j) {
for(unsigned int k = j; k < neu.size(); ++k) {
addToList(neu[j], neu[k], a0[i]);
}
}
}
// neutral scalar Higgs chargino
for(unsigned int i=0;i<h0.size();++i) {
for(unsigned int j = 0; j < chg.size(); ++j) {
for(unsigned int k = 0; k < chg.size(); ++k) {
if(j==k&&abs(chg[j])<16) continue;
addToList(-chg[j], chg[k], h0[i]);
}
}
}
// neutral scalar Higgs chargino
for(unsigned int i=0;i<a0.size();++i) {
for(unsigned int j = 0; j < chg.size(); ++j) {
for(unsigned int k = 0; k < chg.size(); ++k) {
if(j==k&&abs(chg[j])<16) continue;
addToList(-chg[j], chg[k], a0[i]);
}
}
}
// charged higgs
for(unsigned int i=0;i<hp.size();++i) {
for(unsigned int j = 0; j < neu.size(); ++j) {
for(unsigned int k = 0; k < chg.size(); ++k) {
addToList(-chg[k], neu[j], hp[i]);
addToList( chg[k], neu[j],-hp[i]);
}
}
}
}
// neutralino sfermion
if(interactions_==0||interactions_==3) {
// quarks
for(unsigned int nl = 0; nl < neu.size(); ++nl) {
for(long ix=1;ix<7;++ix){
addToList( neu[nl], ix, -(1000000+ix) );
addToList( neu[nl], ix, -(2000000+ix) );
addToList( neu[nl], -ix, (1000000+ix) );
addToList( neu[nl], -ix, (2000000+ix) );
}
}
// neutrino
if(_nmix->size().first<=4) {
for(unsigned int nl = 0; nl < neu.size(); ++nl) {
for(long ix=12;ix<17;ix+=2) {
addToList( neu[nl], ix, -(1000000+ix) );
addToList( neu[nl], -ix, (1000000+ix) );
}
}
}
// charged leptons no mixing
if(!_mixC || _mixC->size().first==1) {
for(unsigned int nl = 0; nl < neu.size(); ++nl) {
for(long ix=11;ix<17;ix+=2) {
addToList( neu[nl], ix, -(1000000+ix) );
addToList( neu[nl], -ix, (1000000+ix) );
addToList( neu[nl], ix, -(2000000+ix) );
addToList( neu[nl], -ix, (2000000+ix) );
}
}
}
}
// chargino sfermion
if(interactions_==0||interactions_==4) {
//quarks
for(unsigned int ic = 0; ic < chg.size(); ++ic) {
for(long ix = 1; ix < 7; ++ix) {
if( ix % 2 == 0 ) {
addToList(-chg[ic], ix,-( 999999+ix));
addToList(-chg[ic], ix,-(1999999+ix));
addToList( chg[ic],-ix, 999999+ix );
addToList( chg[ic],-ix, 1999999+ix );
}
else {
addToList(-chg[ic],-ix, 1000001+ix );
addToList(-chg[ic],-ix, 2000001+ix );
addToList( chg[ic], ix,-(1000001+ix));
addToList( chg[ic], ix,-(2000001+ix));
}
}
}
// sneutrinos
if(!_mixH || _mixH->size().first<=2) {
for(unsigned int ic = 0; ic < chg.size(); ++ic) {
for(long ix = 11; ix < 17; ix+=2) {
addToList(-chg[ic],-ix,1000001+ix);
addToList(chg[ic],ix,-(1000001+ix));
}
}
}
// charged leptons
if(!_mixC || _mixC->size().first==1) {
for(unsigned int ic = 0; ic < chg.size(); ++ic) {
for(long ix = 12; ix < 17; ix+=2) {
addToList(-chg[ic], ix,-( 999999+ix));
addToList(-chg[ic], ix,-(1999999+ix));
addToList( chg[ic],-ix, ( 999999+ix));
addToList( chg[ic],-ix, (1999999+ix));
}
}
}
}
FFSVertex::doinit();
// various couplings and parameters
mw_ = getParticleData(ParticleID::Wplus)->mass();
_sw = sqrt(sin2ThetaW());
double tb = model_->tanBeta();
_cw = sqrt(1. - sqr(_sw));
_sb = tb/sqrt(1 + sqr(tb));
_cb = sqrt(1 - sqr(_sb));
vector<Energy> vnu = model_->sneutrinoVEVs();
double g = electroMagneticCoupling(sqr(mw_))/_sw;
Energy v = 2.*mw_/g;
vd_ = sqrt((sqr(v)-sqr(vnu[0])-sqr(vnu[1])-sqr(vnu[2]))/
(1.+sqr(tb)));
vu_ = vd_*tb;
// couplings of the neutral scalar Higgs to charginos
Energy me = model_->mass(sqr(mw_),getParticleData(ParticleID::eminus ));
Energy mmu = model_->mass(sqr(mw_),getParticleData(ParticleID::muminus ));
Energy mtau = model_->mass(sqr(mw_),getParticleData(ParticleID::tauminus));
double h_E[3] = {sqrt(2.)*me/vd_/g,sqrt(2.)*mmu /vd_/g,sqrt(2.)*mtau/vd_/g};
for(unsigned int ih=0;ih<_mixH->size().first;++ih ) {
OCCHL_.push_back(vector<vector<Complex> >
(_umix->size().first,vector<Complex>(_umix->size().first,0.)));
for(unsigned int i=0;i<_umix->size().first;++i) {
for(unsigned int j=0;j<_umix->size().first;++j) {
OCCHL_[ih][i][j] = -sqrt(0.5)*
( (*_mixH)(ih,0)*(*_vmix)(i,0)*(*_umix)(j,1) +
(*_mixH)(ih,1)*(*_vmix)(i,1)*(*_umix)(j,0));
for(unsigned int k=2;k<_umix->size().first;++k) {
OCCHL_[ih][i][j] -= sqrt(0.5)*(+(*_mixH)(ih,k)*(*_vmix)(i,0)*(*_umix)(j,k)
+h_E[k-2]*(*_umix)(j,k)*(*_vmix)(i,k)*(*_mixH)(ih,0)
-h_E[k-2]*(*_umix)(j,1)*(*_vmix)(i,k)*(*_mixH)(ih,k));
}
}
}
}
// couplings of the neutral scalar Higgs to neutralinos
double tw = _sw/_cw;
for(unsigned int ih=0;ih<_mixH->size().first;++ih) {
ONNHL_.push_back(vector<vector<Complex> >
(_nmix->size().first,vector<Complex>(_nmix->size().first,0.)));
for(unsigned int i=0;i<_nmix->size().first;++i) {
for(unsigned int j=0;j<_nmix->size().first;++j) {
ONNHL_[ih][i][j] =0.;
for(unsigned int in=2;in<_nmix->size().first;++in) {
double sign = in!=3 ? 1. : -1.;
ONNHL_[ih][i][j] += 0.5*sign*(*_mixH)(ih,in-2)*
( + (tw*(*_nmix)(i,0) - (*_nmix)(i,1) )*(*_nmix)(j,in)
+ (tw*(*_nmix)(j,0) - (*_nmix)(j,1) )*(*_nmix)(i,in) );
}
}
}
}
// couplings of the neutral pseudoscalar Higgs to neutralinos
for(unsigned int ih=0;ih<_mixP->size().first;++ih) {
ONNAL_.push_back(vector<vector<Complex> >
(_nmix->size().first,vector<Complex>(_nmix->size().first,0.)));
for(unsigned int i=0;i<_nmix->size().first;++i) {
for(unsigned int j=0;j<_nmix->size().first;++j) {
ONNAL_[ih][i][j] =0.;
for(unsigned int in=2;in<_nmix->size().first;++in) {
double sign = in!=3 ? 1. : -1.;
ONNAL_[ih][i][j] += -0.5*sign*(*_mixP)(ih,in-2)*
( + (tw*(*_nmix)(i,0) - (*_nmix)(i,1) )*(*_nmix)(j,in)
+ (tw*(*_nmix)(j,0) - (*_nmix)(j,1) )*(*_nmix)(i,in) );
}
}
}
}
// couplings of the neutral pseudoscalar higgs to charginos
for(unsigned int ih=0;ih<_mixP->size().first;++ih) {
OCCAL_.push_back(vector<vector<Complex> >
(_umix->size().first,vector<Complex>(_umix->size().first,0.)));
for(unsigned int i=0;i<_umix->size().first;++i) {
for(unsigned int j=0;j<_umix->size().first;++j) {
OCCAL_[ih][i][j] =
(*_mixP)(ih,0)*(*_vmix)(i,0)*(*_umix)(j,1)+
(*_mixP)(ih,1)*(*_vmix)(i,1)*(*_umix)(j,0);
for(unsigned int k=2;k<_umix->size().first;++k) {
OCCAL_[ih][i][j] += (*_mixP)(ih,k)*(*_vmix)(i,0)*(*_umix)(j,k)
-h_E[k-2]*(*_umix)(j,k)*(*_vmix)(i,k)*(*_mixP)(ih,0)
+h_E[k-2]*(*_umix)(j,1)*(*_vmix)(i,k)*(*_mixP)(ih,k);
}
OCCAL_[ih][i][j] *= sqrt(0.5);
}
}
}
// couplings for the charged higgs
for(unsigned int ih=0;ih<_mixC->size().first;++ih) {
OCNSL_.push_back(vector<vector<Complex> >
(_nmix->size().first,vector<Complex>(_umix->size().first,0.)));
OCNSR_.push_back(vector<vector<Complex> >
(_nmix->size().first,vector<Complex>(_umix->size().first,0.)));
for(unsigned int i = 0; i < _nmix->size().first; ++i) {
for(unsigned int j=0;j<_umix->size().first;++j) {
OCNSL_[ih][i][j] = (*_mixC)(ih,1)*conj((*_nmix)(i, 3)*(*_vmix)(j,0)
+((*_nmix)(i,1) + (*_nmix)(i,0)*tw)*(*_vmix)(j,1)/sqrt(2));
OCNSR_[ih][i][j] = (*_mixC)(ih,0)* ((*_nmix)(i, 2)*(*_umix)(j,0)
-((*_nmix)(i,1) + (*_nmix)(i,0)*tw)*(*_umix)(j,1)/sqrt(2));
for(unsigned int k=2;k<_umix->size().first;++k) {
OCNSL_[ih][i][j] += -h_E[k-2]*(*_mixC)(ih,0)*conj((*_nmix)(i,2+k)*(*_vmix)(j,k))
+(*_mixC)(ih,k )*h_E[k-2]*conj((*_nmix)(i, 2)*(*_vmix)(j,k))
+(*_mixC)(ih,k+3)*tw*sqrt(2.)*conj((*_nmix)(i,0)*(*_vmix)(j,k));
OCNSR_[ih][i][j] += (*_mixC)(ih,k)*((*_nmix)(i,2+k)*(*_umix)(j,0)
-((*_nmix)(i,1) + (*_nmix)(i,0)*tw)*(*_umix)(j,k)/sqrt(2))
-(*_mixC)(ih,k+3)*h_E[k-2]*((*_nmix)(i,k+2)*(*_umix)(j,1)-(*_nmix)(i,2)*(*_umix)(j,k));
}
}
}
}
}
void RPVFFSVertex::persistentOutput(PersistentOStream & os) const {
os << interactions_ << _stop << _sbot << _stau << _umix << _vmix
<< _nmix << _mixH << _mixP << _mixC << ounit(mw_,GeV) << yukawa_
<< model_ << _sw << _cw << _sb << _cb << ounit(vd_,GeV) << ounit(vu_,GeV)
<< OCCHL_ << ONNHL_ << ONNAL_ << OCCAL_ << OCNSL_ << OCNSR_;
}
void RPVFFSVertex::persistentInput(PersistentIStream & is, int) {
is >> interactions_ >> _stop >> _sbot >> _stau >> _umix >> _vmix
>> _nmix >> _mixH >> _mixP >> _mixC >> iunit(mw_,GeV) >> yukawa_
>> model_ >> _sw >> _cw >> _sb >> _cb >> iunit(vd_,GeV) >> iunit(vu_,GeV)
>> OCCHL_ >> ONNHL_ >> ONNAL_ >> OCCAL_ >> OCNSL_ >> OCNSR_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RPVFFSVertex,Helicity::FFSVertex>
describeHerwigRPVFFSVertex("Herwig::RPVFFSVertex", "HwSusy.so HwRPV.so");
void RPVFFSVertex::Init() {
static ClassDocumentation<RPVFFSVertex> documentation
("The RPVFFSVertex class implements all the couplings of fermion-antiferion to scalars"
" in R-Parity violating models, including sfermion fermion gaugino, SM ferimon antiferimon Higgs "
"and gaugino-gaugino Higgs.");
static Switch<RPVFFSVertex,unsigned int> interfaceInteractions
("Interactions",
"Whice interactions to include",
&RPVFFSVertex::interactions_, 0, false, false);
static SwitchOption interfaceInteractionsAll
(interfaceInteractions,
"All",
"Include all the interactions",
0);
static SwitchOption interfaceInteractionsHiggsSMFermions
(interfaceInteractions,
"HiggsSMFermions",
"Interactions of Higgs with SM fermions",
1);
static SwitchOption interfaceInteractionsHiggsGaugino
(interfaceInteractions,
"HiggsGaugino",
"Interactions of the Higgs with the gauginos",
2);
static SwitchOption interfaceInteractionsNeutralinoSfermion
(interfaceInteractions,
"NeutralinoSfermion",
"Include the neutralino sfermion interactions",
3);
static SwitchOption interfaceInteractionsCharginoSfermions
(interfaceInteractions,
"CharginoSfermions",
"Include the chargino sfermion interactions",
4);
static Switch<RPVFFSVertex,bool> interfaceYukawa
("Yukawa",
"Whether or not to include the Yukawa type couplings in neutralino/chargino interactions",
&RPVFFSVertex::yukawa_, true, false, false);
static SwitchOption interfaceYukawaYes
(interfaceYukawa,
"Yes",
"Include the terms",
true);
static SwitchOption interfaceYukawaNo
(interfaceYukawa,
"No",
"Don't include them",
false);
}
void RPVFFSVertex::neutralinoSfermionCoupling(Energy2 q2, tcPDPtr fermion,
tcPDPtr gaugino, tcPDPtr sfermion) {
long ism(abs(fermion->id())),ig(abs(gaugino->id())),isc(sfermion->id());
if( ig != _id1last || ism != _id2last || isc != _id3last ) {
_id1last = ig;
_id2last = ism;
_id3last = isc;
// sfermion mass eigenstate
unsigned int alpha(abs(isc)/1000000 - 1);
// neutralino state
unsigned int nl = neutralinoIndex(ig);
assert(nl<=6);
// common primed neutralino matrices
Complex n2prime = (*_nmix)(nl,1)*_cw - (*_nmix)(nl,0)*_sw;
//handle neutrinos first
if( ism == 12 || ism == 14 || ism == 16 ) {
_leftlast = Complex(0., 0.);
_rightlast = -sqrt(0.5)*n2prime/_cw;
}
else {
Complex n1prime = (*_nmix)(nl,0)*_cw + (*_nmix)(nl,1)*_sw;
tcPDPtr smf = getParticleData(ism);
double qf = smf->charge()/eplus;
Complex bracketl = qf*_sw*( conj(n1prime) - _sw*conj(n2prime)/_cw );
double y = yukawa_ ? double(model_->mass(q2, smf)/2./mw_) : 0.;
double lambda(0.);
//neutralino mixing element
Complex nlf(0.);
if( ism % 2 == 0 ) {
y /= _sb;
lambda = -0.5 + qf*sqr(_sw);
nlf = (*_nmix)(nl,3);
}
else {
y /= _cb;
lambda = 0.5 + qf*sqr(_sw);
nlf = (*_nmix)(nl,2);
}
Complex bracketr = _sw*qf*n1prime - n2prime*lambda/_cw;
//heavy quarks/sleptons
if( ism == 5 || ism == 6 || ism == 15 ) {
Complex ma1(0.), ma2(0.);
if( ism == 5 ) {
ma1 = (*_sbot)(alpha,0);
ma2 = (*_sbot)(alpha,1);
}
else if( ism == 6 ) {
ma1 = (*_stop)(alpha,0);
ma2 = (*_stop)(alpha,1);
}
else {
ma1 = (*_stau)(alpha,0);
ma2 = (*_stau)(alpha,1);
}
_leftlast = y*conj(nlf)*ma1 - ma2*bracketl;
_rightlast = y*nlf*ma2 + ma1*bracketr;
}
else {
if( alpha == 0 ) {
_leftlast = y*conj(nlf);
_rightlast = bracketr;
}
else {
_leftlast = -bracketl;
_rightlast = y*nlf;
}
}
_leftlast *= -sqrt(2.);
_rightlast *= -sqrt(2.);
}
}
//determine the helicity order of the vertex
if( fermion->id() < 0 ) {
left (conj(_rightlast));
right(conj( _leftlast));
}
else {
left ( _leftlast);
right(_rightlast);
}
norm(_couplast);
}
void RPVFFSVertex::charginoSfermionCoupling(Energy2 q2, tcPDPtr fermion,
tcPDPtr gaugino, tcPDPtr sfermion) {
long ism(abs(fermion->id())),ig(abs(gaugino->id())),isc(sfermion->id());
if( ig != _id1last || ism != _id2last || isc != _id3last ) {
_id1last = ig;
_id2last = ism;
_id3last = isc;
// sfermion mass eigenstate
unsigned int alpha(abs(isc)/1000000 - 1);
// get the type of chargino
unsigned int ch = charginoIndex(ig);
assert(ch<=4);
// various mixing matrix elements
Complex ul1 = (*_umix)(ch,0), ul2 = (*_umix)(ch,1);
Complex vl1 = (*_vmix)(ch,0), vl2 = (*_vmix)(ch,1);
// lepton/slepton
if( ism >= 11 && ism <= 16 ) {
long lept = ( ism % 2 == 0 ) ? ism - 1 : ism;
double y = yukawa_ ?
double(model_->mass(q2, getParticleData(lept))/mw_/sqrt(2)/_cb) : 0.;
if( ism == 12 || ism == 14 ) {
_leftlast = 0.;
_rightlast = alpha == 0 ? - ul1 : y*ul2;
}
else if( ism == 16 ) {
_leftlast = 0.;
_rightlast = -ul1*(*_stau)(alpha, 0) + y*(*_stau)(alpha,1)*ul2;
}
else if( ism == 11 || ism == 13 || ism == 15 ) {
_leftlast = y*conj(ul2);
_rightlast = -vl1;
}
}
// squark/quark
else {
double yd(0.), yu(0.);
if(yukawa_) {
if( ism % 2 == 0) {
yu = model_->mass(q2, getParticleData(ism))/mw_/sqrt(2)/_sb;
yd = model_->mass(q2, getParticleData(ism - 1))/mw_/sqrt(2)/_cb;
}
else {
yu = model_->mass(q2, getParticleData(ism + 1))/mw_/sqrt(2)/_sb;
yd = model_->mass(q2, getParticleData(ism))/mw_/sqrt(2)/_cb;
}
}
//heavy quarks
if( ism == 5 ) {
_leftlast = yd*conj(ul2)*(*_stop)(alpha,0);
_rightlast = -vl1*(*_stop)(alpha, 0) + yu*vl2*(*_stop)(alpha,1);
}
else if( ism == 6 ) {
_leftlast = yu*conj(vl2)*(*_sbot)(alpha,0);
_rightlast = -ul1*(*_sbot)(alpha, 0) + yd*ul2*(*_sbot)(alpha,1);
}
else {
if( alpha == 0 ) {
_leftlast = (ism % 2 == 0) ? yu*conj(vl2) : yd*conj(ul2);
_rightlast = (ism % 2 == 0) ? -ul1 : -vl1;
}
else {
_leftlast = 0.;
_rightlast = (ism % 2 == 0) ? yd*ul2 : yu*vl2;
}
}
}
}
//determine the helicity order of the vertex
if( fermion->id() < 0 ) {
left (conj(_rightlast));
right(conj( _leftlast));
}
else {
left ( _leftlast);
right(_rightlast);
}
norm(_couplast);
}
void RPVFFSVertex::higgsFermionCoupling(Energy2 q2, tcPDPtr f1,
tcPDPtr f2, tcPDPtr higgs) {
long f1ID(f1->id()), f2ID(f2->id()), isc(higgs->id());
// running fermion masses
if( q2 != _q2last || _id1last != f1ID) {
_massLast.first = model_->mass(q2,f1);
_id1last = f1ID;
}
if( q2 != _q2last || _id2last != f2ID) {
_massLast.second = model_->mass(q2,f2);
_id2last = f2ID;
}
if( q2 != _q2last) _id3last = isc;
Complex fact(0.);
// scalar neutral Higgs
if(isc == ParticleID::h0 || isc == ParticleID::H0 ||
isc == ParticleID::SUSY_nu_eL || isc == ParticleID::SUSY_nu_muL ||
isc == ParticleID::SUSY_nu_tauL ) {
unsigned int ih = isc < 1000000 ? (isc-25)/10 : (isc-1000008)/2;
unsigned int id = abs(f1ID);
fact = -_massLast.first*
((id%2==0) ? (*_mixH)(ih,1)/vu_ : (*_mixH)(ih,0)/vd_);
left (1.);
right(1.);
}
// pseudoscalar neutral Higgs
else if(isc == ParticleID::A0 || isc == 1000017 || isc == 1000018 ||
isc == 1000019 ) {
unsigned int ih = isc < 1000000 ? 0 : (isc-1000016);
unsigned int id = abs(f1ID);
if(_mixP) {
fact = -Complex(0., 1.)*_massLast.first*
( (id%2==0) ? (*_mixP)(ih,1)/vu_ : (*_mixP)(ih,0)/vd_);
}
else {
fact = -Complex(0., 1.)*_massLast.first*
( (id%2==0) ? _cb/vu_ : _sb/vd_);
}
left ( 1.);
right(-1.);
}
// charged higgs
else {
if(!_mixC) {
if( abs(f1ID) % 2 == 0 ) {
_leftlast = _massLast.first /vu_*_cb;
_rightlast = _massLast.second/vd_*_sb;
}
else {
_leftlast = _massLast.second/vu_*_cb;
_rightlast = _massLast.first /vd_*_sb;
}
}
else {
unsigned int ih;
if(abs(isc)==ParticleID::Hplus) {
ih = 0;
}
else {
isc *= -1;
ih = abs(isc)<2000000 ? (abs(isc)-1000009)/2 : (abs(isc)-2000003)/2;
}
if( abs(f1ID) % 2 == 0 ) {
_leftlast = _massLast.first /vu_*(*_mixC)(ih,1);
_rightlast = _massLast.second/vd_*(*_mixC)(ih,0);
}
else {
_leftlast = _massLast.second/vu_*(*_mixC)(ih,1);
_rightlast = _massLast.first /vd_*(*_mixC)(ih,0);
}
}
if( isc > 0 ) swap(_leftlast,_rightlast);
fact = sqrt(2.);
left ( _leftlast);
right(_rightlast);
}
norm(fact);
}
void RPVFFSVertex::higgsGauginoCoupling(Energy2, tcPDPtr f1,
tcPDPtr f2, tcPDPtr higgs) {
long f1ID(f1->id()), f2ID(f2->id()), isc(higgs->id());
if( isc == _id3last && f1ID == _id1last && f2ID == _id2last ) {
left ( _leftlast);
right(_rightlast);
}
else {
_id1last = f1ID;
_id2last = f2ID;
_id3last = isc;
// scalar neutral Higgs
if(isc == ParticleID::h0 || isc == ParticleID::H0 ||
isc == ParticleID::SUSY_nu_eL || isc == ParticleID::SUSY_nu_muL ||
isc == ParticleID::SUSY_nu_tauL ) {
unsigned int ih = isc < 1000000 ? (isc-25)/10 : (isc-1000008)/2;
// charginos
if(f1->charged()) {
unsigned int ei = charginoIndex(f1ID);
unsigned int ej = charginoIndex(f2ID);
if (ei< 2&&f1ID>0) swap(ei,ej);
else if(ei>=2&&f1ID<0) swap(ei,ej);
_rightlast = conj(OCCHL_[ih][ej][ei]);
_leftlast = OCCHL_[ih][ei][ej] ;
}
// neutralinos
else {
unsigned int ei = neutralinoIndex(f1ID);
unsigned int ej = neutralinoIndex(f2ID);
_leftlast = conj(ONNHL_[ih][ej][ei]);
_rightlast = ONNHL_[ih][ei][ej] ;
}
}
// pseudoscalar neutral Higgs
else if(isc == ParticleID::A0 || isc == 1000017 || isc == 1000018 ||
isc == 1000019 ) {
unsigned int ih = isc < 1000000 ? 0 : (isc-1000016);
// charginos
if(f1->charged()) {
unsigned int ei = charginoIndex(f1ID);
unsigned int ej = charginoIndex(f2ID);
if (ei< 2&&f1ID>0) swap(ei,ej);
else if(ei>=2&&f1ID<0) swap(ei,ej);
_rightlast = -Complex(0.,1.)*conj(OCCAL_[ih][ej][ei]);
_leftlast = Complex(0.,1.)* OCCAL_[ih][ei][ej] ;
}
// neutralinos
else {
unsigned int ei = neutralinoIndex(f1ID);
unsigned int ej = neutralinoIndex(f2ID);
_leftlast = Complex(0.,1.)*conj(ONNAL_[ih][ej][ei]);
_rightlast = -Complex(0.,1.)* ONNAL_[ih][ei][ej] ;
}
}
// charged higgs
else {
unsigned int ih = abs(isc) < 1000000 ? 0 :
(abs(isc) < 2000000 ? (abs(isc)-1000009)/2 : (abs(isc)-2000003)/2);
long chg(f2ID), neu(f1ID);
if(f1->charged()) swap(chg, neu);
unsigned int ei = neutralinoIndex(neu);
unsigned int ej = charginoIndex(chg);
_leftlast = -OCNSL_[ih][ei][ej];
_rightlast = -OCNSR_[ih][ei][ej];
bool chargedSwap = abs(isc)<1000000 ? isc<0 : isc>0;
if( chargedSwap ) {
Complex tmp = _leftlast;
_leftlast = conj(_rightlast);
_rightlast = conj(tmp);
}
}
left ( _leftlast);
right(_rightlast);
}
norm(_couplast);
}
void RPVFFSVertex::setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
// overall normalisation
if(q2!=_q2last || _couplast==0.) {
_couplast = weakCoupling(q2);
_q2last=q2;
}
long f1ID(part1->id()), f2ID(part2->id()), isc(abs(part3->id()));
// squark quark
if(part3->coloured()) {
tcPDPtr smfermion = part1, gaugino = part2;
if(gaugino->coloured()) swap(smfermion,gaugino);
if(gaugino->charged())
charginoSfermionCoupling(q2,smfermion,gaugino,part3);
else
neutralinoSfermionCoupling(q2,smfermion,gaugino,part3);
}
// slepton/lepton without mixing
else if((( isc >= 1000011 && isc <= 1000016) ||
( isc >= 2000011 && isc <= 2000016)) &&
(!_mixC || _mixC->size().first<=1 ||
!_mixP || _mixP->size().first<=1 )) {
tcPDPtr smfermion = part1, gaugino = part2;
if(abs(gaugino->id())<1000000) swap(smfermion,gaugino);
if(gaugino->charged())
charginoSfermionCoupling(q2,smfermion,gaugino,part3);
else
neutralinoSfermionCoupling(q2,smfermion,gaugino,part3);
}
// SM quarks and Higgs
else if((abs(f1ID) <= 6 && abs(f2ID) <= 6) ||
((abs(f1ID) >= 11 && abs(f1ID) <= 16) &&
(abs(f2ID) >= 11 && abs(f2ID) <= 16) &&
_umix->size().first==2) ) {
higgsFermionCoupling(q2,part1,part2,part3);
}
// gauginos and the Higgs (general case for sleptons)
else {
higgsGauginoCoupling(q2,part1,part2,part3);
}
}
diff --git a/Models/Susy/RPV/RPVFFWVertex.cc b/Models/Susy/RPV/RPVFFWVertex.cc
--- a/Models/Susy/RPV/RPVFFWVertex.cc
+++ b/Models/Susy/RPV/RPVFFWVertex.cc
@@ -1,267 +1,268 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RPVFFWVertex class.
//
#include "RPVFFWVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "RPVhelper.h"
using namespace Herwig;
RPVFFWVertex::RPVFFWVertex() : _diagonal(false), _ckm(3,vector<Complex>(3,0.0)),
_sw(0.), _couplast(0.), _q2last(ZERO),
_id1last(0), _id2last(0), _leftlast(0.),
_rightlast(0.), _interactions(0) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
IBPtr RPVFFWVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVFFWVertex::fullclone() const {
return new_ptr(*this);
}
void RPVFFWVertex::doinit() {
// SUSY mixing matrices
tSusyBasePtr model = dynamic_ptr_cast<SusyBasePtr>(generator()->standardModel());
if(!model)
throw InitException() << "RPVFFWVertex::doinit() - The model pointer is null!"
<< Exception::abortnow;
_theN = model->neutralinoMix();
_theU = model->charginoUMix();
_theV = model->charginoVMix();
if(!_theN || !_theU || ! _theV)
throw InitException() << "RPVFFWVertex::doinit() - "
<< "A mixing matrix pointer is null."
<< " N: " << _theN << " U: " << _theU << " V: "
<< _theV << Exception::abortnow;
// SM interactions
if(_interactions==0 || _interactions==1) {
// particles for outgoing W-
// quarks
for(int ix=1;ix<6;ix+=2) {
for(int iy=2;iy<7;iy+=2) {
bool isOff = iy/2 != (ix+1)/2;
if ( isOff && _diagonal )
continue;
addToList(-ix, iy, -24);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
int inu = model->majoranaNeutrinos() ? (ix+23)/2 : ix+1;
addToList(-ix, inu, -24);
}
// particles for outgoing W+
// quarks
for(int ix=2;ix<7;ix+=2) {
for(int iy=1;iy<6;iy+=2) {
bool isOff = ix/2 != (iy+1)/2;
if ( isOff && _diagonal )
continue;
addToList(-ix, iy, 24);
}
}
// leptons
for(int ix=11;ix<17;ix+=2) {
int inu = model->majoranaNeutrinos() ? (ix+23)/2 : -ix-1;
addToList(inu, ix, 24);
}
}
// neutralino and chargino
if(_interactions==0 || _interactions==2) {
vector<long> neu(4);
neu[0] = 1000022; neu[1] = 1000023;
neu[2] = 1000025; neu[3] = 1000035;
if(_theN->size().first==7) {
if(model->majoranaNeutrinos()) {
neu.push_back(17);
neu.push_back(18);
neu.push_back(19);
}
else {
neu.push_back(12);
neu.push_back(14);
neu.push_back(16);
}
}
vector<long> cha(2);
cha[0] = 1000024; cha[1] = 1000037;
if(_theV->size().first==5) {
cha.push_back(-11);
cha.push_back(-13);
cha.push_back(-15);
}
// sign == -1 outgoing W-, sign == +1 outgoing W+
for(int sign = -1; sign < 2; sign += 2) {
for(unsigned int ine = 0; ine < neu.size(); ++ine) {
for(unsigned int ic = 0; ic < cha.size(); ++ic ) {
if(ic>1&&ine>3&&ic==ine-2) continue;
addToList(-sign*cha[ic], neu[ine], sign*24);
}
}
}
}
Helicity::FFVVertex::doinit();
// CKM matric
if ( !_diagonal ) {
Ptr<CKMBase>::transient_pointer CKM = model->CKM();
// cast the CKM object to the HERWIG one
ThePEG::Ptr<Herwig::StandardCKM>::transient_const_pointer
hwCKM = ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardCKM>::
transient_const_pointer>(CKM);
if(hwCKM) {
vector< vector<Complex > > CKM;
CKM = hwCKM->getUnsquaredMatrix(generator()->standardModel()->families());
for(unsigned int ix=0;ix<3;++ix) {
for(unsigned int iy=0;iy<3;++iy) {
_ckm[ix][iy]=CKM[ix][iy];
}
}
}
else {
throw Exception() << "Must have access to the Herwig::StandardCKM object"
<< "for the CKM matrix in RPVFFWVertex::doinit()"
<< Exception::runerror;
}
}
_sw = sqrt(sin2ThetaW());
}
void RPVFFWVertex::persistentOutput(PersistentOStream & os) const {
os << _sw << _theN << _theU << _theV << _diagonal << _ckm << _interactions;
}
void RPVFFWVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw >> _theN >> _theU >> _theV >> _diagonal >> _ckm >> _interactions;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RPVFFWVertex,Helicity::FFVVertex>
describeHerwigRPVFFWVertex("Herwig::RPVFFWVertex", "HwSusy.so HwRPV.so");
void RPVFFWVertex::Init() {
static ClassDocumentation<RPVFFWVertex> documentation
("The couplings of the fermions to the W boson in the RPV model"
" with bilinear R-parity violation");
static Switch<RPVFFWVertex,unsigned int> interfaceInteractions
("Interactions",
"Which interactions to include",
&RPVFFWVertex::_interactions, 0, false, false);
static SwitchOption interfaceInteractionsAll
(interfaceInteractions,
"All",
"Include all the interactions",
0);
static SwitchOption interfaceInteractionsSM
(interfaceInteractions,
"SM",
"Only include the MS terms",
1);
static SwitchOption interfaceInteractionsSUSY
(interfaceInteractions,
"SUSY",
"Include the neutralino/chargino terms",
2);
static Switch<RPVFFWVertex,bool> interfaceDiagonal
("Diagonal",
"Use a diagonal CKM matrix (ignoring the CKM object of the StandardModel).",
&RPVFFWVertex::_diagonal, false, false, false);
static SwitchOption interfaceDiagonalYes
(interfaceDiagonal,
"Yes",
"Use a diagonal CKM matrix.",
true);
static SwitchOption interfaceDiagonalNo
(interfaceDiagonal,
"No",
"Use the CKM object as used by the StandardModel.",
false);
}
void RPVFFWVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
assert(abs(part3->id()) == ParticleID::Wplus);
// normalization
// first the overall normalisation
if(q2 != _q2last||_couplast==0.) {
_couplast = weakCoupling(q2);
_q2last=q2;
}
norm(_couplast);
// left and right couplings for quarks
if(abs(part1->id()) <= 6) {
int iferm=abs(part1->id());
int ianti=abs(part2->id());
if(iferm%2!=0) swap(iferm,ianti);
iferm = iferm/2;
ianti = (ianti+1)/2;
assert( iferm>=1 && iferm<=3 && ianti>=1 && ianti<=3);
left(-sqrt(0.5)*_ckm[iferm-1][ianti-1]);
right(0.);
}
else {
long neu, cha;
if(part1->charged()) {
cha = part1->id();
neu = part2->id();
}
else {
cha = part2->id();
neu = part1->id();
}
if(_theV->size().first==2&&abs(neu)<=16) {
left(-sqrt(0.5));
right(0.);
}
else {
if(cha != _id1last || neu != _id2last) {
_id1last = cha;
_id2last = neu;
unsigned int eigc = RPV_helper::charginoIndex(cha);
unsigned int eign = RPV_helper::neutralinoIndex(neu);
_leftlast = (*_theN)(eign, 1)*conj((*_theV)(eigc, 0)) -
( (*_theN)(eign, 3)*conj((*_theV)(eigc, 1))/sqrt(2));
_rightlast = conj((*_theN)(eign, 1))*(*_theU)(eigc, 0) +
( conj((*_theN)(eign, 2))*(*_theU)(eigc, 1)/sqrt(2));
if(_theV->size().first==5) {
for(unsigned int k=0;k<3;++k)
_rightlast += ( conj((*_theN)(eign, 4+k))*(*_theU)(eigc, 2+k)/sqrt(2));
}
}
Complex ltemp = _leftlast;
Complex rtemp = _rightlast;
bool chapart = abs(cha)>1000000 ? cha>0 : cha<0;
// conjugate if +ve chargino
if(chapart) {
ltemp = conj(ltemp);
rtemp = conj(rtemp);
}
if((part1->id()==cha&&chapart)||(part2->id()==cha&&!chapart)) {
Complex temp = ltemp;
ltemp = -rtemp;
rtemp = -temp;
}
left (ltemp);
right(rtemp);
}
}
}
diff --git a/Models/Susy/RPV/RPVFFZVertex.cc b/Models/Susy/RPV/RPVFFZVertex.cc
--- a/Models/Susy/RPV/RPVFFZVertex.cc
+++ b/Models/Susy/RPV/RPVFFZVertex.cc
@@ -1,295 +1,296 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RPVFFZVertex class.
//
#include "RPVFFZVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "RPVhelper.h"
using namespace Herwig;
RPVFFZVertex::RPVFFZVertex() : _sw(0.), _cw(0.), _id1last(0),
_id2last(0), _q2last(), _couplast(0.),
_leftlast(0.), _rightlast(0.),
_gl(17,0.0), _gr(17,0.0), _gblast(0),
_interactions(0) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
IBPtr RPVFFZVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVFFZVertex::fullclone() const {
return new_ptr(*this);
}
void RPVFFZVertex::persistentOutput(PersistentOStream & os) const {
os << _sw << _cw << _theN << _theU << _theV
<< _gl << _gr << _interactions;
}
void RPVFFZVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw >> _cw >> _theN >> _theU >> _theV
>> _gl >> _gr >> _interactions;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RPVFFZVertex,Helicity::FFVVertex>
describeHerwigRPVFFZVertex("Herwig::RPVFFZVertex", "HwSusy.so HwRPV.so");
void RPVFFZVertex::Init() {
static ClassDocumentation<RPVFFZVertex> documentation
("The RPVFFZVertex class implements trhe coupling of the Z to all"
" fermion-antifermion pairs in models with bilinear RPV.");
static Switch<RPVFFZVertex,unsigned int> interfaceInteractions
("Interactions",
"Which interactions to include",
&RPVFFZVertex::_interactions, 0, false, false);
static SwitchOption interfaceInteractionsAll
(interfaceInteractions,
"All",
"Include all the interactions",
0);
static SwitchOption interfaceInteractionsSM
(interfaceInteractions,
"SM",
"Only include what would have been the interactions with the SM"
" fermions in the absence of mixing",
1);
static SwitchOption interfaceInteractionsNeutralino
(interfaceInteractions,
"Neutralino",
"Only include what would have been the interactions with the "
"neutralinos in the absence of mixing",
2);
static SwitchOption interfaceInteractionsChargino
(interfaceInteractions,
"Chargino",
"Only include what would have been the interactions with the "
"charginos in the absence of mixing",
3);
}
void RPVFFZVertex::doinit() {
// extract the mixing matrices
tSusyBasePtr model = dynamic_ptr_cast<SusyBasePtr>(generator()->standardModel());
if(!model) throw InitException() << "RPVFFZVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
_theN = model->neutralinoMix();
_theU = model->charginoUMix();
_theV = model->charginoVMix();
if( !_theN || !_theU || !_theV )
throw InitException() << "RPVFFZVertex::doinit - "
<< "A mixing matrix pointer is null. U: "
<< _theU << " V: " << _theV << " N: " << _theN
<< Exception::abortnow;
// Standard Model fermions
if(_interactions==0||_interactions==1) {
// PDG codes for the particles
// the quarks
for(int ix=1;ix<7;++ix) {
addToList(-ix, ix, 23);
}
// the leptons
for(int ix=11;ix<17;ix+=2) {
addToList(-ix, ix, 23);
}
for(int ix=12;ix<17;ix+=2) {
if(_theN->size().first==7) {
long inu = (ix-12)/2+17;
addToList( inu, inu, 23);
}
else
addToList(-ix, ix, 23);
}
}
// neutralinos
if(_interactions==0||_interactions==2) {
vector<long> neu(4);
neu[0] = 1000022; neu[1] = 1000023;
neu[2] = 1000025; neu[3] = 1000035;
if(_theN->size().first==7) {
if(model->majoranaNeutrinos()) {
neu.push_back(17);
neu.push_back(18);
neu.push_back(19);
}
else {
neu.push_back(12);
neu.push_back(14);
neu.push_back(16);
}
}
for(unsigned int i = 0; i < neu.size(); ++i) {
for(unsigned int j = 0; j < neu.size(); ++j) {
if(!(i>3&&i==j)) addToList(neu[i], neu[j], 23);
}
}
}
// charginos
if(_interactions==0||_interactions==3) {
addToList(-1000024, 1000024, 22);
addToList(-1000037, 1000037, 22);
vector<long> cha(2);
cha[0] = 1000024; cha[1] = 1000037;
if(_theV->size().first==5) {
cha.push_back(-11);
cha.push_back(-13);
cha.push_back(-15);
}
for(unsigned int i = 0; i < cha.size(); ++i) {
for(unsigned int j = 0; j < cha.size(); ++j) {
if(!(i>1&&i==j)) addToList(-cha[i], cha[j], 23);
}
}
}
Helicity::FFVVertex::doinit();
// weak mixing
double sw2 = sin2ThetaW();
_cw = sqrt(1. - sw2);
_sw = sqrt( sw2 );
// Standard Model couplings
for(int ix=1;ix<4;++ix) {
_gl[2*ix-1] = -0.25*(model->vd() + model->ad() );
_gl[2*ix ] = -0.25*(model->vu() + model->au() );
_gl[2*ix+9 ] = -0.25*(model->ve() + model->ae() );
_gl[2*ix+10] = -0.25*(model->vnu() + model->anu());
_gr[2*ix-1] = -0.25*(model->vd() - model->ad() );
_gr[2*ix ] = -0.25*(model->vu() - model->au() );
_gr[2*ix+9 ] = -0.25*(model->ve() - model->ae() );
_gr[2*ix+10] = -0.25*(model->vnu() - model->anu());
}
}
void RPVFFZVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
// first the overall normalisation
if(q2!=_q2last||_couplast==0.) {
_couplast = electroMagneticCoupling(q2);
_q2last=q2;
}
long iferm1(part1->id()), iferm2(part2->id()), boson(part3->id());
long iferm = abs(iferm1);
// chargino coupling to the photon
if(part3->id()==ParticleID::gamma) {
assert(iferm == abs(iferm2));
_gblast = boson;
_id1last = iferm1;
_id2last = iferm2;
_leftlast = -1.;
_rightlast = -1.;
if(iferm1>0) {
Complex temp = _leftlast;
_leftlast = -_rightlast;
_rightlast = -temp;
}
}
// coupling to the Z
else {
assert(part3->id()==ParticleID::Z0);
// quarks
if(iferm<=6) {
_leftlast = _gl[iferm]/(_sw*_cw);
_rightlast = _gr[iferm]/(_sw*_cw);
}
// charged leptons and charginos
else if(part1->iCharge()!=0) {
if(boson != _gblast || iferm1 != _id1last || iferm2 != _id2last) {
_gblast = boson;
_id1last = iferm1;
_id2last = iferm2;
unsigned int ic1(0);
if(_theV->size().first==2&&iferm<=16) {
_leftlast = -_gr[iferm];
_rightlast = -_gl[iferm];
}
else {
ic1 = RPV_helper::charginoIndex(iferm1);
unsigned int ic2 = RPV_helper::charginoIndex(iferm2);
_leftlast = -(*_theV)(ic1, 0)*conj((*_theV)(ic2, 0)) -
0.5*(*_theV)(ic1, 1)*conj((*_theV)(ic2, 1));
_rightlast = -conj((*_theU)(ic1, 0))*(*_theU)(ic2, 0) -
0.5*conj((*_theU)(ic1, 1))*(*_theU)(ic2, 1);
if(abs(iferm1) == abs(iferm2)) {
_leftlast += sqr(_sw);
_rightlast += sqr(_sw);
}
if(_theV->size().first==5) {
for(unsigned int ix=0;ix<3;++ix) {
_rightlast += -0.5*(*_theU)(ic1, 2+ix)*conj((*_theU)(ic2, 2+ix));
}
}
}
if((ic1<2&&iferm1>0)||(ic1>=2&&iferm1<0)) {
Complex temp = _leftlast;
_leftlast = -_rightlast;
_rightlast = -temp;
}
Complex temp = _leftlast;
_leftlast = -_rightlast;
_rightlast = -temp;
_leftlast /= _sw*_cw;
_rightlast /= _sw*_cw;
}
}
// neutrinos and neutralinos
else {
// case where only 4x4 matrix and neutrino
if(_theN->size().first==4&&iferm<=16) {
assert(iferm==12||iferm==14||iferm==16);
_leftlast = _gl[iferm]/(_sw*_cw);
_rightlast = _gr[iferm]/(_sw*_cw);
}
// neutralino
else {
long ic1 = part2->id();
long ic2 = part1->id();
assert(ic1 == ParticleID::SUSY_chi_10 || ic1 == ParticleID::SUSY_chi_20 ||
ic1 == ParticleID::SUSY_chi_30 || ic1 == ParticleID::SUSY_chi_40 ||
abs(ic1) == 12 || abs(ic1) == 14 || abs(ic1) == 16 ||
abs(ic1) == 17 || abs(ic1) == 18 || abs(ic1) == 19 );
assert(ic2 == ParticleID::SUSY_chi_10 || ic2 == ParticleID::SUSY_chi_20 ||
ic2 == ParticleID::SUSY_chi_30 || ic2 == ParticleID::SUSY_chi_40 ||
abs(ic2) == 12 || abs(ic2) == 14 || abs(ic2) == 16 ||
abs(ic2) == 17 || abs(ic2) == 18 || abs(ic2) == 19 );
if(ic1 != _id1last || ic2 != _id2last) {
_id1last = ic1;
_id2last = ic2;
unsigned int neu1 = RPV_helper::neutralinoIndex(ic1);
unsigned int neu2 = RPV_helper::neutralinoIndex(ic2);
_leftlast = 0.5*( (*_theN)(neu1, 3)*conj((*_theN)(neu2, 3)) -
(*_theN)(neu1, 2)*conj((*_theN)(neu2, 2)) );
if(_theN->size().first>4) {
for(unsigned int k=0;k<3;++k)
_leftlast -= 0.5*(*_theN)(neu1, 4+k)*conj((*_theN)(neu2, 4+k));
}
_rightlast = -conj(_leftlast);
_leftlast /= _sw*_cw;
_rightlast /= _sw*_cw;
}
}
}
}
norm ( _couplast);
left ( _leftlast);
right(_rightlast);
}
diff --git a/Models/Susy/RPV/RPVLLEVertex.cc b/Models/Susy/RPV/RPVLLEVertex.cc
--- a/Models/Susy/RPV/RPVLLEVertex.cc
+++ b/Models/Susy/RPV/RPVLLEVertex.cc
@@ -1,181 +1,182 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RPVLLEVertex class.
//
#include "RPVLLEVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
RPVLLEVertex::RPVLLEVertex() {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr RPVLLEVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVLLEVertex::fullclone() const {
return new_ptr(*this);
}
void RPVLLEVertex::persistentOutput(PersistentOStream & os) const {
os << lambda_ << stau_;
}
void RPVLLEVertex::persistentInput(PersistentIStream & is, int) {
is >> lambda_ >> stau_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<RPVLLEVertex,FFSVertex>
describeHerwigRPVLLEVertex("Herwig::RPVLLEVertex", "HwSusy.so HwRPV.so");
void RPVLLEVertex::Init() {
static ClassDocumentation<RPVLLEVertex> documentation
("The RPVLLEVertex class implements the trilinear LLE"
" coupling in R-parity violating models.");
}
void RPVLLEVertex::doinit() {
RPVPtr rpv = dynamic_ptr_cast<RPVPtr>(generator()->standardModel());
if(!rpv)
throw InitException() << "Must have the RPV model in"
<< " RPVLLEVertex::doinit()"
<< Exception::abortnow;
// get the coupling
lambda_ = rpv->lambdaLLE();
stau_ = rpv->stauMix();
// set the particles in the vertex if coupling non-zero
for( int i=0;i<3;++i) {
for( int j=0; j<3; ++j) {
for( int k=0; k<3; ++k) {
// continue if zero
if(lambda_[i][j][k]==0.) continue;
// particles in the vertex
// sneutrino
addToList( -2*i-11, 2*k+11, -1000012-2*j );
addToList( 2*i+11, -2*k-11, 1000012+2*j );
// left slepton
addToList( -2*i-12, 2*k+11, -1000011-2*j );
addToList( 2*i+12, -2*k-11, +1000011+2*j );
if(j==2) {
addToList( -2*i-12, 2*k+11, -2000011-2*j );
addToList( 2*i+12, -2*k-11, +2000011+2*j );
}
// right slepton
addToList( 2*i+12, 2*j+11, -2000011-2*k );
addToList( -2*i-12, -2*j-11, +2000011+2*k );
if(k==2) {
addToList( 2*i+12, 2*j+11, -1000011-2*k );
addToList( -2*i-12, -2*j-11, +1000011+2*k );
}
}
}
}
FFSVertex::doinit();
}
void RPVLLEVertex::setCoupling(Energy2, tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3) {
int islep = part3->id();
int i(-1),j(-1),k(-1);
Complex mix=1.;
// sneutrino case
if( abs(islep) == ParticleID::SUSY_nu_eL ||
abs(islep) == ParticleID::SUSY_nu_muL ||
abs(islep) == ParticleID::SUSY_nu_tauL) {
j = (abs(islep) - 1000012)/2;
i = (abs(part1->id())-11)/2;
k = (abs(part2->id())-11)/2;
if(part1->id()*islep<0) swap(i,k);
if(islep<0) {
left (1.);
right(0.);
}
else {
left (0.);
right(1.);
}
}
// charged slepton case
else if( abs(islep) == ParticleID::SUSY_e_Lminus ||
abs(islep) == ParticleID::SUSY_mu_Lminus ||
abs(islep) == ParticleID::SUSY_e_Rminus ||
abs(islep) == ParticleID::SUSY_mu_Rminus ||
abs(islep) == ParticleID::SUSY_tau_1minus||
abs(islep) == ParticleID::SUSY_tau_2minus) {
// right charged slepton
if(part1->id()*part2->id()>0) {
if(abs(part1->id())%2==0) {
i = (abs(part1->id())-12)/2;
j = (abs(part2->id())-11)/2;
}
else {
i = (abs(part2->id())-12)/2;
j = (abs(part1->id())-11)/2;
}
if(abs(islep)>2000000) {
k = (abs(islep)-2000011)/2;
if(k==2) mix = (*stau_)(1,1);
}
else {
assert(abs(islep)==ParticleID::SUSY_tau_1minus);
k = 2;
mix = (*stau_)(0,1);
}
if(islep>0) {
left (-1.);
right(0.);
}
else {
left (0.);
right(-1.);
}
}
// left charged
else {
if(abs(part1->id())%2==0) {
i = (abs(part1->id())-12)/2;
k = (abs(part2->id())-11)/2;
}
else {
i = (abs(part2->id())-12)/2;
k = (abs(part1->id())-11)/2;
}
if(abs(islep)<2000000) {
j = (abs(islep)-1000011)/2;
if(j==2) mix = (*stau_)(0,0);
}
else {
assert(abs(islep)==ParticleID::SUSY_tau_2minus);
j = 2;
mix = (*stau_)(1,0);
}
if(islep<0) {
left (-1.);
right(0.);
}
else {
left (0.);
right(-1.);
}
}
}
else
assert(false);
assert( i>=0 && i<=2 && j>=0 && j<=2 && k>=0 && k<=2 );
norm(mix*lambda_[i][j][k]);
}
diff --git a/Models/Susy/RPV/RPVLQDVertex.cc b/Models/Susy/RPV/RPVLQDVertex.cc
--- a/Models/Susy/RPV/RPVLQDVertex.cc
+++ b/Models/Susy/RPV/RPVLQDVertex.cc
@@ -1,281 +1,282 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RPVLQDVertex class.
//
#include "RPVLQDVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
RPVLQDVertex::RPVLQDVertex() {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
IBPtr RPVLQDVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVLQDVertex::fullclone() const {
return new_ptr(*this);
}
void RPVLQDVertex::persistentOutput(PersistentOStream & os) const {
os << lambda_ << stop_ << sbot_ << stau_;
}
void RPVLQDVertex::persistentInput(PersistentIStream & is, int) {
is >> lambda_ >> stop_ >> sbot_ >> stau_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<RPVLQDVertex,FFSVertex>
describeHerwigRPVLQDVertex("Herwig::RPVLQDVertex", "HwSusy.so HwRPV.so");
void RPVLQDVertex::Init() {
static ClassDocumentation<RPVLQDVertex> documentation
("The RPVLQDVertex class implements the trilinear LQD"
" coupling in R-parity violating models.");
}
void RPVLQDVertex::doinit() {
RPVPtr rpv = dynamic_ptr_cast<RPVPtr>(generator()->standardModel());
if(!rpv)
throw InitException() << "Must have the RPV model in"
<< " RPVLQDVertex::doinit()"
<< Exception::abortnow;
// get the coupling
lambda_ = rpv->lambdaLQD();
stop_ = rpv->stopMix();
sbot_ = rpv->sbottomMix();
stau_ = rpv->stauMix();
// set the particles in the vertex if coupling non-zero
for( int i=0;i<3;++i) {
for( int j=0; j<3; ++j) {
for( int k=0; k<3; ++k) {
// continue if zero
if(lambda_[i][j][k]==0.) continue;
// particles in the vertex
// sneutrino
addToList( -2*j-1 , 2*k+1 , -1000012-2*i );
addToList( 2*j+1 , -2*k-1 , 1000012+2*i );
// left slepton
addToList( -2*j-2 , 2*k+1 , -1000011-2*i );
addToList( 2*j+2 , -2*k-1 , +1000011+2*i );
if(i==2) {
addToList( -2*j-2 , 2*k+1 , -2000011-2*i );
addToList( 2*j+2 , -2*k-1 , +2000011+2*i );
}
// up squark
addToList( -2*i-11, 2*k+1 , -1000002-2*j );
addToList( 2*i+11, -2*k-1 , 1000002+2*j );
if(j==2) {
addToList( -2*i-11, 2*k+1 , -2000002-2*j );
addToList( 2*i+11, -2*k-1 , 2000002+2*j );
}
// left down squark
addToList( -2*i-12, 2*k+1 , -1000001-2*j );
addToList( 2*i+12, -2*k-1 , 1000001+2*j );
if(j==2) {
addToList( -2*i-12, 2*k+1 , -2000001-2*j );
addToList( 2*i+12, -2*k-1 , 2000001+2*j );
}
// right down squark
addToList( 2*i+12, 2*j+1 , -2000001-2*k );
addToList( -2*i-12, -2*j-1 , +2000001+2*k );
if(k==2) {
addToList( 2*i+12, 2*j+1 , -1000001-2*k );
addToList( -2*i-12, -2*j-1 , +1000001+2*k );
}
addToList( 2*i+11, 2*j+2 , -2000001-2*k );
addToList( -2*i-11, -2*j-2 , +2000001+2*k );
if(k==2) {
addToList( 2*i+11, 2*j+2 , -1000001-2*k );
addToList( -2*i-11, -2*j-2 , +1000001+2*k );
}
}
}
}
FFSVertex::doinit();
}
void RPVLQDVertex::setCoupling(Energy2, tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3) {
int islep = part3->id();
int i(-1),j(-1),k(-1);
Complex mix(1.);
// sneutrino case
if( abs(islep) == ParticleID::SUSY_nu_eL ||
abs(islep) == ParticleID::SUSY_nu_muL ||
abs(islep) == ParticleID::SUSY_nu_tauL) {
i = (abs(islep)-1000012)/2;
j = (abs(part1->id())-1)/2;
k = (abs(part2->id())-1)/2;
if( islep*part1->id() <0 ) swap(j,k);
if(islep>0) {
left ( 0.);
right(-1.);
}
else {
left (-1.);
right( 0.);
}
}
else if(abs(islep) == ParticleID::SUSY_e_Lminus||
abs(islep) == ParticleID::SUSY_mu_Lminus||
abs(islep) == ParticleID::SUSY_tau_1minus||
abs(islep) == ParticleID::SUSY_tau_2minus) {
if(abs(islep)<2000000) {
i = (abs(islep)-1000011)/2;
if(i==2) mix = (*stau_)(0,0);
}
else {
i = 2;
mix = (*stau_)(1,0);
assert(abs(islep)==ParticleID::SUSY_tau_2minus);
}
if(abs(part1->id())%2==1) {
j = (abs(part2->id())-2)/2;
k = (abs(part1->id())-1)/2;
}
else {
j = (abs(part1->id())-2)/2;
k = (abs(part2->id())-1)/2;
}
if(islep<0) {
left ( 1.);
right( 0.);
}
else {
left ( 0.);
right( 1.);
}
}
// left up squark
else if(abs(islep) == ParticleID::SUSY_u_L ||
abs(islep) == ParticleID::SUSY_c_L ||
abs(islep) == ParticleID::SUSY_t_1 ||
abs(islep) == ParticleID::SUSY_t_2) {
if(abs(islep)<2000000) {
j = (abs(islep)-1000002)/2;
if(j==2) mix = (*stop_)(0,0);
}
else {
j = 2;
mix = (*stop_)(1,0);
assert(abs(islep)==ParticleID::SUSY_t_2);
}
if(part1->coloured()) {
i = (abs(part2->id())-11)/2;
k = (abs(part1->id())- 1)/2;
}
else {
i = (abs(part1->id())-11)/2;
k = (abs(part2->id())- 1)/2;
}
if(islep<0) {
left ( 1.);
right( 0.);
}
else {
left ( 0.);
right( 1.);
}
}
else if(abs(islep) == ParticleID::SUSY_d_L ||
abs(islep) == ParticleID::SUSY_s_L ||
abs(islep) == ParticleID::SUSY_b_1 ||
abs(islep) == ParticleID::SUSY_b_2 ||
abs(islep) == ParticleID::SUSY_d_R ||
abs(islep) == ParticleID::SUSY_s_R) {
// right down squark
if(part1->id()*part2->id()>0) {
if(part1->coloured()) {
if(abs(part1->id())%2==1) {
i = (abs(part2->id())-12)/2;
j = (abs(part1->id())-1 )/2;
mix *= -1.;
assert(i>=0);
}
else {
i = (abs(part2->id())-11)/2;
j = (abs(part1->id())-2 )/2;
assert(i>=0);
}
}
else {
if(abs(part2->id())%2==1) {
i = (abs(part1->id())-12)/2;
j = (abs(part2->id())-1 )/2;
mix *= -1.;
assert(i>=0);
}
else {
i = (abs(part1->id())-11)/2;
j = (abs(part2->id())-2 )/2;
assert(i>=0);
}
}
if(abs(islep)>2000000) {
k = (abs(islep)-2000001)/2;
if(k==2) mix *= (*sbot_)(1,1);
}
else {
k = 2;
mix *= (*sbot_)(0,1);
assert(abs(islep)==ParticleID::SUSY_b_1);
}
if(islep<0) {
left ( 0.);
right( 1.);
}
else {
left ( 1.);
right( 0.);
}
}
// left down squark
else {
if(abs(islep)<2000000) {
j = (abs(islep)-1000001)/2;
if(j==2) mix = (*sbot_)(0,0);
}
else {
j = 2;
mix = (*sbot_)(1,0);
assert(abs(islep)==ParticleID::SUSY_b_2);
}
if(part1->coloured()) {
i = (abs(part2->id())-12)/2;
k = (abs(part1->id())- 1)/2;
}
else {
i = (abs(part1->id())-12)/2;
k = (abs(part2->id())- 1)/2;
}
if(islep<0) {
left (-1.);
right( 0.);
}
else {
left ( 0.);
right(-1.);
}
assert(i>=0);
}
}
else
assert(false);
assert( i>=0 && i<=2 && j>=0 && j<=2 && k>=0 && k<=2 );
norm(mix*lambda_[i][j][k]);
}
diff --git a/Models/Susy/RPV/RPVSSSVertex.cc b/Models/Susy/RPV/RPVSSSVertex.cc
--- a/Models/Susy/RPV/RPVSSSVertex.cc
+++ b/Models/Susy/RPV/RPVSSSVertex.cc
@@ -1,876 +1,877 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RPVSSSVertex class.
//
#include "RPVSSSVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "RPV.h"
#include <cassert>
using namespace Herwig;
using namespace ThePEG::Helicity;
RPVSSSVertex::RPVSSSVertex() : interactions_(0), q2Last_(ZERO), gLast_(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr RPVSSSVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVSSSVertex::fullclone() const {
return new_ptr(*this);
}
void RPVSSSVertex::persistentOutput(PersistentOStream & os) const {
os << interactions_ << stau_ << sbottom_ << stop_ << ounit(scalarScalarScalar_,GeV)
<< ounit(scalarPseudoPseudo_,GeV) << ounit(scalarSup_,GeV) << ounit(scalarSdown_,GeV)
<< ounit(scalarSneutrino_,GeV) << ounit(scalarSlepton_,GeV)
<< ounit(chargedSquark_,GeV) << ounit(chargedSlepton_,GeV)
<< ounit(scalarChargedCharged_,GeV) << ounit(pseudoChargedCharged_,GeV)
<< ounit(pseudoSup_,GeV) << ounit(pseudoSdown_,GeV) << ounit(pseudoSlepton_,GeV);
}
void RPVSSSVertex::persistentInput(PersistentIStream & is, int) {
is >> interactions_ >> stau_ >> sbottom_ >> stop_ >> iunit(scalarScalarScalar_,GeV)
>> iunit(scalarPseudoPseudo_,GeV) >> iunit(scalarSup_,GeV) >> iunit(scalarSdown_,GeV)
>> iunit(scalarSneutrino_,GeV) >> iunit(scalarSlepton_,GeV)
>> iunit(chargedSquark_,GeV) >> iunit(chargedSlepton_,GeV)
>> iunit(scalarChargedCharged_,GeV) >> iunit(pseudoChargedCharged_,GeV)
>> iunit(pseudoSup_,GeV) >> iunit(pseudoSdown_,GeV) >> iunit(pseudoSlepton_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RPVSSSVertex,SSSVertex>
describeHerwigRPVSSSVertex("Herwig::RPVSSSVertex", "HwRPV.so");
void RPVSSSVertex::Init() {
static ClassDocumentation<RPVSSSVertex> documentation
("The RPVSSSVertex class implements the coupling of three"
" scalar particles in the RPV model");
static Switch<RPVSSSVertex,unsigned int> interfaceInteractions
("Interactions",
"Which interactions to include",
&RPVSSSVertex::interactions_, 0, false, false);
static SwitchOption interfaceInteractionsAll
(interfaceInteractions,
"All",
"Include both triple Higgs and Higgs sfermion interactions",
0);
static SwitchOption interfaceInteractionsHiggsHiggsHiggs
(interfaceInteractions,
"HiggsHiggsHiggs",
"Only include triple Higgs boson interactions",
1);
static SwitchOption interfaceInteractionsHiggsSfermions
(interfaceInteractions,
"HiggsSfermions",
"Only include Higgs sfermion interactions",
2);
}
void RPVSSSVertex::doinit() {
// extract the model
tRPVPtr model = dynamic_ptr_cast<tRPVPtr>(generator()->standardModel());
if( !model ) throw InitException() << "RPVSSSVertex::doinit() - The"
<< " pointer to the RPV object is null!"
<< Exception::abortnow;
// get the Higgs mixing matrices
MixingMatrixPtr mixH = model->CPevenHiggsMix() ;
MixingMatrixPtr mixP = model->CPoddHiggsMix() ;
MixingMatrixPtr mixC = model->ChargedHiggsMix();
// find the codes for the Higgs bosons
vector<long> pseudo(1,36);
vector<long> scalar(2);
vector<long> charged(1,37);
scalar[0] = 25;
scalar[1] = 35;
if(mixH&&mixH->size().first>2) {
scalar.push_back(1000012);
scalar.push_back(1000014);
scalar.push_back(1000016);
}
if(mixP&&mixP->size().first>1) {
pseudo.push_back(1000017);
pseudo.push_back(1000018);
pseudo.push_back(1000019);
}
if(mixC&&mixC->size().first>2) {
charged.push_back(-1000011);
charged.push_back(-1000013);
charged.push_back(-1000015);
charged.push_back(-2000011);
charged.push_back(-2000013);
charged.push_back(-2000015);
}
// triple Higgs interactions
if(interactions_==0||interactions_==1) {
// three neutral scalar bosons
for(unsigned int i1=0;i1<scalar.size();++i1) {
for(unsigned int i2=0;i2<=i1;++i2) {
for(unsigned int i3=0;i3<=i2;++i3) {
addToList(scalar[i1],scalar[i2],scalar[i3]);
}
}
}
// one neutral scalar two pseudoscalars
for(unsigned int i1=0;i1<scalar.size();++i1) {
for(unsigned int i2=0;i2<pseudo.size();++i2) {
for(unsigned int i3=0;i3<=i2;++i3) {
addToList(scalar[i1],pseudo[i2],pseudo[i3]);
}
}
}
// one neutral scalar two charged scalars
for(unsigned int i1=0;i1<scalar.size();++i1) {
for(unsigned int i2=0;i2<charged.size();++i2) {
for(unsigned int i3=0;i3<charged.size();++i3) {
if(!(abs(charged[i2])>1000000&&abs(charged[i3])>1000000&&
abs(charged[i2])%1000000==abs(charged[i3])%1000000))
addToList(scalar[i1],charged[i2],-charged[i3]);
}
}
}
// one pseudo scalar two charged scalars
if(charged.size()>1) {
for(unsigned int i1=0;i1<pseudo.size();++i1) {
for(unsigned int i2=0;i2<charged.size();++i2) {
for(unsigned int i3=0;i3<charged.size();++i3) {
if(i2==i3) continue;
if(!(abs(charged[i2])>1000000&&abs(charged[i3])>1000000&&
abs(charged[i2])%1000000==abs(charged[i3])%1000000))
addToList(pseudo[i1],charged[i2],-charged[i3]);
}
}
}
}
}
// sfermion interactions
if(interactions_==0||interactions_==2) {
// scalar neutral higgs sfermion sfermion
for(unsigned int i = 0; i < scalar.size(); ++i) {
// squarks
for(unsigned int j = 1; j < 7; ++j) {
long lj = 1000000 + j;
long rj = 2000000 + j;
//LLbar
addToList(scalar[i],lj,-lj);
//RRbar
addToList(scalar[i],rj,-rj);
//LRbar
addToList(scalar[i],lj,-rj);
//RLbar
addToList(scalar[i],rj,-lj);
}
// sleptons
for(unsigned int j = 11; j < 17; ++j) {
long lj = 1000000 + j;
long rj = 2000000 + j;
if( j % 2 != 0) {
// LL
addToList(scalar[i],lj,-lj);
// RR
addToList(scalar[i],rj,-rj);
//LRbar
addToList(scalar[i],lj,-rj);
//RLbar
addToList(scalar[i],rj,-lj);
}
// sneutrino only if no mixing
else if(scalar.size()==2) {
addToList(scalar[i],lj,-lj);
}
}
}
// pseudoscalar sfermion sfermion
for(unsigned int i = 0; i < pseudo.size(); ++i) {
// squarks
for(unsigned int j = 1; j < 7; ++j) {
long lj = 1000000 + j;
long rj = 2000000 + j;
//LRbar
addToList(pseudo[i],lj,-rj);
//RLbar
addToList(pseudo[i],rj,-lj);
}
// sleptons
if(scalar.size()==2) {
for(unsigned int j = 11; j < 17; j += 2) {
long lj = 1000000 + j;
long rj = 2000000 + j;
addToList(36,lj,-rj);
addToList(36,rj,-lj);
}
}
}
//outgoing H+
for(unsigned int i=0;i<charged.size();++i) {
// squarks
for(long ii = 2; ii < 7; ii += 2) {
//LL
addToList(charged[i], 999999 + ii, -1000000 - ii);
//RR
addToList(charged[i], 1999999 + ii, -2000000 - ii);
//RL
addToList(charged[i], 1999999 + ii, -1000000 - ii);
//LR
addToList(charged[i], 999999 + ii, -2000000 - ii);
}
if(scalar.size()==2) {
for(long ii = 11; ii < 17; ii += 2) {
addToList(37, 1000000 + ii, -1000001 - ii);
addToList(37, 2000000 + ii, -1000001 - ii);
}
}
//outgoing H-
for(long ii = 2; ii < 7; ii += 2) {
//LL
addToList(-charged[i], 1000000 + ii, -999999 - ii);
//RR
addToList(-charged[i], 2000000 + ii, -1999999 - ii);
//RL
addToList(-charged[i], 1000000 + ii, -1999999 - ii);
//LR
addToList(-charged[i], 2000000 + ii, -999999 - ii);
}
if(scalar.size()==2) {
for(long ii = 11; ii < 17; ii += 2) {
addToList(-37, 1000001 + ii, -1000000 - ii);
addToList(-37, 1000001 + ii, -2000000 - ii);
}
}
}
}
SSSVertex::doinit();
// extract the sfermion mixing matrices
// sfermion mixing
stop_ = model->stopMix();
sbottom_ = model->sbottomMix();
if(!stop_ || !sbottom_)
throw InitException() << "RPVSSSVertex::doinit() - "
<< "A mixing matrix pointer is null."
<< " stop: " << stop_ << " sbottom: " << sbottom_
<< Exception::abortnow;
stau_ = model->stauMix();
if(!stau_ && (!mixC || mixC->size().first<2))
throw InitException() << "RPVSSSVertex::doinit() either the stau"
<< " mixing matrix must be set or the stau"
<< " included in mixing with the"
<< " charged Higgs bosons" << Exception::abortnow;
// couplings of the neutral Higgs bosons
Energy mw = getParticleData(ParticleID::Wplus)->mass();
double sw = sqrt(sin2ThetaW());
double cw = sqrt(1.-sin2ThetaW());
// extract the vevs
vector<Energy> vnu = model->sneutrinoVEVs();
double g = electroMagneticCoupling(sqr(mw))/sw;
Energy v = 2.*mw/g;
double tanb = model->tanBeta();
vector<Energy> vevs(5);
vevs[0] = sqrt((sqr(v)-sqr(vnu[0])-sqr(vnu[1])-sqr(vnu[2]))/
(1.+sqr(tanb)));
vevs[1] = vevs[0]*tanb;
for(unsigned int ix=0;ix<vnu.size();++ix) vevs[2+ix] = vnu[ix];
// bilinear RPV terms
// coupling of three scalar Higgs bosons
scalarScalarScalar_.resize(scalar.size(),vector<vector<complex<Energy > > >
(scalar.size(),vector<complex<Energy> >(scalar.size(),complex<Energy>(ZERO))));
double delta[5]={1.,-1.,1.,1.,1.};
if(vevs.size()>scalar.size()) vevs.resize(scalar.size());
for(unsigned int i1=0;i1<scalar.size();++i1) {
for(unsigned int i2=0;i2<scalar.size();++i2) {
for(unsigned int i3=0;i3<scalar.size();++i3) {
scalarScalarScalar_[i1][i2][i3] = ZERO;
for(unsigned int ix=0;ix<vevs.size();++ix) {
for(unsigned int k=0;k<scalar.size();++k) {
scalarScalarScalar_[i1][i2][i3] +=
delta[ix]*vevs[ix]*(*mixH)(i1,ix)*delta[k]*(*mixH)(i2,k)*(*mixH)(i3,k)+
delta[ix]*vevs[ix]*(*mixH)(i2,ix)*delta[k]*(*mixH)(i1,k)*(*mixH)(i3,k)+
delta[ix]*vevs[ix]*(*mixH)(i3,ix)*delta[k]*(*mixH)(i1,k)*(*mixH)(i2,k);
}
}
scalarScalarScalar_[i1][i2][i3] *= -0.25*g/sqr(cw);
}
}
}
// coupling of scalar Higgs to 2 pseudoscalars
scalarPseudoPseudo_.resize(scalar.size(),vector<vector<complex<Energy > > >
(pseudo.size(),vector<complex<Energy> >(pseudo.size(),complex<Energy>(ZERO))));
for(unsigned int i1=0;i1<scalar.size();++i1) {
for(unsigned int i2=0;i2<pseudo.size();++i2) {
for(unsigned int i3=0;i3<pseudo.size();++i3) {
scalarPseudoPseudo_[i1][i2][i3] = ZERO;
for(unsigned int ix=0;ix<vevs.size();++ix) {
for(unsigned int k=0;k<pseudo.size();++k) {
scalarPseudoPseudo_[i1][i2][i3] +=
delta[k]*delta[ix]*vevs[ix]*(*mixH)(i1,ix)*(*mixP)(i2,k)*(*mixP)(i3,k);
}
}
scalarPseudoPseudo_[i1][i2][i3] *= -0.25*g/sqr(cw);
}
}
}
// coupling of scalar Higgs to 2 charged Higgs
double gp = g*sw/cw;
Energy mu = model->muParameter();
vector<Energy> eps = model->epsilon();
scalarChargedCharged_.resize(scalar.size(),vector<vector<complex<Energy > > >
(charged.size(),vector<complex<Energy> >(charged.size(),complex<Energy>(ZERO))));
double yl[3] = {sqrt(2.)*getParticleData(11)->mass()/vevs[1],
sqrt(2.)*getParticleData(13)->mass()/vevs[1],
sqrt(2.)*getParticleData(15)->mass()/vevs[1]};
complex<Energy> Al[3] = {complex<Energy>(ZERO),complex<Energy>(ZERO),yl[2]*model->tauTrilinear()};
for(unsigned int i1=0;i1<scalar.size();++i1) {
for(unsigned int i2=0;i2<charged.size();++i2) {
for(unsigned int i3=0;i3<charged.size();++i3) {
complex<Energy> umdi = vevs[0]*(*mixH)(i1,0)-vevs[1]*(*mixH)(i1,1)+vevs[2]*(*mixH)(i1,2)+
vevs[3]*(*mixH)(i1,3)+vevs[4]*(*mixH)(i1,4);
scalarChargedCharged_[i1][i2][i3] =
// HH term
0.25*sqr(g)*(-vevs[1]*((*mixH)(i1,1)*((*mixC)(i2,1)*(*mixC)(i3,1)+(*mixC)(i2,2)*(*mixC)(i3,2))+
(*mixH)(i1,0)*((*mixC)(i2,2)*(*mixC)(i3,1)+(*mixC)(i2,1)*(*mixC)(i3,2)))
-vevs[0]*((*mixH)(i1,0)*((*mixC)(i2,1)*(*mixC)(i3,1)+(*mixC)(i2,2)*(*mixC)(i3,2))+
(*mixH)(i1,1)*((*mixC)(i2,2)*(*mixC)(i3,1)+(*mixC)(i2,1)*(*mixC)(i3,2)))
+(vevs[2]*(*mixH)(i1,2)+vevs[3]*(*mixH)(i1,3)+vevs[4]*(*mixH)(i1,4))*
((*mixC)(i2,1)*(*mixC)(i3,1)-(*mixC)(i2,2)*(*mixC)(i3,2)))-
0.25*sqr(gp)*((*mixC)(i2,1)*(*mixC)(i3,1)-(*mixC)(i2,2)*(*mixC)(i3,2))*umdi
-0.5*(*mixC)(i2,1)*(*mixC)(i3,1)*(yl[0]*vevs[2]*(*mixH)(i1,2)+yl[1]*vevs[3]*(*mixH)(i1,3)+yl[2]*vevs[4]*(*mixH)(i1,4))
// LL term
+0.25*(sqr(g)-sqr(gp))*umdi*((*mixC)(i2,2)*(*mixC)(i3,2)+(*mixC)(i2,3)*(*mixC)(i3,3)+(*mixC)(i2,4)*(*mixC)(i3,4))
-vevs[0]*(*mixH)(i1,1)*(yl[0]*(*mixC)(i2,2)*(*mixC)(i3,2)+yl[1]*(*mixC)(i2,3)*(*mixC)(i3,3)+yl[2]*(*mixC)(i2,4)*(*mixC)(i3,4))
-0.25*sqr(g)*((vevs[2]*(*mixC)(i3,2)+vevs[3]*(*mixC)(i3,3)+vevs[4]*(*mixC)(i3,4))*
((*mixH)(i1,2)*(*mixC)(i2,2)+(*mixH)(i1,3)*(*mixC)(i2,3)+(*mixH)(i1,4)*(*mixC)(i2,4))+
(vevs[2]*(*mixC)(i2,2)+vevs[3]*(*mixC)(i2,3)+vevs[4]*(*mixC)(i2,4))*
((*mixH)(i1,2)*(*mixC)(i3,2)+(*mixH)(i1,3)*(*mixC)(i3,3)+(*mixH)(i1,4)*(*mixC)(i3,4)))
// RR term
+0.5*sqr(gp)*umdi*((*mixC)(i2,5)*(*mixC)(i3,5)+(*mixC)(i2,6)*(*mixC)(i3,6)+(*mixC)(i2,7)*(*mixC)(i3,7))
-vevs[0]*(*mixH)(i1,1)*(yl[0]*(*mixC)(i2,5)*(*mixC)(i3,5)+yl[1]*(*mixC)(i2,6)*(*mixC)(i3,6)+yl[2]*(*mixC)(i2,7)*(*mixC)(i3,7))
-0.5*((vevs[2]*yl[0]*(*mixC)(i2,5)+vevs[3]*yl[1]*(*mixC)(i2,6)+vevs[4]*yl[2]*(*mixC)(i2,7))*
(yl[0]*(*mixH)(i1,2)*(*mixC)(i3,5)+yl[1]*(*mixH)(i1,3)*(*mixC)(i3,6)+yl[2]*(*mixH)(i1,4)*(*mixC)(i3,7))+
(vevs[2]*yl[0]*(*mixC)(i3,5)+vevs[3]*yl[1]*(*mixC)(i3,6)+vevs[4]*yl[2]*(*mixC)(i3,7))*
(yl[0]*(*mixH)(i1,2)*(*mixC)(i2,5)+yl[1]*(*mixH)(i1,3)*(*mixC)(i2,6)+yl[2]*(*mixH)(i1,4)*(*mixC)(i2,7)))
// LR
-(*mixH)(i1,1)/sqrt(2.)*(Al[0]*(*mixC)(i2,2)*(*mixC)(i3,2)+Al[1]*(*mixC)(i2,3)*(*mixC)(i3,3)+Al[2]*(*mixC)(i2,4)*(*mixC)(i3,4))
+(*mixH)(i1,2)/sqrt(2.)*mu*(yl[0]*(*mixC)(i2,2)*(*mixC)(i3,2)+yl[1]*(*mixC)(i2,3)*(*mixC)(i3,3)+yl[2]*(*mixC)(i2,4)*(*mixC)(i3,4))
// RL
-(*mixH)(i1,1)/sqrt(2.)*(Al[0]*(*mixC)(i3,2)*(*mixC)(i2,2)+Al[1]*(*mixC)(i3,3)*(*mixC)(i2,3)+Al[2]*(*mixC)(i3,4)*(*mixC)(i2,4))
+(*mixH)(i1,2)/sqrt(2.)*mu*(yl[0]*(*mixC)(i3,2)*(*mixC)(i2,2)+yl[1]*(*mixC)(i3,3)*(*mixC)(i2,3)+yl[2]*(*mixC)(i3,4)*(*mixC)(i2,4))
// HL
-0.25*sqr(g)*(((*mixH)(i1,2)*(*mixC)(i3,2)+(*mixH)(i1,3)*(*mixC)(i3,3)+(*mixH)(i1,4)*(*mixC)(i3,4))*
(vevs[0]*(*mixC)(i2,0)+vevs[1]*(*mixC)(i2,1))
+(vevs[2]*(*mixC)(i3,2)+vevs[3]*(*mixC)(i3,3)+vevs[4]*(*mixC)(i3,4))*
((*mixH)(i1,0)*(*mixC)(i2,0)+(*mixH)(i1,1)*(*mixC)(i2,1)))
+0.5*(*mixH)(i1,0)*(*mixC)(i2,0)*
(sqr(yl[0])*vevs[2]*(*mixC)(i3,2)+sqr(yl[1])*vevs[3]*(*mixC)(i3,3)+sqr(yl[2])*vevs[4]*(*mixC)(i3,4))
+0.5*vevs[0]*(*mixC)(i2,0)*(sqr(yl[0])*(*mixH)(i1,2)*(*mixC)(i3,2)+
sqr(yl[1])*(*mixH)(i1,3)*(*mixC)(i3,3)+
sqr(yl[2])*(*mixH)(i1,4)*(*mixC)(i3,4))
// LH
-0.25*sqr(g)*(((*mixH)(i1,2)*(*mixC)(i2,2)+(*mixH)(i1,3)*(*mixC)(i2,3)+(*mixH)(i1,4)*(*mixC)(i2,4))*
(vevs[0]*(*mixC)(i3,0)+vevs[1]*(*mixC)(i3,1))
+(vevs[2]*(*mixC)(i2,2)+vevs[3]*(*mixC)(i2,3)+vevs[4]*(*mixC)(i2,4))*
((*mixH)(i1,0)*(*mixC)(i3,0)+(*mixH)(i1,1)*(*mixC)(i3,1)))
+0.5*(*mixH)(i1,0)*(*mixC)(i3,0)*
(sqr(yl[0])*vevs[2]*(*mixC)(i2,2)+sqr(yl[1])*vevs[3]*(*mixC)(i2,3)+sqr(yl[2])*vevs[4]*(*mixC)(i2,4))
+0.5*vevs[0]*(*mixC)(i3,0)*(sqr(yl[0])*(*mixH)(i1,2)*(*mixC)(i2,2)+
sqr(yl[1])*(*mixH)(i1,3)*(*mixC)(i2,3)+
sqr(yl[2])*(*mixH)(i1,4)*(*mixC)(i2,4))
// HR
+sqrt(0.5)*(eps[0]*yl[0]*(*mixC)(i3,5)+eps[1]*yl[1]*(*mixC)(i3,6)+eps[2]*yl[2]*(*mixC)(i3,7))*
((*mixH)(i1,0)*(*mixC)(i2,1)+(*mixH)(i1,1)*(*mixC)(i2,0))
+sqrt(0.5)*(*mixC)(i2,0)*(Al[0]*(*mixH)(i1,2)*(*mixC)(i3,5)+
Al[1]*(*mixH)(i1,2)*(*mixC)(i3,6)+Al[2]*(*mixH)(i1,2)*(*mixC)(i3,7))
+sqrt(0.5)*mu*(*mixC)(i2,1)*(yl[0]*(*mixH)(i1,2)*(*mixC)(i3,5)+
yl[1]*(*mixH)(i1,3)*(*mixC)(i3,6)+
yl[2]*(*mixH)(i1,4)*(*mixC)(i3,7))
// RH
+sqrt(0.5)*(eps[0]*yl[0]*(*mixC)(i2,5)+eps[1]*yl[1]*(*mixC)(i2,6)+eps[2]*yl[2]*(*mixC)(i2,7))*
((*mixH)(i1,0)*(*mixC)(i3,1)+(*mixH)(i1,1)*(*mixC)(i3,0))
+sqrt(0.5)*(*mixC)(i3,0)*(Al[0]*(*mixH)(i1,2)*(*mixC)(i2,5)+
Al[1]*(*mixH)(i1,2)*(*mixC)(i2,6)+Al[2]*(*mixH)(i1,2)*(*mixC)(i2,7))
+sqrt(0.5)*mu*(*mixC)(i3,1)*(yl[0]*(*mixH)(i1,2)*(*mixC)(i2,5)+
yl[1]*(*mixH)(i1,3)*(*mixC)(i2,6)+
yl[2]*(*mixH)(i1,4)*(*mixC)(i2,7));
// normalization
scalarChargedCharged_[i1][i2][i3] /= g;
}
}
}
// coupling of the pseudoscalar Higgs to two charged Higgs bosons
pseudoChargedCharged_.resize(pseudo.size(),vector<vector<complex<Energy > > >
(charged.size(),vector<complex<Energy> >(charged.size(),complex<Energy>(ZERO))));
if(charged.size()<5) {
for(unsigned int i1=0;i1<pseudo.size();++i1) {
for(unsigned int i2=0;i2<charged.size();++i2) {
for(unsigned int i3=0;i3<charged.size();++i3) {
pseudoChargedCharged_[i1][i2][i3] = ZERO;
for(unsigned int il=0;il<3;++il) {
pseudoChargedCharged_[i1][i2][i3] += (Al[il]*(*mixP)(i1,0)-mu*yl[il]*(*mixP)(i1,1))*
((*mixC)(i2,il+2)*(*mixC)(i3,il+5)-(*mixC)(i2,il+5)*(*mixC)(i3,il+2));
}
// normalization // do not revert to *= , breaks with XCode 5.1
pseudoChargedCharged_[i1][i2][i3] = pseudoChargedCharged_[i1][i2][i3] * Complex(0.,-1.)*sqrt(0.5)/g;
}
}
}
}
// couplings of the Higgs bosons to the up type squarks
scalarSup_.resize(scalar.size(),vector<vector<vector<complex<Energy > > > >
(3,vector<vector<complex<Energy> > >(2,vector<complex<Energy> >(2,complex<Energy>(ZERO)))));
for(unsigned int iq=0;iq<3;++iq) {
double y = sqrt(2.)*getParticleData(2*long(iq+1))->mass()/vevs[1];
complex<Energy> A = iq!=2 ? complex<Energy>(ZERO) : y*model->topTrilinear();
Complex mixing[2][2];
if(iq!=2) {
mixing[0][0] = 1.;
mixing[0][1] = 0.;
mixing[1][0] = 0.;
mixing[1][1] = 1.;
}
else {
mixing[0][0] = (*stop_)(0,0);
mixing[0][1] = (*stop_)(0,1);
mixing[1][0] = (*stop_)(1,0);
mixing[1][1] = (*stop_)(1,1);
}
// loop over Higgs
for(unsigned int ix=0;ix<2;++ix) {
for(unsigned int iy=0;iy<2;++iy) {
for(unsigned int ih=0;ih<scalar.size();++ih) {
// first LL term
Complex LL1 =-(sqr(g)/4.- sqr(gp)/12.)*mixing[ix][0]*conj(mixing[iy][0]);
// first RR term
Complex RR1 = -1./3.*sqr(gp)*mixing[ix][1]*conj(mixing[iy][1]);
complex<Energy> factors[5];
for(unsigned int iz=0;iz<5;++iz) factors[iz] = delta[iz]*vevs[iz]*(LL1+RR1);
factors[0] += y/sqrt(2.)*mu*( mixing[ix][0]*conj(mixing[iy][1]) +
mixing[ix][1]*conj(mixing[iy][0]) );
factors[1] += -vevs[1]*sqr(y)*( mixing[ix][0]*conj(mixing[iy][0]) +
mixing[ix][1]*conj(mixing[iy][1]) )
-A/sqrt(2.)*(mixing[ix][0]*conj(mixing[iy][1]) +
mixing[ix][1]*conj(mixing[iy][0]));
for(unsigned int iz=0;iz<3;++iz) {
factors[iz+2] += -y*eps[iz]/sqrt(2.)*( mixing[ix][0]*conj(mixing[iy][1]) +
mixing[ix][1]*conj(mixing[iy][0]) );
}
for(unsigned int iz=0;iz<scalar.size();++iz) {
scalarSup_[ih][iq][ix][iy] += (*mixH)(ih,iz)*factors[iz];
}
scalarSup_[ih][iq][ix][iy] /= g;
}
}
}
}
// couplings of the pseudoscalar Higgs bosons to the up type squarks
pseudoSup_.resize(pseudo.size(),vector<complex<Energy > >(3,complex<Energy>(ZERO)));
for(unsigned int iq=0;iq<3;++iq) {
double y = sqrt(2.)*getParticleData(2*long(iq+1))->mass()/vevs[1];
complex<Energy> A = iq!=2 ? complex<Energy>(ZERO) : y*model->topTrilinear();
// loop over Higgs
for(unsigned int ih=0;ih<pseudo.size();++ih) {
pseudoSup_[ih][iq] = Complex(0.,-1.)*sqrt(0.5)*(A*(*mixP)(ih,1)-y*mu*(*mixP)(ih,0))/g;
}
}
// couplings of the Higgs bosons to the down type squarks
scalarSdown_.resize(scalar.size(),vector<vector<vector<complex<Energy > > > >
(3,vector<vector<complex<Energy> > >(2,vector<complex<Energy> >(2,complex<Energy>(ZERO)))));
for(unsigned int iq=0;iq<3;++iq) {
double y = sqrt(2.)*getParticleData(2*long(iq+1)-1)->mass()/vevs[0];
Complex mixing[2][2];
complex<Energy> A = iq!=2 ? complex<Energy>(ZERO) : y*model->bottomTrilinear();
if(iq!=2) {
mixing[0][0] = 1.;
mixing[0][1] = 0.;
mixing[1][0] = 0.;
mixing[1][1] = 1.;
}
else {
mixing[0][0] = (*sbottom_)(0,0);
mixing[0][1] = (*sbottom_)(0,1);
mixing[1][0] = (*sbottom_)(1,0);
mixing[1][1] = (*sbottom_)(1,1);
}
for(unsigned int ix=0;ix<2;++ix) {
for(unsigned int iy=0;iy<2;++iy) {
for(unsigned int ih=0;ih<scalar.size();++ih) {
// first LL term
Complex LL1 = (sqr(g)/4.+sqr(gp)/12.)*mixing[ix][0]*conj(mixing[iy][0]);
// first RR term
Complex RR1 = 1./6.*sqr(gp)*mixing[ix][1]*conj(mixing[iy][1]);
complex<Energy> factors[5];
for(unsigned int iz=0;iz<5;++iz) factors[iz] = delta[iz]*vevs[iz]*(LL1+RR1);
factors[0] += -vevs[0]*sqr(y)*(mixing[ix][0]*conj(mixing[iy][0])+
mixing[ix][1]*conj(mixing[iy][1]))
- A/sqrt(2.)*(mixing[ix][0]*conj(mixing[iy][1])+
mixing[ix][1]*conj(mixing[iy][0]));
factors[1] += y/sqrt(2.)*mu*(mixing[ix][0]*conj(mixing[iy][1])+
mixing[ix][1]*conj(mixing[iy][0]));
for(unsigned int iz=0;iz<scalar.size();++iz) {
scalarSdown_[ih][iq][ix][iy] += (*mixH)(ih,iz)*factors[iz];
}
scalarSdown_[ih][iq][ix][iy] /= g;
}
}
}
}
// couplings of the pseudoscalar Higgs bosons to the down type squarks
pseudoSdown_.resize(pseudo.size(),vector<complex<Energy > >(3,complex<Energy>(ZERO)));
for(unsigned int iq=0;iq<3;++iq) {
double y = sqrt(2.)*getParticleData(2*long(iq+1)-1)->mass()/vevs[0];
complex<Energy> A = iq!=2 ? complex<Energy>(ZERO) : y*model->bottomTrilinear();
for(unsigned int ih=0;ih<pseudo.size();++ih) {
pseudoSdown_[ih][iq] = Complex(0.,-1.)*sqrt(0.5)*(A*(*mixP)(ih,0)-mu*y*(*mixP)(ih,1))/g;
}
}
// couplings of the scalar Higgs bosons to the sneutrinos
if(scalar.size()==2) {
scalarSneutrino_.resize(scalar.size(),vector<complex<Energy > >(3,complex<Energy>(ZERO)));
for(unsigned int il=0;il<3;++il) {
// loop over Higgs
for(unsigned int ih=0;ih<scalar.size();++ih) {
// first LL term
Complex LL1 =-(sqr(g)/4.+sqr(gp)/4.);
complex<Energy> factors[5];
for(unsigned int iz=0;iz<5;++iz) factors[iz] = delta[iz]*vevs[iz]*LL1;
for(unsigned int iz=0;iz<scalar.size();++iz) {
scalarSneutrino_[ih][il] += (*mixH)(ih,iz)*factors[iz];
}
scalarSneutrino_[ih][il] /= g;
}
}
}
// couplings of the Higgs bosons to the charged sleptons
if(charged.size()==1) {
scalarSlepton_.resize(scalar.size(),vector<vector<vector<complex<Energy > > > >
(3,vector<vector<complex<Energy> > >(2,vector<complex<Energy> >(2,complex<Energy>(ZERO)))));
for(unsigned int il=0;il<3;++il) {
double y = sqrt(2.)*getParticleData(2*long(il+6)-1)->mass()/vevs[0];
Complex mixing[2][2];
complex<Energy> A = il!=2 ? complex<Energy>(ZERO) : y*model->tauTrilinear();
if(il!=2) {
mixing[0][0] = 1.;
mixing[0][1] = 0.;
mixing[1][0] = 0.;
mixing[1][1] = 1.;
}
else {
mixing[0][0] = (*stau_)(0,0);
mixing[0][1] = (*stau_)(0,1);
mixing[1][0] = (*stau_)(1,0);
mixing[1][1] = (*stau_)(1,1);
}
for(unsigned int ix=0;ix<2;++ix) {
for(unsigned int iy=0;iy<2;++iy) {
for(unsigned int ih=0;ih<scalar.size();++ih) {
// first LL term
Complex LL1 = (sqr(g)/4.-sqr(gp)/4.)*mixing[ix][0]*conj(mixing[iy][0]);
// first RR term
Complex RR1 = 0.5*sqr(gp)*mixing[ix][1]*conj(mixing[iy][1]);
complex<Energy> factors[5];
for(unsigned int iz=0;iz<5;++iz) factors[iz] = delta[iz]*vevs[iz]*(LL1+RR1);
factors[0] += -vevs[0]*sqr(y)*(mixing[ix][0]*conj(mixing[iy][0])+
mixing[ix][1]*conj(mixing[iy][1]))
- A/sqrt(2.)*(mixing[ix][0]*conj(mixing[iy][1])+
mixing[ix][1]*conj(mixing[iy][0]));
factors[1] += y/sqrt(2.)*mu*(mixing[ix][0]*conj(mixing[iy][1])+
mixing[ix][1]*conj(mixing[iy][0]));
for(unsigned int iz=0;iz<scalar.size();++iz) {
scalarSlepton_[ih][il][ix][iy] += (*mixH)(ih,iz)*factors[iz];
}
scalarSlepton_[ih][il][ix][iy] /= g;
}
}
}
}
}
// couplings of the pseudoscalar Higgs bosons to the charged sleptons
if(charged.size()==1) {
pseudoSlepton_.resize(pseudo.size(),vector<complex<Energy> >(3,complex<Energy>(ZERO)));
for(unsigned int il=0;il<3;++il) {
double y = sqrt(2.)*getParticleData(2*long(il+6)-1)->mass()/vevs[0];
complex<Energy> A = il!=2 ? complex<Energy>(ZERO) : y*model->tauTrilinear();
for(unsigned int ih=0;ih<pseudo.size();++ih) {
pseudoSlepton_[ih][il] = Complex(0.,-1.)*sqrt(0.5)*(A*(*mixP)(ih,0)-mu*y*(*mixP)(ih,1))/g;
}
}
}
// charged Higgs squarks
chargedSquark_.resize(charged.size(),vector<vector<vector<complex<Energy > > > >
(3,vector<vector<complex<Energy> > >(2,vector<complex<Energy> >(2,complex<Energy>(ZERO)))));
for(unsigned int iq=0;iq<3;++iq) {
double yd = sqrt(2.)*getParticleData(2*long(iq+1)-1)->mass()/vevs[0];
double yu = sqrt(2.)*getParticleData(2*long(iq+1))->mass()/vevs[1];
Complex mixd[2][2],mixu[2][2];
complex<Energy> Ad = iq!=2 ? complex<Energy>(ZERO) : yd*model->bottomTrilinear();
complex<Energy> Au = iq!=2 ? complex<Energy>(ZERO) : yu*model->topTrilinear();
if(iq!=2) {
mixd[0][0] = mixu[0][0] = 1.;
mixd[0][1] = mixu[0][1] = 0.;
mixd[1][0] = mixu[1][0] = 0.;
mixd[1][1] = mixu[1][1] = 1.;
}
else {
mixd[0][0] = (*sbottom_)(0,0);
mixd[0][1] = (*sbottom_)(0,1);
mixd[1][0] = (*sbottom_)(1,0);
mixd[1][1] = (*sbottom_)(1,1);
mixu[0][0] = (*stop_)(0,0);
mixu[0][1] = (*stop_)(0,1);
mixu[1][0] = (*stop_)(1,0);
mixu[1][1] = (*stop_)(1,1);
}
for(unsigned int ih=0;ih<charged.size();++ih) {
for(unsigned int ix=0;ix<2;++ix) {
for(unsigned int iy=0;iy<2;++iy) {
// various terms (up first) (down second)
complex<Energy> LL(ZERO);
for(unsigned int iz=0;iz<vevs.size();++iz)
LL += 0.5*sqr(g)*vevs[iz]*(*mixC)(ih,iz);
LL += -vevs[0]*(*mixC)(ih,0)*sqr(yd)-vevs[1]*(*mixC)(ih,1)*sqr(yu);
LL *= -sqrt(0.5);
complex<Energy> RR =
yu*yd*(vevs[1]*(*mixC)(ih,0) + vevs[0]*(*mixC)(ih,1))/sqrt(2.);
complex<Energy> LR = (*mixC)(ih,0)*Ad+(*mixC)(ih,1)*yd*mu;
complex<Energy> RL = yu*mu*(*mixC)(ih,0) + Au*(*mixC)(ih,1);
chargedSquark_[ih][iq][ix][iy] =
mixu[ix][0]*mixd[iy][0]*LL + mixu[ix][1]*mixd[iy][1]*RR +
mixu[ix][0]*mixd[iy][1]*LR + mixu[ix][1]*mixd[iy][0]*RL;
chargedSquark_[ih][iq][ix][iy] /=g;
}
}
}
}
// charged Higgs slepton
if(charged.size()==1) {
chargedSlepton_.resize(charged.size(),vector<vector<complex<Energy > > >
(3,vector<complex<Energy> >(2,complex<Energy>(ZERO))));
for(unsigned int il=0;il<3;++il) {
double y = sqrt(2.)*getParticleData(2*long(il+6)-1)->mass()/vevs[0];
Complex mixd[2][2];
complex<Energy> Al = il!=2 ? complex<Energy>(ZERO) : y*model->tauTrilinear();
if(il!=2) {
mixd[0][0] = 1.;
mixd[0][1] = 0.;
mixd[1][0] = 0.;
mixd[1][1] = 1.;
}
else {
mixd[0][0] = (*stau_)(0,0);
mixd[0][1] = (*stau_)(0,1);
mixd[1][0] = (*stau_)(1,0);
mixd[1][1] = (*stau_)(1,1);
}
for(unsigned int ih=0;ih<charged.size();++ih) {
for(unsigned int ix=0;ix<2;++ix) {
// various terms (charged lepton second)
complex<Energy> LL(ZERO);
for(unsigned int iz=0;iz<vevs.size();++iz)
LL += 0.5*sqr(g)*vevs[iz]*(*mixC)(ih,iz);
LL += -vevs[0]*(*mixC)(ih,0)*sqr(y);
LL *= -sqrt(0.5);
complex<Energy> LR = (*mixC)(ih,0)*Al+(*mixC)(ih,1)*y*mu;
chargedSlepton_[ih][il][ix] = mixd[ix][0]*LL + mixd[ix][1]*LR;
chargedSlepton_[ih][il][ix] /=g;
}
}
}
}
}
namespace {
int scalarEigenState(long id) {
if(id<1000000)
return (id-25)/10;
else
return (id-1000008)/2;
}
int pseudoEigenState(long id) {
if(id<1000000)
return 0;
else
return (id-1000016);
}
int chargedEigenState(long id) {
if(abs(id)<1000000)
return 0;
else if(abs(id)<2000000)
return (abs(id)-1000009)/2;
else
return (abs(id)-2000003)/2;
}
}
void RPVSSSVertex::setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
// prefactor
if( q2 != q2Last_ || gLast_==0. ) {
q2Last_ = q2;
gLast_ = weakCoupling(q2);
}
// some ordering of the particles
// sort in order of PDG codes, smallest first
if(abs(part1->id())>abs(part2->id())) swap(part1,part2);
if(abs(part1->id())>abs(part3->id())) swap(part1,part3);
if(abs(part2->id())>abs(part3->id())) swap(part2,part3);
// make sure squarks 2nd and 3rd
if(abs(part1->id())%1000000<=6) swap(part1,part2);
if(abs(part1->id())%1000000<=6) swap(part1,part3);
// extract particle ids
long sca1(part1->id()), sca2(part2->id()), sca3(part3->id());
// Higgs squark couplings
if(abs(sca2)%1000000<=6) {
// charged Higgs
if( part1->charged() ) {
int ih = chargedEigenState(sca1);
if(abs(sca2)%2!=0) swap(sca2,sca3);
unsigned int alpha = abs(sca2)/1000000-1;
unsigned int beta = abs(sca3)/1000000-1;
unsigned int iq = (abs(sca2)%1000000-2)/2;
norm(gLast_*chargedSquark_[ih][iq][alpha][beta]*UnitRemoval::InvE);
return;
}
// neutral Higgs
else {
long sm(0);
// get the left/right light/heavy state
unsigned int alpha(abs(sca2)/1000000 - 1), beta(abs(sca3)/1000000 - 1);
sm = abs(sca2)%1000000;
bool pseudo = sca1==36 || (sca1>=1000017&&sca1<=1000019);
int higgs = pseudo ? pseudoEigenState(sca1) : scalarEigenState(sca1);
complex<Energy> coup;
if(!pseudo) {
if( sm % 2 == 0 ) {
coup = scalarSup_ [higgs][(sm-2)/2][alpha][beta];
}
else {
coup = scalarSdown_[higgs][(sm-1)/2][alpha][beta];
}
}
else {
if( sm % 2 == 0 ) {
coup = pseudoSup_ [higgs][(sm-2)/2];
}
else {
coup = pseudoSdown_[higgs][(sm-1)/2];
}
if((alpha==1&&sca2<0)||(beta==1&&sca3<0)) coup *=-1.;
}
// set coupling and return
norm(gLast_*coup*UnitRemoval::InvE);
return;
}
}
// all neutral
else if(!part1->charged()&&!part2->charged()&&!part3->charged()) {
// neutral Higgs sneutrino
if(scalarScalarScalar_.size()==2&&abs(sca2)>1000000) {
assert(!(sca1==36 || (sca1>=1000017&&sca1<=1000019)));
int il = (abs(sca2)-1000012)/2;
norm(gLast_*scalarSneutrino_[scalarEigenState(sca1)][il]*UnitRemoval::InvE);
return;
}
else {
if(sca1==36 || (sca1>=1000017&&sca2<=1000019)) swap(sca1,sca2);
if(sca1==36 || (sca1>=1000017&&sca2<=1000019)) swap(sca1,sca3);
// 2 pseudoscalar 1 scale
if(sca2==36 || (sca2>=1000017&&sca2<=1000019)) {
norm(gLast_*scalarPseudoPseudo_[scalarEigenState(sca1)]
[pseudoEigenState(sca2)][pseudoEigenState(sca3)]*UnitRemoval::InvE);
return;
}
// 3 scalars
else {
norm(gLast_*scalarScalarScalar_[scalarEigenState(sca1)]
[scalarEigenState(sca2)][scalarEigenState(sca3)]*UnitRemoval::InvE);
return;
}
}
}
// two charged
else {
// put the charged last
if(!part2->charged()) {
swap(part1,part2);
swap(sca1 ,sca2 );
}
if(!part3->charged()) {
swap(part1,part3);
swap(sca1 ,sca3 );
}
// sleptons
if(scalarChargedCharged_[0].size()<5&&abs(sca2)>1000000) {
// neutral Higgs charged sleptons
if((abs(sca2)>=1000011&&abs(sca2)<=1000015&&abs(sca2)%2!=0)&&
(abs(sca3)>=1000011&&abs(sca3)<=1000015&&abs(sca3)%2!=0)) {
long sm(0);
// get the left/right light/heavy state
unsigned int alpha(abs(sca2)/1000000 - 1), beta(abs(sca3)/1000000 - 1);
sm = (abs(sca2)%1000000-11)/2;
bool pseudo = sca1==36 || (sca1>=1000017&&sca1<=1000019);
int higgs = pseudo ? pseudoEigenState(sca1) : scalarEigenState(sca1);
complex<Energy> coup;
if(!pseudo) {
coup = scalarSlepton_[higgs][(sm-1)/2][alpha][beta];
}
else {
coup = pseudoSlepton_[higgs][(sm-1)/2];
if((alpha==1&&sca2<0)||(beta==1&&sca3<0)) coup *=-1.;
}
// set coupling and return
norm(gLast_*coup*UnitRemoval::InvE);
return;
}
// charged Higgs
else {
if(abs(sca2)<1000000) {
swap(part1,part2);
swap(sca1 ,sca2 );
}
if(abs(sca3)<1000000) {
swap(part1,part3);
swap(sca1 ,sca3 );
}
if(part3->charged()) {
swap(part2,part3);
swap(sca2 ,sca3 );
}
unsigned int il = (abs(sca2)%1000000-11)/2;
unsigned int alpha = abs(sca2)/1000000-1;
norm(gLast_*chargedSlepton_[chargedEigenState(sca1)][il][alpha]*UnitRemoval::InvE);
}
}
else {
// pseudoscalar charged charged
if(sca1==36 || (sca1>=1000017&&sca1<=1000019)) {
if(sca2>0) swap(sca2,sca3);
norm(gLast_*pseudoChargedCharged_[pseudoEigenState(sca1)]
[chargedEigenState(sca2)][chargedEigenState(sca3)]*UnitRemoval::InvE);
}
// scalar charged charged
else {
norm(gLast_*scalarChargedCharged_[scalarEigenState(sca1)]
[chargedEigenState(sca2)][chargedEigenState(sca3)]*UnitRemoval::InvE);
}
}
return;
}
}
diff --git a/Models/Susy/RPV/RPVUDDVertex.cc b/Models/Susy/RPV/RPVUDDVertex.cc
--- a/Models/Susy/RPV/RPVUDDVertex.cc
+++ b/Models/Susy/RPV/RPVUDDVertex.cc
@@ -1,149 +1,150 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UDDVertex class.
//
#include "RPVUDDVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
RPVUDDVertex::RPVUDDVertex() {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::EPS);
}
IBPtr RPVUDDVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVUDDVertex::fullclone() const {
return new_ptr(*this);
}
void RPVUDDVertex::persistentOutput(PersistentOStream & os) const {
os << lambda_ << stop_ << sbot_;
}
void RPVUDDVertex::persistentInput(PersistentIStream & is, int) {
is >> lambda_ >> stop_ >> sbot_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<RPVUDDVertex,FFSVertex>
describeHerwigRPVUDDVertex("Herwig::RPVUDDVertex", "HwSusy.so HwRPV.so");
void RPVUDDVertex::Init() {
static ClassDocumentation<RPVUDDVertex> documentation
("The RPVUDDVertex class implements the trilinear UDD"
" coupling in R-parity violating models.");
}
void RPVUDDVertex::doinit() {
RPVPtr rpv = dynamic_ptr_cast<RPVPtr>(generator()->standardModel());
if(!rpv)
throw InitException() << "Must have the RPV model in"
<< " RPVUDDVertex::doinit()"
<< Exception::abortnow;
// get the coupling
lambda_ = rpv->lambdaUDD();
stop_ = rpv->stopMix();
sbot_ = rpv->sbottomMix();
// set the particles in the vertex if coupling non-zero
for( int i=0;i<3;++i) {
for( int j=0; j<3; ++j) {
for( int k=0; k<3; ++k) {
// continue if zero
if(lambda_[i][j][k]==0.) continue;
// particles in the vertex
// right up squark
if(j<k) {
addToList( -2*j-1 , -2*k-1 , -2000002-2*i );
addToList( 2*j+1 , 2*k+1 , +2000002+2*i );
}
if(i==2) {
addToList( -2*j-1 , -2*k-1 , -1000002-2*i );
addToList( 2*j+1 , 2*k+1 , +1000002+2*i );
}
// right down squark
addToList( -2*i-2 , -2*j-1 , -2000001-2*k );
addToList( 2*i+2 , 2*j+1 , +2000001+2*k );
if(k==2) {
addToList( -2*i-2 , -2*j-1 , -1000001-2*k );
addToList( 2*i+2 , 2*j+1 , +1000001+2*k );
}
}
}
}
FFSVertex::doinit();
}
void RPVUDDVertex::setCoupling(Energy2, tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3) {
int islep = part3->id();
int i(-1),j(-1),k(-1);
Complex mix(1.);
// left up squark
if(abs(islep) == ParticleID::SUSY_u_R ||
abs(islep) == ParticleID::SUSY_c_R ||
abs(islep) == ParticleID::SUSY_t_1 ||
abs(islep) == ParticleID::SUSY_t_2) {
if(abs(islep)>2000000) {
i = (abs(islep)-2000002)/2;
if(i==2) mix = (*stop_)(1,1);
}
else {
i = 2;
mix = (*stop_)(0,1);
assert(abs(islep)==ParticleID::SUSY_t_1);
}
j = (abs(part1->id())- 1)/2;
k = (abs(part2->id())- 1)/2;
}
else if(abs(islep) == ParticleID::SUSY_d_R ||
abs(islep) == ParticleID::SUSY_s_R ||
abs(islep) == ParticleID::SUSY_b_1 ||
abs(islep) == ParticleID::SUSY_b_2) {
if(abs(islep)>2000000) {
k = (abs(islep)-2000001)/2;
if(k==2) mix = (*sbot_)(1,1);
}
else {
k = 2;
mix = (*sbot_)(0,1);
assert(abs(islep)==ParticleID::SUSY_b_1);
}
if(abs(part1->id())%2==0) {
i = (abs(part1->id())- 2)/2;
j = (abs(part2->id())- 1)/2;
}
else {
i = (abs(part2->id())- 2)/2;
j = (abs(part1->id())- 1)/2;
// mix *= -1.;
}
}
else
assert(false);
assert( i>=0 && i<=2 && j>=0 && j<=2 && k>=0 && k<=2 );
if(islep>0) {
left (1.);
right(0.);
}
else {
left (0.);
right(1.);
}
norm(mix*lambda_[i][j][k]);
}
diff --git a/Models/Susy/RPV/RPVWSSVertex.cc b/Models/Susy/RPV/RPVWSSVertex.cc
--- a/Models/Susy/RPV/RPVWSSVertex.cc
+++ b/Models/Susy/RPV/RPVWSSVertex.cc
@@ -1,439 +1,440 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RPVWSSVertex class.
//
#include "RPVWSSVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "RPV.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
RPVWSSVertex::RPVWSSVertex() :_sw(0.), _cw(0.), _s2w(0.), _c2w(0.),
_interactions(0), _q2last(),
_ulast(0), _dlast(0), _gblast(0),
_factlast(0.), _couplast(0.) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
IBPtr RPVWSSVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVWSSVertex::fullclone() const {
return new_ptr(*this);
}
void RPVWSSVertex::doinit() {
// extract the model
tRPVPtr model = dynamic_ptr_cast<tRPVPtr>(generator()->standardModel());
if( !model ) throw InitException() << "RPVWSSVertex::doinit() - The"
<< " pointer to the RPV object is null!"
<< Exception::abortnow;
// get the mixing matrices
MixingMatrixPtr mixH = model->CPevenHiggsMix() ;
MixingMatrixPtr mixP = model->CPoddHiggsMix() ;
MixingMatrixPtr mixC = model->ChargedHiggsMix();
// find the codes for the Higgs bosons
vector<long> pseudo(1,36);
vector<long> scalar(2);
vector<long> charged(1,37);
scalar[0] = 25;
scalar[1] = 35;
if(mixH&&mixH->size().first>2) {
scalar.push_back(1000012);
scalar.push_back(1000014);
scalar.push_back(1000016);
}
if(mixP&&mixP->size().first>1) {
pseudo.push_back(1000017);
pseudo.push_back(1000018);
pseudo.push_back(1000019);
}
if(mixC&&mixC->size().first>2) {
charged.push_back(-1000011);
charged.push_back(-1000013);
charged.push_back(-1000015);
charged.push_back(-2000011);
charged.push_back(-2000013);
charged.push_back(-2000015);
}
// sfermion interactions
if(_interactions==0||_interactions==1) {
// squarks
//W-
//LL-squarks
for(long ix=1000001;ix<1000006;ix+=2) {
addToList(-24,ix+1,-ix);
}
//1-2 stop sbottom
addToList(-24,1000006,-2000005);
//2-1 stop sbottom
addToList(-24,2000006,-1000005);
//2-2 stop sbottom
addToList(-24,2000006,-2000005);
//W+
for(long ix=1000001;ix<1000006;ix+=2) {
addToList(24,-(ix+1),ix);
}
//1-2 stop sbottom
addToList(24,-1000006,2000005);
//2-1 stop sbottom
addToList(24,-2000006,1000005);
//2-2 stop sbottom
addToList(24,-2000006,2000005);
//LL squarks
for(long ix=1000001;ix<1000007;++ix) {
addToList(23,ix,-ix);
}
//RR squarks
for(long ix=2000001;ix<2000007;++ix) {
addToList(23,ix,-ix);
}
//L-Rbar stop
addToList(23,1000006,-2000006);
//Lbar-R stop
addToList(23,-1000006,2000006);
//L-Rbar sbottom
addToList(23,1000005,-2000005);
//Lbar-R sbottom
addToList(23,-1000005,2000005);
// gamma
//squarks
for(long ix=1000001;ix<1000007;++ix) {
addToList(22,ix,-ix);
}
for(long ix=2000001;ix<2000007;++ix) {
addToList(22,ix,-ix);
}
//sleptons
// gamma
for(long ix=1000011;ix<1000016;ix+=2) {
addToList(22,ix,-ix);
}
for(long ix=2000011;ix<2000016;ix+=2) {
addToList(22,ix,-ix);
}
// Z
//LL-sleptons
for(long ix=1000011;ix<1000017;ix+=2) {
addToList(23,ix,-ix);
}
// RR-sleptons
for(long ix=2000011;ix<2000016;ix+=2) {
addToList(23,ix,-ix);
}
//L-Rbar stau
addToList(23,1000015,-2000015);
//Lbar-R stau
addToList(23,-1000015,2000015);
if(!(mixH&&mixH->size().first>2)) {
for(long ix=1000012;ix<1000017;ix+=2) {
// sneutrinos
addToList(23,ix,-ix);
}
//LL-sleptons
for(long ix=1000011;ix<1000016;ix+=2) {
addToList(-24,-ix,ix+1);
}
//2-L stau
addToList(-24,-2000015,1000016);
//LL-sleptons
for(long ix=1000011;ix<1000016;ix+=2) {
addToList(24,ix,-ix-1);
}
//2-L stau
addToList(24,2000015,-1000016);
}
}
if(_interactions==0||_interactions==2) {
// charged Higgs and photon
addToList(22,37,-37);
// charged Higgs and Z
for(unsigned int ix=0;ix<charged.size();++ix) {
for(unsigned int iy=0;iy<charged.size();++iy) {
if(abs(charged[ix])>1000000&&abs(charged[iy])>100000 &&
( charged[ix]==charged[iy] ||
(abs(charged[ix])%1000000==15&&abs(charged[iy])%1000000==15)))
continue;
addToList(23,charged[ix],-charged[iy]);
}
}
// neutral Higgs and Z
for(unsigned int ix=0;ix<scalar.size();++ix) {
for(unsigned int iy=0;iy<pseudo.size();++iy) {
addToList(23,scalar[ix],pseudo[iy]);
}
}
// charged higss, scalar higgs and W
for(unsigned int ix=0;ix<charged.size();++ix) {
for(unsigned int iy=0;iy<scalar.size();++iy) {
addToList( 24,-charged[ix],scalar[iy]);
addToList(-24, charged[ix],scalar[iy]);
}
}
// charged higss, pseudoscalar higgs and W
for(unsigned int ix=0;ix<charged.size();++ix) {
for(unsigned int iy=0;iy<pseudo.size();++iy) {
addToList( 24,-charged[ix],pseudo[iy]);
addToList(-24, charged[ix],pseudo[iy]);
}
for(unsigned int iy=0;iy<scalar.size();++iy) {
addToList( 24,-charged[ix],scalar[iy]);
addToList(-24, charged[ix],scalar[iy]);
}
}
}
VSSVertex::doinit();
// sfermion mixing
_stop = model->stopMix();
_sbottom = model->sbottomMix();
if(!_stop || !_sbottom)
throw InitException() << "RPVWSSVertex::doinit() - "
<< "A mixing matrix pointer is null."
<< " stop: " << _stop << " sbottom: " << _sbottom
<< Exception::abortnow;
_stau = model->stauMix();
if(!_stau && (!mixC || mixC->size().first<2))
throw InitException() << "RPVWSSVertex::doinit() either the stau"
<< " mixing matrix must be set or the stau"
<< " included in mixing with the"
<< " charged Higgs bosons" << Exception::abortnow;
// weak mixing
_sw = sqrt(sin2ThetaW());
_cw = sqrt( 1. - sin2ThetaW() );
_s2w = 2.*_cw*_sw;
_c2w = 1. - 2.*sin2ThetaW();
// Coupling of Z to scalar and pseudoscalar
Cijeo_.resize(pseudo.size(),vector<Complex>(scalar.size(),0.));
for(unsigned int i=0;i<pseudo.size();++i) {
for(unsigned int j=0;j<scalar.size();++j) {
for(unsigned int ix=0;ix<mixH->size().second;++ix) {
double sign = ix!=1 ? 1. : -1.;
Cijeo_[i][j] += sign*(*mixP)(i,ix)*(*mixH)(j,ix);
}
}
}
// Coupling of W to scalar charged
Cijec_.resize(scalar.size(),vector<Complex>(charged.size(),0.));
for(unsigned int i=0;i<scalar.size();++i) {
for(unsigned int j=0;j<charged.size();++j) {
for(unsigned int ix=0;ix<mixH->size().second;++ix) {
double sign = ix!=1 ? 1. : -1.;
Cijec_[i][j] += sign*(*mixH)(i,ix)*(*mixC)(j,ix);
}
}
}
// Coupling of W to pseudopseudo charged
Cijco_.resize(pseudo.size(),vector<Complex>(charged.size(),0.));
for(unsigned int i=0;i<pseudo.size();++i) {
for(unsigned int j=0;j<charged.size();++j) {
for(unsigned int ix=0;ix<mixP->size().second;++ix) {
// not sure about this need it to get agreement with SPheno
//double sign = ix!=1 ? 1. : -1.;
double sign = 1.;
Cijco_[i][j] += sign*(*mixP)(i,ix)*(*mixC)(j,ix);
}
}
}
// Coupling of Z to charged Higgs
Cijc_.resize(charged.size(),vector<Complex>(charged.size(),0.));
for(unsigned int i=0;i<charged.size();++i) {
for(unsigned int j=0;j<charged.size();++j) {
for(unsigned int ix=5;ix<mixC->size().second;++ix) {
Cijc_[i][j] += (*mixC)(i,ix)*(*mixC)(j,ix);
}
}
}
}
void RPVWSSVertex::persistentOutput(PersistentOStream & os) const {
os << _interactions << _sw << _cw
<< _stau << _stop << _sbottom << _s2w << _c2w
<< Cijeo_ << Cijec_ << Cijco_ << Cijc_;
}
void RPVWSSVertex::persistentInput(PersistentIStream & is, int) {
is >> _interactions >> _sw >> _cw
>> _stau >> _stop >> _sbottom >> _s2w >> _c2w
>> Cijeo_ >> Cijec_ >> Cijco_ >> Cijc_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RPVWSSVertex,Helicity::VSSVertex>
describeHerwigRPVWSSVertex("Herwig::RPVWSSVertex", "HwSusy.so HwRPV.so");
void RPVWSSVertex::Init() {
static ClassDocumentation<RPVWSSVertex> documentation
("There is no documentation for the RPVWSSVertex class");
static Switch<RPVWSSVertex,unsigned int> interfaceInteractions
("Interactions",
"Which interactions to include",
&RPVWSSVertex::_interactions, 0, false, false);
static SwitchOption interfaceInteractionsAll
(interfaceInteractions,
"All",
"Include both the interactions which would have been sfermion"
" and Higgs bosons with the gauge bosons in the MSSM",
0);
static SwitchOption interfaceInteractionsSfermions
(interfaceInteractions,
"Sfermions",
"Include the sfermion interactions",
1);
static SwitchOption interfaceInteractionsHiggs
(interfaceInteractions,
"Higgs",
"Include the Higgs boson interactions",
2);
}
void RPVWSSVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
long gboson = part1->id();
assert( gboson == ParticleID::Z0 ||
gboson == ParticleID::gamma ||
abs(gboson) == ParticleID::Wplus );
long h1ID = part2->id();
long h2ID = part3->id();
// squarks and sleptons
if(((abs(h1ID)>=1000001&&abs(h1ID)<=1000006)||
(abs(h1ID)>=2000001&&abs(h1ID)<=2000006)) ||
(((abs(h1ID)>=1000011&&abs(h1ID)<=1000016)||
(abs(h1ID)>=2000011&&abs(h1ID)<=2000016))&&
Cijeo_.size()==1)) {
long sf1(abs(part2->id())),sf2(abs(part3->id()));
if( sf1 % 2 != 0 ) swap(sf1, sf2);
if( sf1 != _ulast || sf2 != _dlast || gboson != _gblast) {
_gblast = gboson;
_ulast = sf1;
_dlast = sf2;
//photon is simplest
if( gboson == ParticleID::gamma )
_factlast = getParticleData(sf1)->charge()/eplus;
else {
//determine which helicity state
unsigned int alpha(sf1/1000000 - 1), beta(sf2/1000000 - 1);
//mixing factors
Complex m1a(0.), m1b(0.);
if( sf1 == ParticleID::SUSY_t_1 || sf1 == ParticleID::SUSY_t_2 )
m1a = (*_stop)(alpha, 0);
else if( sf1 == ParticleID::SUSY_b_1 || sf1 == ParticleID::SUSY_b_2 )
m1a = (*_sbottom)(alpha, 0);
else if( sf1 == ParticleID::SUSY_tau_1minus ||
sf1 == ParticleID::SUSY_tau_2minus )
m1a = (*_stau)(alpha, 0);
else
m1a = (alpha == 0) ? Complex(1.) : Complex(0.);
if( sf2 == ParticleID::SUSY_t_1 || sf2 == ParticleID::SUSY_t_2 )
m1b = (*_stop)(beta, 0);
else if( sf2 == ParticleID::SUSY_b_1 || sf2 == ParticleID::SUSY_b_2 )
m1b = (*_sbottom)(beta, 0);
else if( sf2 == ParticleID::SUSY_tau_1minus ||
sf2 == ParticleID::SUSY_tau_2minus )
m1b = (*_stau)(beta, 0);
else
m1b = (beta == 0) ? Complex(1.) : Complex(0.);
//W boson
if( abs(gboson) == ParticleID::Wplus ) {
_factlast = m1a*m1b/sqrt(2)/_sw;
}
//Z boson
else {
if( sf1 == ParticleID::SUSY_nu_eL || sf1 == ParticleID::SUSY_nu_muL ||
sf1 == ParticleID::SUSY_nu_tauL ) {
_factlast = 1./_cw/2./_sw;
}
else {
double lmda(1.);
if( sf2 % 2 == 0 ) lmda = -1.;
_factlast = lmda*m1a*m1b;
if( alpha == beta) {
double ef = getParticleData(sf1)->charge()/eplus;
_factlast += 2.*ef*sqr(_sw);
}
_factlast *= -1./2./_cw/_sw;
}
}
}
}
}
// Higgs bosons
else {
_gblast = gboson;
_ulast = h1ID;
_dlast = h2ID;
_factlast = 0.;
if( gboson == ParticleID::Z0 ) {
if( part2->charged() ) {
unsigned int c1 = abs(h1ID) < 1000000 ? 0 :
(abs(h1ID) < 2000000 ? (abs(h1ID)-1000009)/2 : (abs(h1ID)-2000003)/2);
unsigned int c2 = abs(h2ID) < 1000000 ? 0 :
(abs(h2ID) < 2000000 ? (abs(h2ID)-1000009)/2 : (abs(h2ID)-2000003)/2);
if(c1==c2) _factlast = (_c2w-Cijc_[c1][c2])/_s2w;
else _factlast = -Cijc_[c1][c2]/_s2w;
if(part2->iCharge()<0) _factlast *= -1.;
}
else {
if(h1ID == ParticleID::h0 || h1ID == ParticleID::H0 ||
h1ID == ParticleID::SUSY_nu_eL || h1ID == ParticleID::SUSY_nu_muL ||
h1ID == ParticleID::SUSY_nu_tauL ) {
unsigned int is = h1ID < 1000000 ? (h1ID-25)/10 : (h1ID-1000008)/2;
unsigned int ip = h2ID < 1000000 ? 0 : (h2ID-1000016);
_factlast = Complex(0.,1.)*Cijeo_[ip][is]/_s2w;
}
else {
unsigned int is = h2ID < 1000000 ? (h2ID-25)/10 : (h2ID-1000008)/2;
unsigned int ip = h1ID < 1000000 ? 0 : (h1ID-1000016);
_factlast = -Complex(0.,1.)*Cijeo_[ip][is]/_s2w;
}
}
}
else if( gboson == ParticleID::gamma ) {
_factlast = part2->iCharge()/3;
}
else {
long scalar = part2->charged() ? h2ID : h1ID;
long charged = part2->charged() ? h1ID : h2ID;
unsigned int ic = abs(charged) < 1000000 ? 0 :
(abs(charged) < 2000000 ? (abs(charged)-1000009)/2 : (abs(charged)-2000003)/2);
if(scalar == ParticleID::h0 || scalar == ParticleID::H0 ||
scalar == ParticleID::SUSY_nu_eL || scalar == ParticleID::SUSY_nu_muL ||
scalar == ParticleID::SUSY_nu_tauL ) {
unsigned int ih = scalar < 1000000 ? (scalar-25)/10 : (scalar-1000008)/2;
_factlast = -0.5*Cijec_[ih][ic]/_sw;
if(gboson<0) _factlast *= -1.;
}
else {
unsigned int ih = scalar < 1000000 ? 0 : (scalar-1000016);
_factlast = Complex(0., 0.5)*Cijco_[ih][ic]/_sw;
}
if(part3->charged()) _factlast *= -1.;
}
}
if( q2 != _q2last || _couplast==0. ) {
_q2last = q2;
_couplast = electroMagneticCoupling(q2);
}
if(part2->id()>0)
norm(-_couplast*_factlast);
else
norm(+_couplast*_factlast);
}
diff --git a/Models/Susy/RPV/RPVWWHVertex.cc b/Models/Susy/RPV/RPVWWHVertex.cc
--- a/Models/Susy/RPV/RPVWWHVertex.cc
+++ b/Models/Susy/RPV/RPVWWHVertex.cc
@@ -1,109 +1,110 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the RPVWWHVertex class.
//
#include "RPVWWHVertex.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 "RPV.h"
using namespace Herwig;
RPVWWHVertex::RPVWWHVertex() : coupLast_(ZERO), q2Last_(ZERO) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void RPVWWHVertex::doinit() {
// extract some models parameters to decide if we need sneutrinos
tRPVPtr model = dynamic_ptr_cast<tRPVPtr>(generator()->standardModel());
if( !model ) throw InitException() << "RPVWWHVertex::doinit() - "
<< "The pointer to the RPV object is null!"
<< Exception::abortnow;
// get the Higgs mixing matrix
MixingMatrixPtr mix = model->CPevenHiggsMix();
// possible interactions
vector<long> higgs(2);
higgs[0] = 25; higgs[1] = 35;
if(mix->size().first>2) {
higgs.push_back(1000012);
higgs.push_back(1000014);
higgs.push_back(1000016);
}
for(unsigned int ix=0;ix<higgs.size();++ix) {
addToList( 23, 23,higgs[ix]);
addToList(-24, 24,higgs[ix]);
}
VVSVertex::doinit();
// SM parameters
Energy mw = getParticleData(ParticleID::Wplus)->mass();
Energy mz = getParticleData(ParticleID::Z0)->mass();
double sw = sqrt(sin2ThetaW());
double cw = sqrt(1.-sin2ThetaW());
vector<Energy> vnu = model->sneutrinoVEVs();
Energy v = 2.*mw/electroMagneticCoupling(sqr(mw))*sw;
double tanb = model->tanBeta();
Energy vd = sqrt((sqr(v)-sqr(vnu[0])-sqr(vnu[1])-sqr(vnu[2]))/
(1.+sqr(tanb)));
Energy vu = vd*tanb;
for(unsigned int ix=0;ix<higgs.size();++ix) {
complex<Energy> c = vd*(*mix)(ix,0)+vu*(*mix)(ix,1);
for(size_t iy=2; iy<mix->size().second; ++iy) c += vnu[iy-2]*(*mix)(ix,iy);
vector<complex<Energy> > coup(2);
coup[0] = c/v*mw;
coup[1] = c/v*mz/cw;
couplings_.push_back(coup);
}
}
IBPtr RPVWWHVertex::clone() const {
return new_ptr(*this);
}
IBPtr RPVWWHVertex::fullclone() const {
return new_ptr(*this);
}
void RPVWWHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(couplings_,GeV);
}
void RPVWWHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(couplings_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<RPVWWHVertex,Helicity::VVSVertex>
describeHerwigRPVWWHVertex("Herwig::RPVWWHVertex", "HwSusy.so HwRPV.so");
void RPVWWHVertex::Init() {
static ClassDocumentation<RPVWWHVertex> documentation
("The RPVWWHVertex class implements the couplings of a pair of electroweak"
" gauge bosons to the higgs boson in he R-parity violating MSSM.");
}
void RPVWWHVertex::setCoupling(Energy2 q2, tcPDPtr particle1, tcPDPtr,
tcPDPtr particle3) {
long bosonID = abs(particle1->id());
long higgsID = particle3->id();
assert( bosonID == ParticleID::Wplus || bosonID == ParticleID::Z0 );
int ihiggs = higgsID>1000000 ? (higgsID-1000008)/2 : (higgsID-25)/10;
assert(ihiggs>=0 && ihiggs<=4);
complex<Energy> fact = bosonID==ParticleID::Wplus ?
couplings_[ihiggs][0] : couplings_[ihiggs][1];
if( q2 != q2Last_ ) {
q2Last_ = q2;
coupLast_ = weakCoupling(q2);
}
norm(coupLast_*fact*UnitRemoval::InvE);
}
diff --git a/Models/Susy/SSCCZVertex.cc b/Models/Susy/SSCCZVertex.cc
--- a/Models/Susy/SSCCZVertex.cc
+++ b/Models/Susy/SSCCZVertex.cc
@@ -1,127 +1,128 @@
// -*- C++ -*-
//
// SSCCZVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSCCZVertex class.
//
#include "SSCCZVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSCCZVertex::SSCCZVertex() : _sw2(0.), _cw(0.), _couplast(0.),
_q2last(), _id1last(0), _id2last(0),
_leftlast(0.), _rightlast(0.), _gblast(0) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
void SSCCZVertex::doinit() {
addToList(-1000024, 1000024, 23);
addToList(-1000024, 1000037, 23);
addToList(-1000037, 1000024, 23);
addToList(-1000037, 1000037, 23);
//photon
addToList(-1000024, 1000024, 22);
addToList(-1000037, 1000037, 22);
FFVVertex::doinit();
tSusyBasePtr theSS = dynamic_ptr_cast<SusyBasePtr>(generator()->standardModel());
if(!theSS)
throw InitException() << "SSCCZVertex::doinit - The model pointer "
<< "is null! "
<< Exception::abortnow;
_sw2 = sin2ThetaW();
_cw = sqrt(1. - _sw2);
_theU = theSS->charginoUMix();
_theV = theSS->charginoVMix();
if(!_theU || !_theV)
throw InitException() << "SSCCZVertex::doinit - "
<< "A mixing matrix pointer is null. U: "
<< _theU << " V: " << _theV
<< Exception::abortnow;
}
void SSCCZVertex::persistentOutput(PersistentOStream & os) const {
os << _sw2 << _cw << _theU << _theV;
}
void SSCCZVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw2 >> _cw >> _theU >> _theV;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSCCZVertex,Helicity::FFVVertex>
describeSSCCZVertex("Herwig::SSCCZVertex", "HwSusy.so");
void SSCCZVertex::Init() {
static ClassDocumentation<SSCCZVertex> documentation
("This class implements the coupling of a Z/gamma to a pair of"
" charginos. ");
}
void SSCCZVertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long ichar1(part1->id()), ichar2(part2->id()), boson(part3->id());
assert( boson == ParticleID::gamma || boson == ParticleID::Z0);
assert( abs(ichar1) == 1000024 || abs(ichar1) == 1000037);
assert( abs(ichar2) == 1000024 || abs(ichar2) == 1000037);
if(_q2last != q2||_couplast==0.) {
_q2last = q2;
_couplast = electroMagneticCoupling(q2);
}
norm(_couplast);
if(boson != _gblast || ichar1 != _id1last || ichar2 != _id2last) {
_gblast = boson;
_id1last = ichar1;
_id2last = ichar2;
if( boson == ParticleID::Z0 ) {
unsigned int ic1(0), ic2(0);
if(abs(ichar1) == 1000037) ic1 = 1;
if(abs(ichar2) == 1000037) ic2 = 1;
_leftlast = -(*_theV)(ic1, 0)*conj((*_theV)(ic2, 0)) -
0.5*(*_theV)(ic1, 1)*conj((*_theV)(ic2, 1));
_rightlast = -conj((*_theU)(ic1, 0))*(*_theU)(ic2, 0) -
0.5*conj((*_theU)(ic1, 1))*(*_theU)(ic2, 1);
if(abs(ichar1) == abs(ichar2)) {
_leftlast += _sw2;
_rightlast += _sw2;
}
_leftlast /= sqrt(_sw2)*_cw;
_rightlast /= sqrt(_sw2)*_cw;
}
else {
if(abs(ichar1) == abs(ichar2)) {
_leftlast = -1.;
_rightlast = -1.;
}
else {
_leftlast = 0.;
_rightlast = 0.;
}
}
if(ichar1>0) {
Complex temp = _leftlast;
_leftlast = -_rightlast;
_rightlast = -temp;
}
}
left(_leftlast);
right(_rightlast);
}
diff --git a/Models/Susy/SSCFSVertex.cc b/Models/Susy/SSCFSVertex.cc
--- a/Models/Susy/SSCFSVertex.cc
+++ b/Models/Susy/SSCFSVertex.cc
@@ -1,237 +1,238 @@
// -*- C++ -*-
//
// SSCFSVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSCFSVertex class.
//
#include "SSCFSVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSCFSVertex::SSCFSVertex(): _sb(0.),_cb(0.),_mw(ZERO),
_q2last(0.*GeV2), _couplast(0.),
_leftlast(0.),_rightlast(0.),
_id1last(0), _id2last(0), _id3last(0),
yukawa_(1) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SSCFSVertex::doinit() {
long chargino[2] = {1000024, 1000037};
for(unsigned int ic = 0; ic < 2; ++ic) {
//quarks
for(long ix = 1; ix < 7; ++ix) {
if( ix % 2 == 0 ) {
addToList(-chargino[ic],ix,-(999999+ix));
addToList(-chargino[ic],ix,-(1999999+ix));
addToList(-ix,chargino[ic],(999999+ix));
addToList(-ix,chargino[ic],(1999999+ix));
}
else {
addToList(-chargino[ic],-ix,(1000001+ix));
addToList(-chargino[ic],-ix,2000001+ix);
addToList(chargino[ic],ix,-(1000001+ix));
addToList(chargino[ic],ix,-(2000001+ix));
}
}
//leptons
for(long ix = 11; ix < 17; ++ix) {
if( ix % 2 == 0 ) {
addToList(-chargino[ic],ix,-(999999+ix));
addToList(-chargino[ic],ix,-(1999999+ix));
addToList(-ix,chargino[ic],(999999+ix));
addToList(-ix,chargino[ic],(1999999+ix));
}
else {
addToList(-chargino[ic],-ix,1000001+ix);
addToList(chargino[ic],ix,-(1000001+ix));
}
}
}
FFSVertex::doinit();
_theSS = dynamic_ptr_cast<MSSMPtr>(generator()->standardModel());
//mixing matrices
_stop = _theSS->stopMix();
_sbot = _theSS->sbottomMix();
_stau = _theSS->stauMix();
_umix = _theSS->charginoUMix();
_vmix = _theSS->charginoVMix();
if(!_stop || !_stau || !_sbot || !_umix || !_vmix)
throw InitException() << "SSCFSVertex:: doinit - "
<< "A mixing matrix pointer is null."
<< " stop: " << _stop << " sbottom: " << _sbot
<< " stau: " << _stau << " U: " << _umix
<< " V:" << _vmix
<< Exception::abortnow;
_mw = getParticleData(24)->mass();
double tb = _theSS->tanBeta();
_sb = tb/sqrt(1 + sqr(tb));
_cb = sqrt(1.- sqr(_sb));
}
void SSCFSVertex::persistentOutput(PersistentOStream & os) const {
os << _theSS << _sb << _cb << ounit(_mw,GeV) << _stop
<< _sbot << _stau << _umix << _vmix << yukawa_;
}
void SSCFSVertex::persistentInput(PersistentIStream & is, int) {
is >> _theSS >> _sb >> _cb >> iunit(_mw,GeV) >> _stop
>> _sbot >> _stau >> _umix >> _vmix >> yukawa_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSCFSVertex,FFSVertex>
describeHerwigSSCFSVertex("Herwig::SSCFSVertex", "HwSusy.so");
void SSCFSVertex::Init() {
static ClassDocumentation<SSCFSVertex> documentation
("The implementation of the coupling of the charginos to fermion-"
"sfermions.");
static Switch<SSCFSVertex,unsigned int> interfaceYukawa
("Yukawa",
"Whether or not to include the Yukawa type couplings",
&SSCFSVertex::yukawa_, true, false, false);
static SwitchOption interfaceYukawaYes
(interfaceYukawa,
"Yes",
"Include the terms",
1);
static SwitchOption interfaceYukawaNo
(interfaceYukawa,
"No",
"Don't include them",
0);
static SwitchOption interfaceYukawa3rdGen
(interfaceYukawa,
"ThirdGeneration",
"Only include them for the third generation",
2);
}
void SSCFSVertex::setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
long isc(abs(part3->id())), ism(abs(part1->id())),
ichg(abs(part2->id()));
tcPDPtr smfermion = part1;
if( ism / 1000000 == 1 ) {
swap( ism, ichg);
smfermion = part2;
}
//overall normalisation
if(q2!=_q2last||_couplast==0.) {
_q2last=q2;
_couplast = -weakCoupling(q2);
}
norm(_couplast);
if( ichg != _id1last || ism != _id2last || isc != _id3last ) {
_id1last = ichg;
_id2last = ism;
_id3last = isc;
// determine chargino and sfermion eigenstates
unsigned int alpha(isc/1000000 - 1);
unsigned int ch = (ichg == 1000024 ) ? 0 : 1;
Complex ul1 = (*_umix)(ch,0);
Complex ul2 = (*_umix)(ch,1);
Complex vl1 = (*_vmix)(ch,0);
Complex vl2 = (*_vmix)(ch,1);
if( ism >= 11 && ism <= 16 ) {
long lept = ( ism % 2 == 0 ) ? ism - 1 : ism;
double y = 0.;
if(yukawa_==1 || (lept==15 && yukawa_==2))
y = double(_theSS->mass(q2, getParticleData(lept))/_mw/sqrt(2)/_cb);
if( ism == 12 || ism == 14 ) {
_leftlast = Complex(0., 0.);
if( alpha == 0 )
_rightlast = ul1;
else
_rightlast = -y*ul2;
}
else if( ism == 16 ) {
_leftlast = Complex(0., 0.);
_rightlast = ul1*(*_stau)(alpha, 0) - y*(*_stau)(alpha,1)*ul2;
}
else if( ism == 11 || ism == 13 || ism == 15 ) {
_leftlast = -y*conj(ul2);
_rightlast = vl1;
}
}
else {
double yd(0.), yu(0.);
if(yukawa_==1 || ((ism==5 || ism==6 ) && yukawa_==2)) {
if( ism % 2 == 0) {
yu = _theSS->mass(q2, getParticleData(ism))/_mw/sqrt(2)/_sb;
yd = _theSS->mass(q2, getParticleData(ism - 1))/_mw/sqrt(2)/_cb;
}
else {
yu = _theSS->mass(q2, getParticleData(ism + 1))/_mw/sqrt(2)/_sb;
yd = _theSS->mass(q2, getParticleData(ism))/_mw/sqrt(2)/_cb;
}
}
//heavy quarks
if( ism == 5 ) {
_leftlast = -yd*conj(ul2)*(*_stop)(alpha,0);
_rightlast = vl1*(*_stop)(alpha, 0) - yu*vl2*(*_stop)(alpha,1);
}
else if( ism == 6 ) {
_leftlast = -yu*conj(vl2)*(*_sbot)(alpha,0);
_rightlast = ul1*(*_sbot)(alpha, 0) - yd*ul2*(*_sbot)(alpha,1);
}
else {
if( alpha == 0 ) {
_leftlast = (ism % 2 == 0) ? -yu*conj(vl2) : -yd*conj(ul2);
_rightlast = (ism % 2 == 0) ? ul1 : vl1;
}
else {
_leftlast = Complex(0.);
_rightlast = (ism % 2 == 0) ? -yd*ul2 : -yu*vl2;
}
}
}
}//end of coupling calculation
//determine the helicity order of the vertex
if( smfermion->id() < 0 ) {
left(conj(_rightlast));
right(conj(_leftlast));
}
else {
left(_leftlast);
right(_rightlast);
}
}
diff --git a/Models/Susy/SSCNWVertex.cc b/Models/Susy/SSCNWVertex.cc
--- a/Models/Susy/SSCNWVertex.cc
+++ b/Models/Susy/SSCNWVertex.cc
@@ -1,131 +1,132 @@
// -*- C++ -*-
//
// SSCNWVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSCNWVertex class.
//
#include "SSCNWVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSCNWVertex::SSCNWVertex() : _sw(0.), _couplast(0.), _q2last(ZERO),
_id1last(0), _id2last(0), _leftlast(0.),
_rightlast(0.) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
void SSCNWVertex::doinit() {
long neu[] = { 1000022, 1000023, 1000025, 1000035, 1000045 };
long cha[] = { 1000024, 1000037 };
// sign == -1 outgoing W-, sign == +1 outgoing W+
for(int sign = -1; sign < 2; sign += 2)
for(unsigned int ine = 0; ine < 5; ++ine)
for(unsigned int ic = 0; ic < 2; ++ic)
addToList(-sign*cha[ic], neu[ine], sign*24);
FFVVertex::doinit();
tSusyBasePtr theSS = dynamic_ptr_cast<SusyBasePtr>(generator()->standardModel());
if(!theSS)
throw InitException() << "SSCNWVertex::doinit() - The model pointer is null!"
<< Exception::abortnow;
_sw = sqrt(sin2ThetaW());
_theN = theSS->neutralinoMix();
_theU = theSS->charginoUMix();
_theV = theSS->charginoVMix();
if(!_theN || !_theU || ! _theV)
throw InitException() << "SSCNWVertex::doinit() - "
<< "A mixing matrix pointer is null."
<< " N: " << _theN << " U: " << _theU << " V: "
<< _theV << Exception::abortnow;
}
void SSCNWVertex::persistentOutput(PersistentOStream & os) const {
os << _sw << _theN << _theU << _theV;
}
void SSCNWVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw >> _theN >> _theU >> _theV;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSCNWVertex,Helicity::FFVVertex>
describeSSCNWVertex("Herwig::SSCNWVertex", "HwSusy.so");
void SSCNWVertex::Init() {
static ClassDocumentation<SSCNWVertex> documentation
("This class implements the coupling of a W boson to a "
"neutralino and a chargino");
}
void SSCNWVertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
#ifndef NDEBUG
tcPDPtr part3) {
#else
tcPDPtr) {
#endif
assert(abs(part3->id()) == ParticleID::Wplus);
long neu, cha;
if(part1->charged()) {
cha = part1->id();
neu = part2->id();
}
else {
cha = part2->id();
neu = part1->id();
}
assert((abs(cha) == 1000024 || abs(cha) == 1000037) &&
(neu == 1000022 || neu == 1000023 ||
neu == 1000025 || neu == 1000035 ||
neu == 1000045) );
if(q2 != _q2last||_couplast==0.) {
_q2last = q2;
_couplast = weakCoupling(q2);
}
norm(_couplast);
if(cha != _id1last || neu != _id2last) {
_id1last = cha;
_id2last = neu;
unsigned int eigc = abs(cha) == 1000037 ? 1 : 0;
unsigned int eign(0);
if (neu == 1000023) eign = 1;
else if(neu == 1000025) eign = 2;
else if(neu == 1000035) eign = 3;
else if(neu == 1000045) eign = 4;
_leftlast = (*_theN)(eign, 1)*conj((*_theV)(eigc, 0)) -
( (*_theN)(eign, 3)*conj((*_theV)(eigc, 1))/sqrt(2));
_rightlast = conj((*_theN)(eign, 1))*(*_theU)(eigc, 0) +
( conj((*_theN)(eign, 2))*(*_theU)(eigc, 1)/sqrt(2));
}
Complex ltemp = _leftlast;
Complex rtemp = _rightlast;
// conjugate if +ve chargino
if(cha>0) {
ltemp = conj(ltemp);
rtemp = conj(rtemp);
}
if((part1->id()==cha&&cha>0)||(part2->id()==cha&&cha<0)) {
Complex temp = ltemp;
ltemp = -rtemp;
rtemp = -temp;
}
left (ltemp);
right(rtemp);
}
diff --git a/Models/Susy/SSFFHVertex.cc b/Models/Susy/SSFFHVertex.cc
--- a/Models/Susy/SSFFHVertex.cc
+++ b/Models/Susy/SSFFHVertex.cc
@@ -1,159 +1,160 @@
// -*- C++ -*-
//
// SSFFHVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSFFHVertex class.
//
#include "SSFFHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include <cassert>
using namespace ThePEG::Helicity;
using namespace Herwig;
SSFFHVertex::SSFFHVertex() : thetanb(0.0), theMw(ZERO),
theSa(0.0), theSb(0.0),
theCa(0.0), theCb(0.0),
theFLast(make_pair(0,0)), theGlast(0.),
theq2last(), theMassLast(make_pair(ZERO,ZERO)) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SSFFHVertex::doinit() {
int higgs[] = { 25, 35, 36 };
for ( long h = 0; h < 3; ++h ) {
//neutral higgs
// quarks
for(long ix=1;ix<7;++ix)
addToList(-ix,ix,higgs[h]);
// charged leptons
for(long ix=11;ix<16;ix+=2)
addToList(-ix,ix,higgs[h]);
}
for(long ix=1;ix<6;ix+=2) {
//outgoing H+
addToList(-ix-1, ix, 37);
//outgoing H-
addToList(-ix ,ix+1,-37);
}
for(long ix=11;ix<16;ix+=2) {
//outgoing H+
addToList(-ix-1, ix, 37);
//outgoing H-
addToList(-ix ,ix+1,-37);
}
theMSSM = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !theMSSM )
throw InitException()
<< "SSFFHVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
theMw = getParticleData(ParticleID::Wplus)->mass();
thetanb = theMSSM->tanBeta();
theSb = thetanb/sqrt(1. + sqr(thetanb));
theCb = sqrt( 1. - sqr(theSb) );
theSa = sin(theMSSM->higgsMixingAngle());
theCa = sqrt(1. - sqr(theSa));
FFSVertex::doinit();
}
void SSFFHVertex::persistentOutput(PersistentOStream & os) const {
os << theMSSM << thetanb << ounit(theMw,GeV) << theSa
<< theSb << theCa << theCb;
}
void SSFFHVertex::persistentInput(PersistentIStream & is, int) {
is >> theMSSM >> thetanb >> iunit(theMw,GeV) >> theSa
>> theSb >> theCa >> theCb;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSFFHVertex,FFSVertex>
describeHerwigSSFFHVertex("Herwig::SSFFHVertex", "HwSusy.so");
void SSFFHVertex::Init() {
static ClassDocumentation<SSFFHVertex> documentation
("The coupling of the higgs bosons to SM fermions in the MSSM");
}
void SSFFHVertex::setCoupling(Energy2 q2, tcPDPtr particle1,
tcPDPtr particle2,tcPDPtr particle3) {
long f1ID(abs(particle1->id())), f2ID(abs(particle2->id())),
higgsID(particle3->id());
// check higgs
assert( higgsID == ParticleID::h0 || higgsID == ParticleID::H0 ||
higgsID == ParticleID::A0 || abs(higgsID) == ParticleID::Hplus );
// check fermions
assert(!( ((f1ID > 6 && f1ID < 11) || f1ID > 16 ) ||
((f2ID > 6 && f1ID < 11) || f2ID > 16 ) ));
if( q2 != theq2last || theGlast==0.) {
theGlast = weakCoupling(q2);
}
if( q2 != theq2last || theFLast.first != f1ID) {
theMassLast.first = theMSSM->mass(q2,particle1);
theFLast.first = f1ID;
}
if( q2 != theq2last || theFLast.second != f2ID) {
theMassLast.second = theMSSM->mass(q2,particle2);
theFLast.second = f2ID;
}
theq2last = q2;
Complex coup(0.);
Complex lcoup(1.),rcoup(1.);
if( higgsID == ParticleID::h0 || higgsID == ParticleID::H0 ||
higgsID == ParticleID::A0 ) {
coup = 0.5*theMassLast.first/theMw;
if( higgsID == ParticleID::h0 ) {
if( f1ID % 2 == 0 )
coup *= -theCa/theSb;
else
coup *= theSa/theCb;
}
else if( higgsID == ParticleID::H0 ) {
if( f1ID % 2 == 0 )
coup *= -theSa/theSb;
else
coup *= -theCa/theCb;
}
else {
if( f1ID % 2 == 0 )
coup /= thetanb;
else
coup *= thetanb;
coup *= Complex(0.,-1.);
rcoup = -1.;
}
}
//H+
else {
if( f1ID % 2 == 0 ) {
lcoup = theMassLast.first /thetanb/theMw;
rcoup = theMassLast.second*thetanb/theMw;
}
else {
lcoup = theMassLast.second/thetanb/theMw;
rcoup = theMassLast.first *thetanb/theMw;
}
coup = sqrt(0.5);
if( higgsID > 0 ) swap(lcoup,rcoup);
}
norm(theGlast*coup);
left (lcoup);
right(rcoup);
}
diff --git a/Models/Susy/SSGFSVertex.cc b/Models/Susy/SSGFSVertex.cc
--- a/Models/Susy/SSGFSVertex.cc
+++ b/Models/Susy/SSGFSVertex.cc
@@ -1,147 +1,148 @@
// -*- C++ -*-
//
// SSGFSVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGFSVertex class.
//
#include "SSGFSVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSGFSVertex::SSGFSVertex() :_q2last(0.*GeV2),_couplast(0.),
_id1last(0), _id2last(0) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TFUND);
}
void SSGFSVertex::persistentOutput(PersistentOStream & os) const {
os << _stop << _sbottom << gluinoPhase_;
}
void SSGFSVertex::persistentInput(PersistentIStream & is, int) {
is >> _stop >> _sbottom >> gluinoPhase_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSGFSVertex,FFSVertex>
describeHerwigSSGFSVertex("Herwig::SSGFSVertex", "HwSusy.so");
void SSGFSVertex::Init() {
static ClassDocumentation<SSGFSVertex> documentation
("The SSGFSVertex implements coupling of the gluinos to the "
"squarks and quarks");
}
void SSGFSVertex::setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3) {
tcPDPtr ferm;
long isc(0);
if(abs(part1->id()) == 1000021) {
if(part2->iSpin() == PDT::Spin1Half) {
ferm = part2;
isc = abs(part3->id());
}
else {
ferm = part3;
isc = abs(part2->id());
}
}
else if(abs(part2->id()) == 1000021) {
if(part1->iSpin() == PDT::Spin1Half) {
ferm = part1;
isc = abs(part3->id());
}
else {
ferm = part3;
isc = abs(part1->id());
}
}
else if(abs(part3->id()) == 1000021) {
if(part1->iSpin() == PDT::Spin1Half) {
ferm = part1;
isc = abs(part2->id());
}
else {
ferm = part2;
isc = abs(part1->id());
}
}
else throw HelicityConsistencyError()
<< "SSGFSVertex::setCoupling() - There is no gluino in this vertex!"
<< part1->id() << " " << part2->id() << " " << part3->id()
<< Exception::runerror;
long iferm = abs(ferm->id());
assert(iferm >=1 && iferm <=6);
if(q2 != _q2last || _couplast==0.) {
_couplast = -strongCoupling(q2)*sqrt(2.);
_q2last = q2;
}
if(iferm != _id1last || isc != _id2last) {
_id1last = iferm;
_id2last = isc;
unsigned int eig = (isc/1000000) - 1;
if(iferm == 6) {
_leftlast = -(*_stop)(eig,1)*conj(gluinoPhase_);
_rightlast = (*_stop)(eig,0)* gluinoPhase_ ;
}
else if(iferm == 5){
_leftlast = -(*_sbottom)(eig,1)*conj(gluinoPhase_);
_rightlast = (*_sbottom)(eig,0)* gluinoPhase_ ;
}
else {
if(eig == 0) {
_leftlast = 0.;
_rightlast = gluinoPhase_;
}
else {
_leftlast = -conj(gluinoPhase_);
_rightlast = 0.;
}
}
}
norm(_couplast);
//arrange l/r couplings
if(ferm->id() < 0) {
left(conj(_rightlast));
right(conj(_leftlast));
}
else {
left(_leftlast);
right(_rightlast);
}
}
void SSGFSVertex::doinit() {
for(long ix=1;ix<7;++ix) {
addToList(1000021, ix, -(ix+1000000));
addToList(1000021, ix, -(ix+2000000));
addToList(1000021, -ix, (ix+1000000));
addToList(1000021, -ix, (ix+2000000));
}
FFSVertex::doinit();
tMSSMPtr model = dynamic_ptr_cast<MSSMPtr>(generator()->standardModel());
_stop = model->stopMix();
_sbottom = model->sbottomMix();
gluinoPhase_ = model->gluinoPhase();
if(!_stop || !_sbottom)
throw InitException() << "SSGFSVertex::doinit() - "
<< "There is a null mixing matrix pointer. "
<< "stop: " << _stop << " sbottom: " << _sbottom
<< Exception::abortnow;
}
diff --git a/Models/Susy/SSGGSQSQVertex.cc b/Models/Susy/SSGGSQSQVertex.cc
--- a/Models/Susy/SSGGSQSQVertex.cc
+++ b/Models/Susy/SSGGSQSQVertex.cc
@@ -1,59 +1,60 @@
// -*- C++ -*-
//
// SSGGSQSQVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGGSQSQVertex class.
//
#include "SSGGSQSQVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
-SSGGSQSQVertex::SSGGSQSQVertex() : q2last_(),couplast_(0.)
-{}
+SSGGSQSQVertex::SSGGSQSQVertex() : q2last_(),couplast_(0.) {
+ colourStructure(ColourStructure::SU3TTFUNDS);
+}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<SSGGSQSQVertex,Helicity::VVSSVertex>
describeSSGGSQSQVertex("Herwig::SSGGSQSQVertex", "HwSusy.so");
void SSGGSQSQVertex::Init() {
static ClassDocumentation<SSGGSQSQVertex> documentation
("This implements the gluon-gluon-squark-squark vertex.");
}
void SSGGSQSQVertex::setCoupling(Energy2 q2, tcPDPtr, tcPDPtr, tcPDPtr,
tcPDPtr) {
if(q2 != q2last_ || couplast_ == 0.) {
couplast_ = sqr(strongCoupling(q2));
q2last_ = q2;
}
norm(couplast_);
}
void SSGGSQSQVertex::doinit() {
//L-L squarks
for(long ix=1000001;ix<1000007;++ix) {
addToList(21,21,ix,-ix);
}
//R-R squarks
for(long ix=2000001;ix<2000007;++ix) {
addToList(21,21,ix,-ix);
}
orderInGs(2);
orderInGem(0);
VVSSVertex::doinit();
}
diff --git a/Models/Susy/SSGNGVertex.cc b/Models/Susy/SSGNGVertex.cc
--- a/Models/Susy/SSGNGVertex.cc
+++ b/Models/Susy/SSGNGVertex.cc
@@ -1,304 +1,305 @@
// -*- C++ -*-
//
// SSGNGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGNGVertex class.
//
#include "SSGNGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/Susy/MixingMatrix.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Looptools/clooptools.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
namespace {
unsigned int neutralinoIndex(long id) {
if(id> 1000000)
return id<1000025 ? id-1000022 : (id-1000005)/10;
else if(abs(id)<=16)
return (abs(id)-4)/2;
else
return id-13;
}
}
SSGNGVertex::SSGNGVertex() : _includeOnShell(false), _realIntegral(false),
_omitLightQuarkYukawas(false),
_sw(0.), _cw(0.), _idlast(0),
_q2last(ZERO), _couplast(0.),
_leftlast(ZERO), _rightlast(ZERO),
_initLoops(false) {
orderInGem(1);
orderInGs(2);
+ colourStructure(ColourStructure::DELTA);
}
void SSGNGVertex::doinit() {
if(!_initLoops) {
Looptools::ltini();
_initLoops = true;
}
tMSSMPtr model = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if(!model)
throw InitException() << "SSGNGVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
_theN = model->neutralinoMix();
if(!_theN )
throw InitException() << "SSGNGVertex::doinit - The neutralino "
<< "mixing matrix pointer is null."
<< Exception::abortnow;
vector<long> ineu(4);
ineu[0] = 1000022; ineu[1] = 1000023;
ineu[2] = 1000025; ineu[3] = 1000035;
if(_theN->size().first==5)
ineu.push_back(1000045);
else if(_theN->size().first==7) {
if(model->majoranaNeutrinos()) {
ineu.push_back(17);
ineu.push_back(18);
ineu.push_back(19);
}
else {
ineu.push_back(12);
ineu.push_back(14);
ineu.push_back(16);
}
}
for(unsigned int i = 0; i < ineu.size(); ++i) {
addToList(1000021, ineu[i], 21);
}
GeneralFFVVertex::doinit();
_sw = sqrt(sin2ThetaW());
_cw = sqrt(1 - _sw*_sw);
_mw = getParticleData(ParticleID::Wplus)->mass();
double tb = model->tanBeta();
_sb = tb/sqrt(1 + sqr(tb));
_cb = sqrt(1 - sqr(_sb));
_stop = model->stopMix();
_sbot = model->sbottomMix();
Looptools::ltexi();
}
void SSGNGVertex::dofinish() {
Looptools::ltexi();
GeneralFFVVertex::dofinish();
}
void SSGNGVertex::doinitrun() {
if(!_initLoops) {
Looptools::ltini();
_initLoops = true;
}
GeneralFFVVertex::doinitrun();
}
void SSGNGVertex::persistentOutput(PersistentOStream & os) const {
os << _sw << _cw << _theN << ounit(_mw,GeV) << _sb << _cb
<< _stop << _sbot << _includeOnShell << _omitLightQuarkYukawas
<< _realIntegral;
}
void SSGNGVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw >> _cw >> _theN >> iunit(_mw,GeV) >> _sb >> _cb
>> _stop >> _sbot >> _includeOnShell >> _omitLightQuarkYukawas
>> _realIntegral;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSGNGVertex,GeneralFFVVertex>
describeHerwigSSGNGVertex("Herwig::SSGNGVertex", "HwSusy.so");
void SSGNGVertex::Init() {
static ClassDocumentation<SSGNGVertex> documentation
("The loop-mediated coupling of the gluino to a gluon and a neutralino.");
static Switch<SSGNGVertex,bool> interfaceIncludeOnShellIntermediates
("IncludeOnShellIntermediates",
"Whether or not to include on-shell intermediate states",
&SSGNGVertex::_includeOnShell, false, false, false);
static SwitchOption interfaceIncludeOnShellIntermediatesYes
(interfaceIncludeOnShellIntermediates,
"Yes",
"Include them",
true);
static SwitchOption interfaceIncludeOnShellIntermediatesNo
(interfaceIncludeOnShellIntermediates,
"No",
"Don't incldue them",
false);
static Switch<SSGNGVertex,bool> interfaceOmitLightQuarkYukawas
("OmitLightQuarkYukawas",
"Omit the yukawa type couplings for down, up, strange"
" and charm quarks, mainly for testing vs ISAJET",
&SSGNGVertex::_omitLightQuarkYukawas, false, false, false);
static SwitchOption interfaceOmitLightQuarkYukawasNo
(interfaceOmitLightQuarkYukawas,
"No",
"Include the Yukawas",
false);
static SwitchOption interfaceOmitLightQuarkYukawasYes
(interfaceOmitLightQuarkYukawas,
"Yes",
"Omit Yukawas",
true);
static Switch<SSGNGVertex,bool> interfaceRealIntegral
("RealIntegral",
"Only include the real parts of the integrals",
&SSGNGVertex::_realIntegral, false, false, false);
static SwitchOption interfaceRealIntegralYes
(interfaceRealIntegral,
"Yes",
"Only include the real part",
true);
static SwitchOption interfaceRealIntegralNo
(interfaceRealIntegral,
"No",
"Don't include the real part",
false);
}
void SSGNGVertex::setCoupling(Energy2 q2, tcPDPtr part1,
#ifndef NDEBUG
tcPDPtr part2,tcPDPtr part3) {
#else
tcPDPtr part2,tcPDPtr) {
#endif
int o[2]={1,0};
long in1 = part1->id();
long in2 = part2->id();
Energy Mj = part1->mass();
Energy Mi = part2->mass();
if(in1!=ParticleID::SUSY_g) {
swap(in1,in2);
swap(Mj,Mi);
}
// checks of the particle ids
assert(part3->id()==ParticleID::g);
assert(in1 == ParticleID::SUSY_g);
assert(in2 == ParticleID::SUSY_chi_10 || in2 == ParticleID::SUSY_chi_20 ||
in2 == ParticleID::SUSY_chi_30 || in2 == ParticleID::SUSY_chi_40 ||
in2 == 1000045 || in2==12 || in2==14 || in2==16 || in2==17 || in2==18 || in2==19 );
// normal couplings are zero
setLeft (0.);
setRight(0.);
if(in2 != _idlast || q2 !=_q2last) {
if(!_initLoops) {
Looptools::ltini();
_initLoops = true;
}
Looptools::clearcache();
_leftlast = ZERO;
_rightlast = ZERO;
_idlast = in2;
unsigned int neu = neutralinoIndex(in2);
Complex n1prime = (*_theN)(neu,0)*_cw + (*_theN)(neu,1)*_sw;
Complex n2prime = (*_theN)(neu,1)*_cw - (*_theN)(neu,0)*_sw;
// squark/quark loops
for(long iferm=1;iferm<7;++iferm) {
tcPDPtr smf = getParticleData(iferm);
Energy mf = smf->mass();
double qf = smf->charge()/eplus;
double y = (!(iferm<=4&&_omitLightQuarkYukawas)) ?
0.5*double(dynamic_ptr_cast<tcHwSMPtr>(generator()->standardModel())->mass(q2,smf)/_mw) : 0.;
Complex bracketl = qf*_sw*( conj(n1prime) - _sw*conj(n2prime)/_cw );
double lambda(0.);
// neutralino mixing element
Complex nlf(0.);
if( iferm % 2 == 0 ) {
y /= _sb;
lambda = -0.5 + qf*sqr(_sw);
nlf = (*_theN)(neu,3);
}
else {
y /= _cb;
lambda = 0.5 + qf*sqr(_sw);
nlf = (*_theN)(neu,2);
}
Complex bracketr = _sw*qf*n1prime - n2prime*lambda/_cw;
for(long iy=0;iy<2;++iy) {
long isf = 1000000*(1+iy)+iferm;
Energy msf = getParticleData(isf)->mass();
if(!_includeOnShell&&(mf+msf<Mj||mf+msf<Mi)) continue;
Complex g[2][2];
Complex ma1(0.), ma2(0.);
// heavy fermions
if( iferm == 5 || iferm == 6 ) {
if( iferm == 5 ) {
ma1 = (*_sbot)(iy,0);
ma2 = (*_sbot)(iy,1);
}
else if( iferm == 6 ) {
ma1 = (*_stop)(iy,0);
ma2 = (*_stop)(iy,1);
}
}
else if(iy==0) {
ma1 = 1.;
}
else {
ma2 = 1.;
}
g[0][0] = y*conj(nlf)*ma1 - ma2*bracketl;
g[0][1] = y*nlf *ma2 + ma1*bracketr;
g[1][0] = - ma2;
g[1][1] = + ma1;
swap(g[0][0],g[0][1]);
complex<InvEnergy2> I,J,K,I2;
loopIntegrals(Mi,Mj,msf,mf,I,J,K,I2);
complex<InvEnergy> coup[2];
for(unsigned int ix=0;ix<2;++ix) {
coup[ix] = Mj*(I2-K)*(g[0][ix]*g[1][o[ix]]-conj(g[0][o[ix]]*g[1][ix]))
+Mi*K*(g[0][o[ix]]*g[1][ix]-conj(g[0][ix]*g[1][o[ix]]))
+mf*I*(g[0][ix]*g[1][ix]-conj(g[0][o[ix]]*g[1][o[ix]]));
}
_leftlast += 2.*coup[0];
_rightlast += 2.*coup[1];
}
}
}
if(q2 != _q2last || _couplast==0.) {
_q2last = q2;
_couplast = weakCoupling(q2)*sqr(strongCoupling(q2))/
32./sqr(Constants::pi);
}
norm(_couplast);
setLeftSigma ( _leftlast);
setRightSigma(_rightlast);
}
void SSGNGVertex::loopIntegrals(Energy Mi, Energy Mj, Energy M, Energy m,
complex<InvEnergy2> & I, complex<InvEnergy2> & J,
complex<InvEnergy2> & K, complex<InvEnergy2> & I2) {
Energy2 m2(sqr(m)),M2(sqr(M)),Mi2(sqr(Mi)),Mj2(sqr(Mj));
double min2 = Mj2*UnitRemoval::InvE2;
double mout2 = Mi2*UnitRemoval::InvE2;
double mf2 = m2 *UnitRemoval::InvE2;
double ms2 = M2 *UnitRemoval::InvE2;
I = Looptools::C0i(Looptools::cc0,min2,mout2,0.,mf2,ms2,mf2)*UnitRemoval::InvE2;
J = Looptools::C0i(Looptools::cc0,min2,mout2,0.,ms2,mf2,ms2)*UnitRemoval::InvE2;
I2 =-Looptools::C0i(Looptools::cc1,min2,mout2,0.,mf2,ms2,mf2)*UnitRemoval::InvE2;
K = (1.+Complex(m2*I+M2*J-Mj2*I2))/(Mi2-Mj2);
if(_realIntegral) {
I = I .real();
J = J .real();
I2 = I2.real();
K = K .real();
}
}
diff --git a/Models/Susy/SSGOGOHVertex.cc b/Models/Susy/SSGOGOHVertex.cc
--- a/Models/Susy/SSGOGOHVertex.cc
+++ b/Models/Susy/SSGOGOHVertex.cc
@@ -1,237 +1,238 @@
// -*- C++ -*-
//
// SSGOGOHVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGOGOHVertex class.
//
#include "SSGOGOHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include <cassert>
using namespace ThePEG::Helicity;
using namespace Herwig;
-SSGOGOHVertex::SSGOGOHVertex() : theMw(), theSij(2, vector<Complex>(2,0.0)),
- theQij(2, vector<Complex>(2,0.0)),
- theQijLp(4, vector<Complex>(2,0.0)),
- theQijRp(4, vector<Complex>(2,0.0)),
- theSijdp(4, vector<Complex>(4,0.0)),
- theQijdp(4, vector<Complex>(4,0.0)),
+SSGOGOHVertex::SSGOGOHVertex() : theMw(), theSij(2, {{0., 0.}}),
+ theQij(2, {{0., 0.}}),
+ theQijLp(4, {{0., 0.}}),
+ theQijRp(4, {{0., 0.}}),
+ theSijdp(4, {{0., 0., 0., 0.}}),
+ theQijdp(4, {{0., 0., 0., 0.}}),
theSa(0.0), theSb(0.0),
theCa(0.0), theCb(0.0), theCoupLast(0.0),
theLLast(0.0), theRLast(0.0), theHLast(0),
theID1Last(0), theID2Last(0), theq2last() {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void SSGOGOHVertex::doinit() {
long neu[4] = {1000022, 1000023, 1000025, 1000035};
long chg[2] = {1000024, 1000037};
long higgs[3] = {25, 35, 36};
for(unsigned int i = 0; i < 4; ++i) {
//neutralinos
for(unsigned int j = 0; j < 4; ++j) {
for(unsigned int k = 0; k < 4; ++k) {
if( i < 3 ) {
if(k<=j)
addToList(neu[j], neu[k], higgs[i]);
//charginos
if( j < 2 && k < 2 ) {
addToList(-chg[j], chg[k], higgs[i]);
}
}
else {
if( k == 2 ) break;
addToList(-chg[k], neu[j], 37);
addToList( chg[k], neu[j],-37);
}
}
}
}
FFSVertex::doinit();
tMSSMPtr theMSSM = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !theMSSM )
throw InitException()
<< "SSGOGOHVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
theMw = getParticleData(ParticleID::Wplus)->mass();
double theSw = sqrt(sin2ThetaW());
double tw = theSw/sqrt(1. - theSw*theSw);
double tanb = theMSSM->tanBeta();
theSb = tanb/sqrt(1. + sqr(tanb));
theCb = sqrt( 1. - sqr(theSb) );
theSa = sin(theMSSM->higgsMixingAngle());
theCa = sqrt(1. - sqr(theSa));
MixingMatrix nmix = *theMSSM->neutralinoMix();
MixingMatrix umix = *theMSSM->charginoUMix();
MixingMatrix vmix = *theMSSM->charginoVMix();
for(unsigned int i = 0; i < 4; ++i) {
for(unsigned int j = 0; j < 4; ++j) {
if( i < 2 && j < 2 ) {
theQij[i][j] = vmix(i,0)*umix(j,1)/sqrt(2);
theSij[i][j] = vmix(i,1)*umix(j,0)/sqrt(2);
}
if( j < 2 ) {
theQijLp[i][j] = conj(nmix(i, 3)*vmix(j,0)
+ (nmix(i,1) + nmix(i,0)*tw)*vmix(j,1)/sqrt(2));
theQijRp[i][j] = nmix(i, 2)*umix(j,0)
- (nmix(i,1) + nmix(i,0)*tw)*umix(j,1)/sqrt(2);
}
theQijdp[i][j] = 0.5*( nmix(i,2)*( nmix(j,1) - tw*nmix(j,0) )
+ nmix(j,2)*( nmix(i,1) - tw*nmix(i,0) ) );
theSijdp[i][j] = 0.5*( nmix(i,3)*( nmix(j,1) - tw*nmix(j,0) )
+ nmix(j,3)*( nmix(i,1) - tw*nmix(i,0) ) );
}
}
}
void SSGOGOHVertex::persistentOutput(PersistentOStream & os) const {
os << theSij << theQij << theQijLp << theQijRp << theSijdp
<< theQijdp << ounit(theMw,GeV) << theSa << theSb << theCa
<< theCb;
}
void SSGOGOHVertex::persistentInput(PersistentIStream & is, int) {
is >> theSij >> theQij >> theQijLp >> theQijRp >> theSijdp
>> theQijdp >> iunit(theMw,GeV) >> theSa >> theSb >> theCa
>> theCb;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSGOGOHVertex,FFSVertex>
describeHerwigSSGOGOHVertex("Herwig::SSGOGOHVertex", "HwSusy.so");
void SSGOGOHVertex::Init() {
static ClassDocumentation<SSGOGOHVertex> documentation
("The coupling of the higgs bosons to SM fermions in the MSSM");
}
/// \todo fixme
void SSGOGOHVertex::setCoupling(Energy2 q2, tcPDPtr particle1,
tcPDPtr particle2,tcPDPtr particle3) {
long f1ID(particle1->id()), f2ID(particle2->id()), higgsID(particle3->id());
assert(higgsID == ParticleID::h0 || higgsID == ParticleID::H0 ||
higgsID == ParticleID::A0 || abs(higgsID) == ParticleID::Hplus);
if( f1ID < 0 ) swap(f1ID, f2ID);
if( q2 != theq2last || theCoupLast == 0. ) {
theCoupLast = weakCoupling(q2);
theq2last = q2;
}
if( higgsID == theHLast && f1ID == theID1Last && f2ID == theID2Last) {
norm(theCoupLast);
left(theLLast);
right(theRLast);
return;
}
theHLast = higgsID;
theID1Last = f1ID;
theID2Last = f2ID;
if( higgsID == ParticleID::h0 ) {
//charginos
if( abs(f2ID) == ParticleID::SUSY_chi_1plus ||
abs(f2ID) == ParticleID::SUSY_chi_2plus ) {
unsigned int ei = (abs(f1ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1;
unsigned int ej = (abs(f2ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1;
theLLast = conj(theQij[ej][ei])*theSa - conj(theSij[ej][ei])*theCa;
theRLast = theQij[ei][ej]*theSa - theSij[ei][ej]*theCa;
}
//neutralinos
else {
unsigned int ei(f1ID - ParticleID::SUSY_chi_10),
ej(f2ID - ParticleID::SUSY_chi_10);
if( ei > 1 )
ei = ( ei == 13 ) ? 3 : 2;
if( ej > 1 )
ej = ( ej == 13 ) ? 3 : 2;
theLLast = conj(theQijdp[ej][ei])*theSa + conj(theSijdp[ej][ei])*theCa;
theRLast = theQijdp[ei][ej]*theSa + theSijdp[ei][ej]*theCa ;
}
}
else if( higgsID == ParticleID::H0 ) {
//charginos
if( abs(f2ID) == ParticleID::SUSY_chi_1plus ||
abs(f2ID) == ParticleID::SUSY_chi_2plus ) {
unsigned int ei = (abs(f1ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1;
unsigned int ej = (abs(f2ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1;
theLLast = -conj(theQij[ej][ei])*theCa - conj(theSij[ej][ei])*theSa;
theRLast = -theQij[ei][ej]*theCa - theSij[ei][ej]*theSa;
}
//neutralinos
else {
unsigned int ei(f1ID - ParticleID::SUSY_chi_10),
ej(f2ID - ParticleID::SUSY_chi_10);
if( ei > 1 )
ei = ( ei == 13 ) ? 3 : 2;
if( ej > 1 )
ej = ( ej == 13 ) ? 3 : 2;
theLLast = -conj(theQijdp[ej][ei])*theCa + conj(theSijdp[ej][ei])*theSa;
theRLast = -theQijdp[ei][ej]*theCa + theSijdp[ei][ej]*theSa;
}
}
else if( higgsID == ParticleID::A0 ) {
if( abs(f2ID) == ParticleID::SUSY_chi_1plus ||
abs(f2ID) == ParticleID::SUSY_chi_2plus ) {
unsigned int ei = (abs(f1ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1;
unsigned int ej = (abs(f2ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1;
theLLast = Complex(0.,1.)*( conj(theQij[ej][ei])*theSb
+ conj(theSij[ej][ei])*theCb );
theRLast = -Complex(0.,1.)*(theQij[ei][ej]*theSb + theSij[ei][ej]*theCb);
}
//neutralinos
else {
unsigned int ei(f1ID - ParticleID::SUSY_chi_10),
ej(f2ID - ParticleID::SUSY_chi_10);
if( ei > 1 )
ei = ( ei == 13 ) ? 3 : 2;
if( ej > 1 )
ej = ( ej == 13 ) ? 3 : 2;
theLLast = Complex(0.,1.)*( conj(theQijdp[ej][ei])*theSb
- conj(theSijdp[ej][ei])*theCb );
theRLast = -Complex(0.,1.)*(theQijdp[ei][ej]*theSb - theSijdp[ei][ej]*theCb);
}
}
//charged higgs
else {
unsigned int ei(0),ej(0);
long chg(f2ID), neu(f1ID);
if( abs(neu) == ParticleID::SUSY_chi_1plus ||
abs(neu) == ParticleID::SUSY_chi_2plus ) swap(chg, neu);
ej = ( abs(chg) == ParticleID::SUSY_chi_1plus) ? 0 : 1;
ei = neu - ParticleID::SUSY_chi_10;
if( ei > 1 ) ei = ( ei == 13 ) ? 3 : 2;
theLLast = -theQijLp[ei][ej]*theCb;
theRLast = -theQijRp[ei][ej]*theSb;
if( higgsID < 0 ) {
Complex tmp = theLLast;
theLLast = conj(theRLast);
theRLast = conj(tmp);
}
}
norm(theCoupLast);
left(theLLast);
right(theRLast);
}
diff --git a/Models/Susy/SSGSGSGVertex.cc b/Models/Susy/SSGSGSGVertex.cc
--- a/Models/Susy/SSGSGSGVertex.cc
+++ b/Models/Susy/SSGSGSGVertex.cc
@@ -1,58 +1,59 @@
// -*- C++ -*-
//
// SSGSGSGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGSGSGVertex class.
//
#include "SSGSGSGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSGSGSGVertex::SSGSGSGVertex() : _couplast(0.),_q2last(ZERO) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3F);
}
// Static variable needed for the type description system in ThePEG.
DescribeNoPIOClass<SSGSGSGVertex,FFVVertex>
describeHerwigSSGSGSGVertex("Herwig::SSGSGSGVertex", "HwSusy.so");
void SSGSGSGVertex::Init() {
static ClassDocumentation<SSGSGSGVertex> documentation
("This class implements the gluon-gluino-gluino vertex");
}
void SSGSGSGVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
assert(part1->id()==ParticleID::SUSY_g &&
part2->id()==ParticleID::SUSY_g &&
part3->id() == ParticleID::g);
if(q2 != _q2last || _couplast==0.) {
_couplast = strongCoupling(q2);
_q2last = q2;
}
norm(_couplast);
left(1.);
right(1.);
}
void SSGSGSGVertex::doinit() {
addToList(1000021, 1000021, 21);
FFVVertex::doinit();
}
diff --git a/Models/Susy/SSGSSVertex.cc b/Models/Susy/SSGSSVertex.cc
--- a/Models/Susy/SSGSSVertex.cc
+++ b/Models/Susy/SSGSSVertex.cc
@@ -1,67 +1,68 @@
// -*- C++ -*-
//
// SSGSSVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGSSVertex class.
//
#include "SSGSSVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSGSSVertex::SSGSSVertex() : _couplast(0.),_q2last(ZERO) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TFUND);
}
void SSGSSVertex::doinit() {
for(long ix=1000001;ix<1000007;++ix) {
addToList(21,ix,-ix);
}
for(long ix=2000001;ix<2000007;++ix) {
addToList(21,ix,-ix);
}
VSSVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<SSGSSVertex,Helicity::VSSVertex>
describeSSGSSVertex("Herwig::SSGSSVertex", "HwSusy.so");
void SSGSSVertex::Init() {
static ClassDocumentation<SSGSSVertex> documentation
("The SSGSSVertex class implements the coupling"
" of the gluon to the squarks");
}
void SSGSSVertex::setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3) {
assert(part1->id()==ParticleID::g);
long isf = abs(part2->id());
assert( (isf >= 1000001 && isf <= 1000006) ||
(isf >= 2000001 && isf <= 2000006) );
assert(part2->id()==-part3->id());
if(q2 != _q2last || _couplast == 0.) {
_couplast = strongCoupling(q2);
_q2last = q2;
}
if(part2->id()>0)
norm(-_couplast);
else
norm( _couplast);
}
diff --git a/Models/Susy/SSGVFSVertex.cc b/Models/Susy/SSGVFSVertex.cc
--- a/Models/Susy/SSGVFSVertex.cc
+++ b/Models/Susy/SSGVFSVertex.cc
@@ -1,129 +1,130 @@
// -*- C++ -*-
//
// SSGVFSVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGVFSVertex class.
//
#include "SSGVFSVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSGVFSVertex::SSGVFSVertex() : MPlanck_(2.4e18*GeV) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SSGVFSVertex::persistentOutput(PersistentOStream & os) const {
os << stop_ << sbot_ << stau_ << ounit(MPlanck_,GeV);
}
void SSGVFSVertex::persistentInput(PersistentIStream & is, int) {
is >> stop_ >> sbot_ >> stau_ >> iunit(MPlanck_,GeV);
}
void SSGVFSVertex::doinit() {
//quarks
for(long ix=1;ix<7;++ix){
addToList( ParticleID::SUSY_Gravitino, ix, -(1000000+ix) );
addToList( ParticleID::SUSY_Gravitino, ix, -(2000000+ix) );
addToList( ParticleID::SUSY_Gravitino, -ix, (1000000+ix) );
addToList( ParticleID::SUSY_Gravitino, -ix, (2000000+ix) );
}
//leptons
for(long ix=11;ix<17;++ix) {
addToList( ParticleID::SUSY_Gravitino, ix, -(1000000+ix) );
addToList( ParticleID::SUSY_Gravitino, -ix, (1000000+ix) );
if( ix % 2 != 0 ) {
addToList( ParticleID::SUSY_Gravitino, ix, -(2000000+ix) );
addToList( ParticleID::SUSY_Gravitino, -ix, (2000000+ix) );
}
}
RFSVertex::doinit();
tMSSMPtr model = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !model )
throw InitException() << "SSGVFSVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
MPlanck_ = model->MPlanck();
stop_ = model->stopMix();
sbot_ = model->sbottomMix();
stau_ = model->stauMix();
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSGVFSVertex,RFSVertex>
describeHerwigSSGVFSVertex("Herwig::SSGVFSVertex", "libHwSusy.so");
void SSGVFSVertex::Init() {
static ClassDocumentation<SSGVFSVertex> documentation
("The SSGVFSVertex implements the coupling of the gravitino to "
"a fermion-sfermion");
}
void SSGVFSVertex::setCoupling(Energy2 ,
#ifndef NDEBUG
tcPDPtr part1,
#else
tcPDPtr,
#endif
tcPDPtr part2,tcPDPtr part3) {
assert(part1->id()==ParticleID::SUSY_Gravitino);
assert(part3->iSpin()==PDT::Spin0);
norm(double(sqrt(2.)/MPlanck_*UnitRemoval::E));
// sfermion mass eigenstate
unsigned int alpha(abs(part3->id())/1000000 - 1);
unsigned int ism(abs(part2->id()));
Complex lc,rc;
//heavy quarks/sleptons
if( ism == 5 || ism == 6 || ism == 15 ) {
Complex ma1(0.), ma2(0.);
if( ism == 5 ) {
ma1 = (*sbot_)(alpha,0);
ma2 = (*sbot_)(alpha,1);
}
else if( ism == 6 ) {
ma1 = (*stop_)(alpha,0);
ma2 = (*stop_)(alpha,1);
}
else {
ma1 = (*stau_)(alpha,0);
ma2 = (*stau_)(alpha,1);
}
lc = - ma2;
rc = + ma1;
}
else {
if( alpha == 0 ) {
lc = 0.;
rc = 1.;
}
else {
lc = -1.;
rc = 0.;
}
}
// determine the helicity order of the vertex
if( part2->id() < 0 ) {
left (conj(rc));
right(conj(lc));
}
else {
left (lc);
right(rc);
}
}
diff --git a/Models/Susy/SSGVNHVertex.cc b/Models/Susy/SSGVNHVertex.cc
--- a/Models/Susy/SSGVNHVertex.cc
+++ b/Models/Susy/SSGVNHVertex.cc
@@ -1,109 +1,110 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGVNHVertex class.
//
#include "SSGVNHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "MSSM.h"
using namespace Herwig;
SSGVNHVertex::SSGVNHVertex() : sa_(0.), sb_(0.), ca_(0.), cb_(0.),
MPlanck_(2.4e18*GeV) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr SSGVNHVertex::clone() const {
return new_ptr(*this);
}
IBPtr SSGVNHVertex::fullclone() const {
return new_ptr(*this);
}
void SSGVNHVertex::persistentOutput(PersistentOStream & os) const {
os << sa_ << sb_ << ca_ << cb_ << nmix_ << ounit(MPlanck_,GeV);
}
void SSGVNHVertex::persistentInput(PersistentIStream & is, int) {
is >> sa_ >> sb_ >> ca_ >> cb_ >> nmix_ >> iunit(MPlanck_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSGVNHVertex,Helicity::RFSVertex>
describeHerwigSSGVNHVertex("Herwig::SSGVNHVertex", "HwSusy.so");
void SSGVNHVertex::Init() {
static ClassDocumentation<SSGVNHVertex> documentation
("The SSGVNHVertex class implments the coupling of the Higgs"
" bosons to a gravitino and a neutralino");
}
void SSGVNHVertex::doinit() {
long neu[4] = {ParticleID::SUSY_chi_10, ParticleID::SUSY_chi_20,
ParticleID::SUSY_chi_30, ParticleID::SUSY_chi_40};
long higgs[3] = {25, 35, 36};
for(unsigned int i = 0; i < 3; ++i) {
for(unsigned int j = 0; j < 4; ++j) {
addToList(ParticleID::SUSY_Gravitino, neu[j], higgs[i]);
}
}
RFSVertex::doinit();
tMSSMPtr model = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !model )
throw InitException()
<< "SSGVNHVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
double tanb = model->tanBeta();
sb_ = tanb/sqrt(1. + sqr(tanb));
cb_ = sqrt( 1. - sqr(sb_) );
sa_ = sin(model->higgsMixingAngle());
ca_ = sqrt(1. - sqr(sa_));
nmix_ = model->neutralinoMix();
MPlanck_ = model->MPlanck();
}
void SSGVNHVertex::setCoupling(Energy2 ,
#ifndef NDEBUG
tcPDPtr part1,
#else
tcPDPtr,
#endif
tcPDPtr part2,tcPDPtr part3) {
assert(part1->id()==ParticleID::SUSY_Gravitino);
assert(part3->iSpin()==PDT::Spin0);
unsigned int neut = part2->id() - ParticleID::SUSY_chi_10;
if(neut>1) neut = ( neut == 13 ) ? 3 : 2;
int hid = part3->id();
Complex coup;
switch(hid) {
case ParticleID::h0 :
left (1.);
right(1.);
coup = -(*nmix_)(neut,2)*sa_+(*nmix_)(neut,3)*ca_;
break;
case ParticleID::H0 :
left (1.);
right(1.);
coup = (*nmix_)(neut,2)*ca_+(*nmix_)(neut,3)*sa_;
break;
case ParticleID::A0 :
left (Complex(0.,-1.));
right(Complex(0., 1.));
coup = (*nmix_)(neut,2)*sb_+(*nmix_)(neut,3)*cb_;
break;
default :
assert(false);
}
norm(coup/MPlanck_*UnitRemoval::E);
}
diff --git a/Models/Susy/SSGVNVVertex.cc b/Models/Susy/SSGVNVVertex.cc
--- a/Models/Susy/SSGVNVVertex.cc
+++ b/Models/Susy/SSGVNVVertex.cc
@@ -1,119 +1,120 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSGVNVVertex class.
//
#include "SSGVNVVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "MSSM.h"
using namespace Herwig;
SSGVNVVertex::SSGVNVVertex() : sw_(0.), cw_(0.), sb_(0.), cb_(0.),
mz_(91.1876*GeV), MPlanck_(2.4e18*GeV) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr SSGVNVVertex::clone() const {
return new_ptr(*this);
}
IBPtr SSGVNVVertex::fullclone() const {
return new_ptr(*this);
}
void SSGVNVVertex::persistentOutput(PersistentOStream & os) const {
os << sw_ << cw_ << sb_ << cb_ << ounit(mz_,GeV) << nmix_ << ounit(MPlanck_,GeV);
}
void SSGVNVVertex::persistentInput(PersistentIStream & is, int) {
is >> sw_ >> cw_ >> sb_ >> cb_ >> iunit(mz_,GeV) >> nmix_ >> iunit(MPlanck_,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSGVNVVertex,Helicity::RFVVertex>
describeHerwigSSGVNVVertex("Herwig::SSGVNVVertex", "SSGVNVVertex.so");
void SSGVNVVertex::Init() {
static ClassDocumentation<SSGVNVVertex> documentation
("The SSGVNVVertex class implements the coupling of the gravitino"
" to the neutralino and a photon or Z boson, or the gluino and gluon.");
}
void SSGVNVVertex::doinit() {
long neu[4] = {ParticleID::SUSY_chi_10, ParticleID::SUSY_chi_20,
ParticleID::SUSY_chi_30, ParticleID::SUSY_chi_40};
for(unsigned int j = 0; j < 4; ++j) {
addToList(ParticleID::SUSY_Gravitino, neu[j], ParticleID::gamma);
addToList(ParticleID::SUSY_Gravitino, neu[j], ParticleID::Z0);
}
addToList(ParticleID::SUSY_Gravitino, ParticleID::SUSY_g, ParticleID::g);
RFVVertex::doinit();
tMSSMPtr model = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !model )
throw InitException()
<< "SSGVNVVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
double tanb = model->tanBeta();
sb_ = tanb/sqrt(1. + sqr(tanb));
cb_ = sqrt( 1. - sqr(sb_) );
sw_ = sqrt(sin2ThetaW());
cw_ = sqrt(1. - sin2ThetaW());
nmix_ = model->neutralinoMix();
MPlanck_ = model->MPlanck();
}
void SSGVNVVertex::setCoupling(Energy2 ,
#ifndef NDEBUG
tcPDPtr part1,
#else
tcPDPtr,
#endif
tcPDPtr part2,tcPDPtr part3) {
assert(part1->id()==ParticleID::SUSY_Gravitino);
assert(part3->iSpin()==PDT::Spin1);
unsigned int neut = part2->id() - ParticleID::SUSY_chi_10;
if(neut>1) neut = ( neut == 13 ) ? 3 : 2;
int bid = part3->id();
Complex coup[2];
vector<Complex> lV,rV;
switch(bid) {
case ParticleID::gamma :
coup[0] = (*nmix_)(neut,0)*cw_+(*nmix_)(neut,1)*sw_;
lV.push_back(-coup[0]*part2->mass()*UnitRemoval::InvE);
lV.push_back( coup[0]);
lV.push_back(0.);
rV=lV;
break;
case ParticleID::Z0 :
coup[0] = -(*nmix_)(neut,0)*sw_+(*nmix_)(neut,1)*cw_;
coup[1] = -(*nmix_)(neut,2)*cb_+(*nmix_)(neut,3)*sb_;
lV.push_back((-coup[0]*part2->mass()-mz_*coup[1])*UnitRemoval::InvE);
lV.push_back( coup[0]);
lV.push_back(0.);
rV=lV;
rV[0] = (-coup[0]*part2->mass()+mz_*coup[1])*UnitRemoval::InvE;
break;
case ParticleID::g :
lV.push_back(-double(part2->mass()*UnitRemoval::InvE));
lV.push_back(1.);
lV.push_back(0.);
rV=lV;
break;
default :
assert(false);
}
left (lV);
right(rV);
norm(double(1./MPlanck_*UnitRemoval::E));
}
diff --git a/Models/Susy/SSHGGVertex.cc b/Models/Susy/SSHGGVertex.cc
--- a/Models/Susy/SSHGGVertex.cc
+++ b/Models/Susy/SSHGGVertex.cc
@@ -1,292 +1,293 @@
// -*- C++ -*-
//
// SSHGGVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSHGGVertex class.
//
#include "SSHGGVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Looptools/clooptools.h"
#include <cassert>
using namespace ThePEG::Helicity;
using namespace Herwig;
SSHGGVertex::SSHGGVertex() : theIncludeTriLinear(true),
thePseudoScalarTreatment(false),
theSw(0.), theMw(), theZfact(),
theQt1L(0.), theQt1R(0.), theQt1LR(0.),
theQt2L(0.), theQt2R(0.), theQt2LR(0.),
theQb1L(0.), theQb1R(0.), theQb1LR(0.),
theQb2L(0.), theQb2R(0.), theQb2LR(0.),
theSqmass(4,ZERO),
theTanB(0.),theSinA(0.),
theCosA(0.), theSinB(0.), theCosB(0.),
theSinApB(0.), theCosApB(0.), theCouplast(0.),
theq2last(), theHaveCoeff(false), theLastID(0) {
orderInGs(2);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
void SSHGGVertex::doinit() {
//PDG codes for particles at vertices
addToList(21,21,25);
addToList(21,21,35);
addToList(21,21,36);
theMSSM = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !theMSSM )
throw InitException()
<< "SSHGGVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
theMw = getParticleData(ParticleID::Wplus)->mass();
thetop = getParticleData(ParticleID::t);
thebot = getParticleData(ParticleID::b);
theSw = sqrt(sin2ThetaW());
theZfact = getParticleData(ParticleID::Wplus)->mass()/(1. - sqr(theSw));
theSinA = sin(theMSSM->higgsMixingAngle());
theCosA = sqrt(1. - sqr(theSinA));
theTanB = theMSSM->tanBeta();
theSinB = theTanB/sqrt(1. + sqr(theTanB));
theCosB = sqrt( 1. - sqr(theSinB) );
theSinApB = theSinA*theCosB + theCosA*theSinB;
theCosApB = theCosA*theCosB - theSinA*theSinB;
MixingMatrixPtr stop = theMSSM->stopMix();
MixingMatrixPtr sbot = theMSSM->sbottomMix();
theQt1L = (*stop)(0,0)*(*stop)(0,0);
theQt1R = (*stop)(0,1)*(*stop)(0,1);
theQt1LR = (*stop)(0,1)*(*stop)(0,0) + (*stop)(0,1)*(*stop)(0,0);
theQt2L = (*stop)(1,0)*(*stop)(1,0);
theQt2R = (*stop)(1,1)*(*stop)(1,1);
theQt2LR = (*stop)(1,1)*(*stop)(1,0) + (*stop)(1,0)*(*stop)(1,1);
theQb1L = (*sbot)(0,0)*(*sbot)(0,0);
theQb1R = (*sbot)(0,1)*(*sbot)(0,1);
theQb1LR = (*sbot)(0,1)*(*sbot)(0,0) + (*sbot)(0,1)*(*sbot)(0,0);
theQb2L = (*sbot)(1,0)*(*sbot)(1,0);
theQb2R = (*sbot)(1,1)*(*sbot)(1,1);
theQb2LR = (*sbot)(1,1)*(*sbot)(1,0) + (*sbot)(1,0)*(*sbot)(1,1);
assert( theSqmass.size() == 4 );
theSqmass[0] = getParticleData(ParticleID::SUSY_b_1)->mass();
theSqmass[1] = getParticleData(ParticleID::SUSY_t_1)->mass();
theSqmass[2] = getParticleData(ParticleID::SUSY_b_2)->mass();
theSqmass[3] = getParticleData(ParticleID::SUSY_t_2)->mass();
VVSLoopVertex::doinit();
if(loopToolsInitialized()) Looptools::ltexi();
}
void SSHGGVertex::persistentOutput(PersistentOStream & os) const {
os << theMSSM << theSw << ounit(theMw,GeV) << ounit(theZfact,GeV)
<< theQt1L << theQt1R << theQt1LR << theQt2L << theQt2R << theQt2LR
<< theQb1L << theQb1R << theQb1LR << theQb2L << theQb2R << theQb2LR
<< thetop << thebot << theTanB << theIncludeTriLinear
<< theSinA << theCosA << theSinB << theCosB << theSinApB << theCosApB
<< ounit(theSqmass, GeV) << thePseudoScalarTreatment;
}
void SSHGGVertex::persistentInput(PersistentIStream & is, int) {
is >> theMSSM >> theSw >> iunit(theMw,GeV) >> iunit(theZfact,GeV)
>> theQt1L >> theQt1R >> theQt1LR >> theQt2L >> theQt2R >> theQt2LR
>> theQb1L >> theQb1R >> theQb1LR >> theQb2L >> theQb2R >> theQb2LR
>> thetop >> thebot >> theTanB >> theIncludeTriLinear
>> theSinA >> theCosA >> theSinB >> theCosB >> theSinApB >> theCosApB
>> iunit(theSqmass, GeV) >> thePseudoScalarTreatment;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSHGGVertex,VVSLoopVertex>
describeHerwigSSHGGVertex("Herwig::SSHGGVertex", "HwSusy.so");
void SSHGGVertex::Init() {
static ClassDocumentation<SSHGGVertex> documentation
("This class implements the higgs-gluon-gluon effective "
"vertex in the MSSM including stop, sbottom and top quarks "
"loops.");
static Switch<SSHGGVertex,bool> interfaceIncludeTriLinear
("IncludeTriLinear",
"Whether or not to include the A term squark trilinear couplings",
&SSHGGVertex::theIncludeTriLinear, true, false, false);
static SwitchOption interfaceIncludeTriLinearYes
(interfaceIncludeTriLinear,
"Yes",
"Include them",
true);
static SwitchOption interfaceIncludeTriLinearNo
(interfaceIncludeTriLinear,
"No",
"Don't include them",
false);
static Switch<SSHGGVertex,bool> interfacePseudoScalarTreatment
("PseudoScalarTreatment",
"Whether to treat the pseudoscalar as pseudoscalar or scalar, for testing only",
&SSHGGVertex::thePseudoScalarTreatment, false, false, false);
static SwitchOption interfacePseudoScalarTreatmentPseudoScalar
(interfacePseudoScalarTreatment,
"PseudoScalar",
"Treat as a pseudoscalar, the right physics",
false);
static SwitchOption interfacePseudoScalarTreatmentScalar
(interfacePseudoScalarTreatment,
"Scalar",
"Treat as a scalar for testing",
true);
}
void SSHGGVertex::setCoupling(Energy2 q2, tcPDPtr particle2,
tcPDPtr particle3, tcPDPtr particle1) {
long higgs(abs(particle1->id()));
assert( higgs == ParticleID::h0 || higgs == ParticleID::H0 ||
higgs == ParticleID::A0 );
assert(particle2->id() == ParticleID::g && particle3->id() == ParticleID::g );
if( q2 != theq2last || theCouplast == 0. || higgs != theLastID ) {
Looptools::clearcache();
theCouplast = weakCoupling(q2)*sqr(strongCoupling(q2));
Energy mt = theMSSM->mass(q2, thetop);
Energy mb = theMSSM->mass(q2, thebot);
masses.clear();
type.clear();
if( higgs == ParticleID::h0 || higgs == ParticleID::H0 ) {
setNParticles(6);
masses.insert(masses.begin(), theSqmass.begin(), theSqmass.end());
masses.push_back(mt);
masses.push_back(mb);
type.resize(6, PDT::Spin0);
type[4] = PDT::Spin1Half;
type[5] = PDT::Spin1Half;
couplings.resize(6, make_pair(0., 0.));
complex<Energy> brac1 = theZfact*(0.5 + theMSSM->ed()*sqr(theSw));
complex<Energy> brac2 = theZfact*(0.5 - theMSSM->eu()*sqr(theSw));
complex<Energy> brac3 = theZfact*theMSSM->ed()*sqr(theSw);
complex<Energy> brac4 = theZfact*theMSSM->eu()*sqr(theSw);
Energy Trib=theMSSM->bottomTrilinear().real();
Energy Trit=theMSSM->topTrilinear().real();
Energy theMu = theMSSM->muParameter();
if( higgs == ParticleID::h0 ) {
// lightest sbottom
complex<Energy> trilinear = theIncludeTriLinear ?
theQb1LR*0.5*mb/theMw*(Trib*theSinA + theMu*theCosA)/theCosB : Energy();
Complex coup = 0.5*UnitRemoval::InvE*
(theQb1L *( sqr(mb)*theSinA/theMw/theCosB - theSinApB*brac1) +
theQb1R *( sqr(mb)*theSinA/theMw/theCosB + theSinApB*brac3)+trilinear);
couplings[0] = make_pair(coup, coup);
// lightest stop
trilinear = theIncludeTriLinear ?
-theQt1LR*0.5*mt/theMw*(Trit*theCosA + theMu*theSinA)/theSinB : Energy();
coup = 0.5*UnitRemoval::InvE*
(theQt1L *( - sqr(mt)*theCosA/theMw/theSinB + theSinApB*brac2) +
theQt1R *( - sqr(mt)*theCosA/theMw/theSinB + theSinApB*brac4)+trilinear);
couplings[1] = make_pair(coup, coup);
// heavier sbottom
trilinear = theIncludeTriLinear ?
theQb2LR*0.5*mb/theMw*(Trib*theSinA + theMu*theCosA)/theCosB : Energy();
coup = 0.5*UnitRemoval::InvE*
(theQb2L *( sqr(mb)*theSinA/theMw/theCosB - theSinApB*brac1) +
theQb2R *( sqr(mb)*theSinA/theMw/theCosB + theSinApB*brac3)+trilinear);
couplings[2] = make_pair(coup, coup);
// heavier stop
trilinear = theIncludeTriLinear ?
-theQt2LR*0.5*mt/theMw*(Trit*theCosA + theMu*theSinA)/theSinB : Energy();
coup = 0.5*UnitRemoval::InvE*
(theQt2L *( - sqr(mt)*theCosA/theMw/theSinB + theSinApB*brac2) +
theQt2R *( - sqr(mt)*theCosA/theMw/theSinB + theSinApB*brac4)+trilinear);
couplings[3] = make_pair(coup, coup);
// top
coup = -0.25*(mt*theCosA/theMw/theSinB);
couplings[4] = make_pair(coup, coup);
// bottom
coup = +0.25*(mb*theSinA/theMw/theCosB);
couplings[5] = make_pair(coup, coup);
}
else {
// lightest sbottom
complex<Energy> trilinear = theIncludeTriLinear ?
theQb1LR*0.5*mb/theMw*(theMu*theSinA - Trib*theCosA)/theCosB: Energy();
Complex coup = 0.5*UnitRemoval::InvE*
(theQb1L *( - sqr(mb)*theCosA/theMw/theCosB + theCosApB*brac1) +
theQb1R *( - sqr(mb)*theCosA/theMw/theCosB - theCosApB*brac3)+trilinear);
couplings[0] = make_pair(coup, coup);
// lightest stop
trilinear = theIncludeTriLinear ?
-theQt1LR*0.5*mt/theMw*(-theMu*theCosA + Trit*theSinA)/theSinB: Energy();
coup = 0.5*UnitRemoval::InvE*
(theQt1L *( - sqr(mt)*theSinA/theMw/theSinB - theCosApB*brac2) +
theQt1R *( - sqr(mt)*theSinA/theMw/theSinB - theCosApB*brac4)+trilinear);
couplings[1] = make_pair(coup, coup);
// heavier sbottom
trilinear = theIncludeTriLinear ?
theQb2LR*0.5*mb/theMw*(theMu*theSinA - Trib*theCosA)/theCosB: Energy();
coup = 0.5*UnitRemoval::InvE*
(theQb2L *( - sqr(mb)*theCosA/theMw/theCosB + theCosApB*brac1) +
theQb2R *( - sqr(mb)*theCosA/theMw/theCosB - theCosApB*brac3)+trilinear);
couplings[2] = make_pair(coup, coup);
// heavier stop
trilinear = theIncludeTriLinear ?
-theQt2LR*0.5*mt/theMw*(-theMu*theCosA + Trit*theSinA)/theSinB: Energy();
coup = 0.5*UnitRemoval::InvE*
(theQt2L *( - sqr(mt)*theSinA/theMw/theSinB - theCosApB*brac2) +
theQt2R *( - sqr(mt)*theSinA/theMw/theSinB - theCosApB*brac4)+trilinear);
couplings[3] = make_pair(coup, coup);
// top
coup = -0.25*mt*theSinA/theMw/theSinB;
couplings[4] = make_pair(coup, coup);
// bottom
coup = -0.25*mb*theCosA/theMw/theCosB;
couplings[5] = make_pair(coup, coup);
}
}
else {
setNParticles(2);
masses.resize(2);
couplings.resize(2);
masses[0] = mt;
masses[1] = mb;
type.resize(2,PDT::Spin1Half);
Complex coup = 0.25*Complex(0., 1.)*mt/theMw/theTanB;
couplings[0] = make_pair(coup, thePseudoScalarTreatment ? coup : -coup);
coup = 0.25*Complex(0., 1.)*mb/theMw*theTanB;
couplings[1] = make_pair(coup, thePseudoScalarTreatment ? coup : -coup);
}
theq2last = q2;
theLastID = higgs;
theHaveCoeff = false;
}
norm(theCouplast);
//calculate tensor coefficients
if( !theHaveCoeff ) {
VVSLoopVertex::setCoupling(q2, particle2, particle3, particle1);
theHaveCoeff = true;
}
}
diff --git a/Models/Susy/SSHHHVertex.cc b/Models/Susy/SSHHHVertex.cc
--- a/Models/Susy/SSHHHVertex.cc
+++ b/Models/Susy/SSHHHVertex.cc
@@ -1,148 +1,149 @@
// -*- C++ -*-
//
// SSHHHVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSHHHVertex class.
//
#include "SSHHHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include <cassert>
using namespace ThePEG::Helicity;
using namespace Herwig;
SSHHHVertex::SSHHHVertex() : theMw(ZERO), theZfact(ZERO), theSw(0.),
theSbpa(0.), theCbpa(0.), theSbma(0.),
theCbma(0.), theS2a(0.), theC2a(0.),
theS2b(0.), theC2b(0.), theElast(0.),
theq2last(ZERO) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void SSHHHVertex::doinit() {
long sec = 35;
for(long h = 25; h < 36; h += 10) {
//self-coupling
addToList(h, h, h);
//first-second
addToList(h,sec,sec);
//pseudo-scalar
addToList(h, 36, 36);
//charged higgs
addToList(h, 37,-37);
sec = 25;
}
SSSVertex::doinit();
tMSSMPtr theMSSM = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !theMSSM )
throw InitException()
<< "SSHHHVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
theMw = getParticleData(ParticleID::Wplus)->mass();
theSw = sqrt(sin2ThetaW());
theZfact = getParticleData(ParticleID::Z0)->mass()/2./
theSw/sqrt(1. - sqr(theSw));
double tanbeta = theMSSM->tanBeta();
double sinbeta = tanbeta/sqrt(1. + sqr(tanbeta));
double cosbeta = sqrt(1. - sqr(sinbeta));
double sinalpha = sin(theMSSM->higgsMixingAngle());
double cosalpha = sqrt( 1. - sqr(sinalpha) );
theS2a = 2.*sinalpha*cosalpha;
theS2b = 2.*sinbeta*cosbeta;
theC2a = cosalpha*cosalpha - sinalpha*sinalpha;
theC2b = cosbeta*cosbeta - sinbeta*sinbeta;
theSbpa = sinbeta*cosalpha + sinalpha*cosbeta;
theCbpa = cosbeta*cosalpha - sinbeta*sinalpha;
theSbma = sinbeta*cosalpha - sinalpha*cosbeta;
theCbma = cosbeta*cosalpha + sinbeta*sinalpha;
}
void SSHHHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(theMw,GeV) << ounit(theZfact,GeV) << theSw
<< theSbpa << theCbpa << theSbma << theCbma << theS2a << theC2a
<< theS2b << theC2b;
}
void SSHHHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(theMw,GeV) >> iunit(theZfact,GeV) >> theSw
>> theSbpa >> theCbpa >> theSbma >> theCbma >> theS2a >> theC2a
>> theS2b >> theC2b;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSHHHVertex,SSSVertex>
describeHerwigSSHHHVertex("Herwig::SSHHHVertex", "HwSusy.so");
void SSHHHVertex::Init() {
static ClassDocumentation<SSHHHVertex> documentation
("This is the coupling of a higgs to a pair of higgs bosons "
"in the MSSM.");
}
void SSHHHVertex::setCoupling(Energy2 q2, tcPDPtr particle1,
tcPDPtr particle2,tcPDPtr particle3) {
long ids[3] = { abs(particle1->id()), abs(particle2->id()),
abs(particle3->id()) };
long h1(0), h2(0), h3(0), hc(0);
for(unsigned int i = 0; i < 3; ++i) {
if( ids[i] == ParticleID::h0) ++h1;
else if( ids[i] == ParticleID::H0) ++h2;
else if( ids[i] == ParticleID::A0) ++h3;
else if( ids[i] == ParticleID::Hplus) ++hc;
else assert(false);
}
assert(h1 + h2 + h3 + hc == 3);
complex<Energy> coupling;
if( h1 == 3 || h2 == 3 ) {
coupling = -3.*theZfact*theC2a;
if( h1 == 3 )
coupling *= theSbpa;
else
coupling *= theCbpa;
}
else if( h1 == 1 ) {
if( h2 == 2 )
coupling = theZfact*( 2.*theS2a*theCbpa + theSbpa*theC2a );
else if( h3 == 2 )
coupling = -theZfact*theC2b*theSbpa;
else if( hc == 2 )
coupling = -theMw*theSbma/theSw - theZfact*theC2b*theSbpa;
else assert(false);
}
else if( h2 == 1 ) {
if( h1 == 2 )
coupling = -theZfact*( 2.*theS2a*theSbpa - theCbpa*theC2a );
else if( h3 == 2 )
coupling = theZfact*theC2b*theCbpa;
else if( hc == 2 )
coupling = -theMw*theCbma/theSw + theZfact*theC2b*theCbpa;
else assert(false);
}
if( q2 != theq2last || theElast==0. ) {
theq2last = q2;
theElast = electroMagneticCoupling(q2);
}
norm(theElast*coupling*UnitRemoval::InvE);
}
diff --git a/Models/Susy/SSHPPVertex.cc b/Models/Susy/SSHPPVertex.cc
--- a/Models/Susy/SSHPPVertex.cc
+++ b/Models/Susy/SSHPPVertex.cc
@@ -1,633 +1,634 @@
// -*- C++ -*-
//
// SSHPPVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSHPPVertex class.
//
#include "SSHPPVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include <cassert>
#include "Herwig/Looptools/clooptools.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSHPPVertex::SSHPPVertex() : theIncludeTriLinear(true),
thePseudoScalarTreatment(false),
theSw(0.), theMw(), theZfact(),
theQt1L(0.), theQt1R(0.), theQt1LR(0.),
theQt2L(0.), theQt2R(0.), theQt2LR(0.),
theQb1L(0.), theQb1R(0.), theQb1LR(0.),
theQb2L(0.), theQb2R(0.), theQb2LR(0.),
theLt1L(0.), theLt1R(0.), theLt1LR(0.),
theLt2L(0.), theLt2R(0.), theLt2LR(0.),
theSfmass(6,ZERO),
theTanB(0.),theSinA(0.),
theCosA(0.), theSinB(0.), theCosB(0.),
theSinApB(0.), theCosApB(0.),
theSinBmA(0.), theCosBmA(0.),
theCouplast(0.),
theq2last(), theHaveCoeff(false), theLastID(0) {
orderInGs(0);
orderInGem(3);
+ colourStructure(ColourStructure::SINGLET);
}
void SSHPPVertex::persistentOutput(PersistentOStream & os) const {
os << theMSSM << theSw << ounit(theMw,GeV) << ounit(theZfact,GeV)
<< theQt1L << theQt1R << theQt1LR << theQt2L << theQt2R << theQt2LR
<< theQb1L << theQb1R << theQb1LR << theQb2L << theQb2R << theQb2LR
<< theLt1L << theLt1R << theLt1LR << theLt2L << theLt2R << theLt2LR
<< thetop << thebot << thetau << theTanB << theIncludeTriLinear
<< theSinA << theCosA << theSinB << theCosB << theSinApB << theCosApB
<< theSinBmA << theCosBmA << thePseudoScalarTreatment
<< ounit(theSfmass, GeV) << theU << theV;
}
void SSHPPVertex::persistentInput(PersistentIStream & is, int) {
is >> theMSSM >> theSw >> iunit(theMw,GeV) >> iunit(theZfact,GeV)
>> theQt1L >> theQt1R >> theQt1LR >> theQt2L >> theQt2R >> theQt2LR
>> theQb1L >> theQb1R >> theQb1LR >> theQb2L >> theQb2R >> theQb2LR
>> theLt1L >> theLt1R >> theLt1LR >> theLt2L >> theLt2R >> theLt2LR
>> thetop >> thebot >> thetau >> theTanB >> theIncludeTriLinear
>> theSinA >> theCosA >> theSinB >> theCosB >> theSinApB >> theCosApB
>> theSinBmA >> theCosBmA >> thePseudoScalarTreatment
>> iunit(theSfmass, GeV) >> theU >> theV;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSHPPVertex,VVSLoopVertex>
describeHerwigSSHPPVertex("Herwig::SSHPPVertex", "HwSusy.so");
void SSHPPVertex::Init() {
static ClassDocumentation<SSHPPVertex> documentation
("This class implements the higgs-gluon-gluon effective "
"vertex in the MSSM including stop, sbottom and top quarks "
"loops.");
static Switch<SSHPPVertex,bool> interfaceIncludeTriLinear
("IncludeTriLinear",
"Whether or not to include the A term squark trilinear couplings",
&SSHPPVertex::theIncludeTriLinear, true, false, false);
static SwitchOption interfaceIncludeTriLinearYes
(interfaceIncludeTriLinear,
"Yes",
"Include them",
true);
static SwitchOption interfaceIncludeTriLinearNo
(interfaceIncludeTriLinear,
"No",
"Don't include them",
false);
static Switch<SSHPPVertex,bool> interfacePseudoScalarTreatment
("PseudoScalarTreatment",
"Whether to treat the pseudoscalar as pseudoscalar or scalar, for testing only",
&SSHPPVertex::thePseudoScalarTreatment, false, false, false);
static SwitchOption interfacePseudoScalarTreatmentPseudoScalar
(interfacePseudoScalarTreatment,
"PseudoScalar",
"Treat as a pseudoscalar, the right physics",
false);
static SwitchOption interfacePseudoScalarTreatmentScalar
(interfacePseudoScalarTreatment,
"Scalar",
"Treat as a scalar for testing",
true);
}
void SSHPPVertex::setCoupling(Energy2 q2, tcPDPtr particle2,
tcPDPtr particle3, tcPDPtr particle1) {
long higgs(abs(particle1->id()));
// check allowed
assert ( higgs == ParticleID::h0 || higgs == ParticleID::H0 ||
higgs == ParticleID::A0 );
assert(particle2->id() == ParticleID::gamma &&
particle3->id() == ParticleID::gamma );
// couplings
if( q2 != theq2last || theCouplast == 0. || higgs != theLastID ) {
Looptools::clearcache();
theCouplast = sqr(electroMagneticCoupling(q2))*weakCoupling(q2);
Energy mt = theMSSM->mass(q2, thetop);
Energy mb = theMSSM->mass(q2, thebot);
Energy mtau = theMSSM->mass(q2, thetau);
masses.clear();
type.clear();
if( higgs == ParticleID::h0 || higgs == ParticleID::H0 ) {
setNParticles(13);
masses.insert(masses.begin(), theSfmass.begin(), theSfmass.end());
masses.push_back(mt);
masses.push_back(mb);
masses.push_back(mtau);
masses.push_back(getParticleData(ParticleID::Hplus)->mass());
masses.push_back(theMw);
masses.push_back(getParticleData(ParticleID::SUSY_chi_1plus)->mass());
masses.push_back(getParticleData(ParticleID::SUSY_chi_2plus)->mass());
type.resize(13, PDT::Spin0);
type[6] = PDT::Spin1Half;
type[7] = PDT::Spin1Half;
type[8] = PDT::Spin1Half;
type[9] = PDT::Spin0;
type[10] = PDT::Spin1;
type[11] = PDT::Spin1Half;
type[12] = PDT::Spin1Half;
couplings.resize(13, make_pair(0., 0.));
complex<Energy> brac1 = theZfact*(0.5 + theMSSM->ed()*sqr(theSw));
complex<Energy> brac2 = theZfact*(0.5 - theMSSM->eu()*sqr(theSw));
complex<Energy> brac3 = theZfact*theMSSM->ed()*sqr(theSw);
complex<Energy> brac4 = theZfact*theMSSM->eu()*sqr(theSw);
complex<Energy> brac5 = theZfact*(0.5 + theMSSM->ee()*sqr(theSw));
complex<Energy> brac6 = theZfact*theMSSM->ee()*sqr(theSw);
Energy Trib=theMSSM->bottomTrilinear().real();
Energy Trit=theMSSM->topTrilinear().real();
Energy Trita=theMSSM->tauTrilinear().real();
Energy theMu = theMSSM->muParameter();
if( higgs == ParticleID::h0 ) {
// lightest sbottom
complex<Energy> trilinear = theIncludeTriLinear ?
theQb1LR*0.5*mb/theMw*(Trib*theSinA + theMu*theCosA)/theCosB : Energy();
Complex coup = 3.*UnitRemoval::InvE*sqr(theMSSM->ed())*
(theQb1L *( sqr(mb)*theSinA/theMw/theCosB - theSinApB*brac1) +
theQb1R *( sqr(mb)*theSinA/theMw/theCosB + theSinApB*brac3) +
trilinear);
couplings[0] = make_pair(coup, coup);
// lightest stop
trilinear = theIncludeTriLinear ?
theQt1LR*0.5*mt/theMw*(Trit*theCosA + theMu*theSinA)/theSinB : Energy();
coup = 3.*UnitRemoval::InvE*sqr(theMSSM->eu())*
(theQt1L *( - sqr(mt)*theCosA/theMw/theSinB + theSinApB*brac2) +
theQt1R *( - sqr(mt)*theCosA/theMw/theSinB + theSinApB*brac4) -
trilinear);
couplings[1] = make_pair(coup, coup);
// lightest stau
trilinear = theIncludeTriLinear ?
theLt1LR*0.5*mtau/theMw*(Trita*theSinA + theMu*theCosA)/theCosB : Energy();
coup = UnitRemoval::InvE*sqr(theMSSM->ee())*
(theLt1L *( sqr(mtau)*theSinA/theMw/theCosB - theSinApB*brac5) +
theLt1R *( sqr(mtau)*theSinA/theMw/theCosB + theSinApB*brac6) +
trilinear);
couplings[2] = make_pair(coup, coup);
// heavier sbottom
trilinear = theIncludeTriLinear ?
theQb2LR*0.5*mb/theMw*(Trib*theSinA + theMu*theCosA)/theCosB : Energy();
coup = 3.*UnitRemoval::InvE*sqr(theMSSM->ed())*
(theQb2L *( sqr(mb)*theSinA/theMw/theCosB - theSinApB*brac1) +
theQb2R *( sqr(mb)*theSinA/theMw/theCosB + theSinApB*brac3) +
trilinear);
couplings[3] = make_pair(coup, coup);
// heavier stop
trilinear = theIncludeTriLinear ?
theQt2LR*0.5*mt/theMw*(Trit*theCosA + theMu*theSinA)/theSinB : Energy();
coup = 3.*UnitRemoval::InvE*sqr(theMSSM->eu())*
(theQt2L*( - sqr(mt)*theCosA/theMw/theSinB + theSinApB*brac2) +
theQt2R*( - sqr(mt)*theCosA/theMw/theSinB + theSinApB*brac4) -
trilinear);
couplings[4] = make_pair(coup, coup);
// heavier stau
trilinear = theIncludeTriLinear ?
theLt2LR*0.5*mtau/theMw*(Trita*theSinA + theMu*theCosA)/theCosB : Energy();
coup = UnitRemoval::InvE*sqr(theMSSM->ee())*
(theLt2L *( sqr(mtau)*theSinA/theMw/theCosB - theSinApB*brac5) +
theLt2R *( sqr(mtau)*theSinA/theMw/theCosB + theSinApB*brac6)+
trilinear);
couplings[5] = make_pair(coup, coup);
// top
coup = - 3.*mt*sqr(theMSSM->eu())*theCosA/2./theMw/theSinB;
couplings[6] = make_pair(coup, coup);
// bottom
coup = 3.*mb*sqr(theMSSM->ed())*theSinA/2./theMw/theCosB;
couplings[7] = make_pair(coup, coup);
// tau
coup = mtau*sqr(theMSSM->ee())*theSinA/2./theMw/theCosB;
couplings[8] = make_pair(coup, coup);
// charged higgs
coup = - UnitRemoval::InvE*theMw*(theSinBmA + 0.5/(1.-sqr(theSw))*
(sqr(theCosB)-sqr(theSinB))*theSinApB);
couplings[9] = make_pair(coup, coup);
// W boson
coup = UnitRemoval::InvE*theMw*theSinBmA;
couplings[10] = make_pair(coup, coup);
// charginos
for(unsigned int ix=0;ix<2;++ix) {
Complex Q = sqrt(0.5)*(*theV)(ix,0)*(*theU)(ix,1);
Complex S = sqrt(0.5)*(*theV)(ix,1)*(*theU)(ix,0);
coup = Q*theSinA-S*theCosA;
couplings[11+ix] = make_pair(conj(coup), coup);
}
}
else {
// lightest sbottom
complex<Energy> trilinear = theIncludeTriLinear ?
theQb1LR*0.5*mb/theMw*(theMu*theSinA - Trib*theCosA)/theCosB: Energy();
Complex coup = 3.*UnitRemoval::InvE*sqr(theMSSM->ed())*
(theQb1L *( - sqr(mb)*theCosA/theMw/theCosB + theCosApB*brac1) +
theQb1R *( - sqr(mb)*theCosA/theMw/theCosB - theCosApB*brac3)+trilinear);
couplings[0] = make_pair(coup, coup);
// lightest stop
trilinear = theIncludeTriLinear ?
-theQt1LR*0.5*mt/theMw*(-theMu*theCosA + Trit*theSinA)/theSinB: Energy();
coup = 3.*UnitRemoval::InvE*sqr(theMSSM->eu())*
(theQt1L *( - sqr(mt)*theSinA/theMw/theSinB - theCosApB*brac2) +
theQt1R *( - sqr(mt)*theSinA/theMw/theSinB - theCosApB*brac4)+trilinear);
couplings[1] = make_pair(coup, coup);
// lightest stau
trilinear = theIncludeTriLinear ?
theLt1LR*0.5*mtau/theMw*(theMu*theSinA - Trita*theCosA)/theCosB: Energy();
coup = UnitRemoval::InvE*sqr(theMSSM->ee())*
(theLt1L *( - sqr(mtau)*theCosA/theMw/theCosB + theCosApB*brac5) +
theLt1R *( - sqr(mtau)*theCosA/theMw/theCosB - theCosApB*brac6)+trilinear);
couplings[2] = make_pair(coup, coup);
// heavier sbottom
trilinear = theIncludeTriLinear ?
theQb2LR*0.5*mb/theMw*(theMu*theSinA - Trib*theCosA)/theCosB: Energy();
coup = 3.*UnitRemoval::InvE*sqr(theMSSM->ed())*
(theQb2L *( - sqr(mb)*theCosA/theMw/theCosB + theCosApB*brac1) +
theQb2R *( - sqr(mb)*theCosA/theMw/theCosB - theCosApB*brac3)+trilinear);
couplings[3] = make_pair(coup, coup);
// heavier stop
trilinear = theIncludeTriLinear ?
-theQt2LR*0.5*mt/theMw*(-theMu*theCosA + Trit*theSinA)/theSinB: Energy();
coup = 3.*UnitRemoval::InvE*sqr(theMSSM->eu())*
(theQt2L *( - sqr(mt)*theSinA/theMw/theSinB - theCosApB*brac2) +
theQt2R *( - sqr(mt)*theSinA/theMw/theSinB - theCosApB*brac4)+trilinear);
couplings[4] = make_pair(coup, coup);
// heavier stau
trilinear = theIncludeTriLinear ?
theLt2LR*0.5*mtau/theMw*(theMu*theSinA - Trita*theCosA)/theCosB: Energy();
coup = UnitRemoval::InvE*sqr(theMSSM->ee())*
(theLt2L *( - sqr(mtau)*theCosA/theMw/theCosB + theCosApB*brac5) +
theLt2R *( - sqr(mtau)*theCosA/theMw/theCosB - theCosApB*brac6)+trilinear);
couplings[5] = make_pair(coup, coup);
// top
coup = -3.*mt*sqr(theMSSM->eu())*theSinA/2./theMw/theSinB;
couplings[6] = make_pair(coup, coup);
// bottom
coup = -3.*mb*sqr(theMSSM->ed())*theCosA/2./theMw/theCosB;
couplings[7] = make_pair(coup, coup);
// tau
coup = -mtau*sqr(theMSSM->ee())*theCosA/2./theMw/theCosB;
couplings[8] = make_pair(coup, coup);
// charged higgs
coup = - UnitRemoval::InvE*theMw*(theCosBmA - 0.5/(1.-sqr(theSw))*
(sqr(theCosB)-sqr(theSinB))*theCosApB);
couplings[9] = make_pair(coup, coup);
// W boson
coup = UnitRemoval::InvE*theMw*theCosBmA;
couplings[10] = make_pair(coup, coup);
// charginos
for(unsigned int ix=0;ix<2;++ix) {
Complex Q = sqrt(0.5)*(*theV)(ix,0)*(*theU)(ix,1);
Complex S = sqrt(0.5)*(*theV)(ix,1)*(*theU)(ix,0);
coup = -Q*theCosA-S*theSinA;
couplings[11+ix] = make_pair(conj(coup), coup);
}
}
}
else {
setNParticles(5);
masses.resize(5);
couplings.resize(5);
masses[0] = mt;
masses[1] = mb;
masses[2] = mtau;
masses[3] = getParticleData(ParticleID::SUSY_chi_1plus)->mass();
masses[4] = getParticleData(ParticleID::SUSY_chi_2plus)->mass();
type.resize(5,PDT::Spin1Half);
// top
Complex coup = 3.*Complex(0., 1.)*sqr(theMSSM->eu())*mt/2./theMw/theTanB;
couplings[0] = make_pair(coup, thePseudoScalarTreatment ? coup : -coup);
// bottom
coup = 3.*Complex(0., 1.)*sqr(theMSSM->ed())*mb/2./theMw*theTanB;
couplings[1] = make_pair(coup, thePseudoScalarTreatment ? coup : -coup);
// tau
coup = Complex(0., 1.)*sqr(theMSSM->ee())*mtau/2./theMw*theTanB;
couplings[2] = make_pair(coup, thePseudoScalarTreatment ? coup : -coup);
// charginos
for(unsigned int ix=0;ix<2;++ix) {
Complex Q = sqrt(0.5)*(*theV)(ix,0)*(*theU)(ix,1);
Complex S = sqrt(0.5)*(*theV)(ix,1)*(*theU)(ix,0);
coup = - Complex(0., 1.)*(Q*theSinB+S*theCosB);
couplings[3+ix] = make_pair(coup, thePseudoScalarTreatment ? coup : -coup);
}
}
theq2last = q2;
theLastID = higgs;
theHaveCoeff = false;
}
norm(theCouplast);
//calculate tensor coefficients
if( !theHaveCoeff ) {
VVSLoopVertex::setCoupling(q2, particle2, particle3, particle1);
theHaveCoeff = true;
}
}
// functions for loops for testing
// namespace {
// Complex F0(double tau) {
// Complex ft;
// if(tau>=1.)
// ft = sqr(asin(1./sqrt(tau)));
// else {
// double etap = 1.+sqrt(1.-tau);
// double etam = 1.-sqrt(1.-tau);
// ft = -0.25*sqr(log(etap/etam)-Constants::pi*Complex(0.,1.));
// }
// return tau*(1.-tau*ft);
// }
// Complex FHalf(double tau,double eta) {
// Complex ft;
// if(tau>=1.)
// ft = sqr(asin(1./sqrt(tau)));
// else {
// double etap = 1.+sqrt(1.-tau);
// double etam = 1.-sqrt(1.-tau);
// ft = -0.25*sqr(log(etap/etam)-Constants::pi*Complex(0.,1.));
// }
// return -2.*tau*(eta+(1.-tau*eta)*ft);
// }
// Complex F1(double tau) {
// Complex ft;
// if(tau>=1.)
// ft = sqr(asin(1./sqrt(tau)));
// else {
// double etap = 1.+sqrt(1.-tau);
// double etam = 1.-sqrt(1.-tau);
// ft = -0.25*sqr(log(etap/etam)-Constants::pi*Complex(0.,1.));
// }
// return 2.+3.*tau+3.*tau*(2.-tau)*ft;
// }
// }
void SSHPPVertex::doinit() {
//PDG codes for particles at vertices
addToList(22,22,25);
addToList(22,22,35);
addToList(22,22,36);
theMSSM = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !theMSSM )
throw InitException()
<< "SSHPPVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
theMw = getParticleData(ParticleID::Wplus)->mass();
thetop = getParticleData(ParticleID::t);
thebot = getParticleData(ParticleID::b);
thetau = getParticleData(ParticleID::tauminus);
theSw = sqrt(sin2ThetaW());
theZfact = getParticleData(ParticleID::Wplus)->mass()/(1. - sqr(theSw));
theSinA = sin(theMSSM->higgsMixingAngle());
theCosA = sqrt(1. - sqr(theSinA));
theTanB = theMSSM->tanBeta();
theSinB = theTanB/sqrt(1. + sqr(theTanB));
theCosB = sqrt( 1. - sqr(theSinB) );
theSinApB = theSinA*theCosB + theCosA*theSinB;
theCosApB = theCosA*theCosB - theSinA*theSinB;
theSinBmA =-theSinA*theCosB + theCosA*theSinB;
theCosBmA = theCosA*theCosB + theSinA*theSinB;
MixingMatrix stop = *theMSSM->stopMix();
MixingMatrix sbot = *theMSSM->sbottomMix();
MixingMatrix stau = *theMSSM->stauMix();
theQt1L = stop(0,0)*stop(0,0);
theQt1R = stop(0,1)*stop(0,1);
theQt1LR = stop(0,1)*stop(0,0) + stop(0,1)*stop(0,0);
theQt2L = stop(1,0)*stop(1,0);
theQt2R = stop(1,1)*stop(1,1);
theQt2LR = stop(1,1)*stop(1,0) + stop(1,0)*stop(1,1);
theQb1L = sbot(0,0)*sbot(0,0);
theQb1R = sbot(0,1)*sbot(0,1);
theQb1LR = sbot(0,1)*sbot(0,0) + sbot(0,1)*sbot(0,0);
theQb2L = sbot(1,0)*sbot(1,0);
theQb2R = sbot(1,1)*sbot(1,1);
theQb2LR = sbot(1,1)*sbot(1,0) + sbot(1,0)*sbot(1,1);
theLt1L = stau(0,0)*stau(0,0);
theLt1R = stau(0,1)*stau(0,1);
theLt1LR = stau(0,1)*stau(0,0) + stau(0,1)*stau(0,0);
theLt2L = stau(1,0)*stau(1,0);
theLt2R = stau(1,1)*stau(1,1);
theLt2LR = stau(1,1)*stau(1,0) + stau(1,0)*stau(1,1);
theU = theMSSM->charginoUMix();
theV = theMSSM->charginoVMix();
assert( theSfmass.size() == 6 );
theSfmass[0] = getParticleData(ParticleID::SUSY_b_1)->mass();
theSfmass[1] = getParticleData(ParticleID::SUSY_t_1)->mass();
theSfmass[2] = getParticleData(ParticleID::SUSY_tau_1minus)->mass();
theSfmass[3] = getParticleData(ParticleID::SUSY_b_2)->mass();
theSfmass[4] = getParticleData(ParticleID::SUSY_t_2)->mass();
theSfmass[5] = getParticleData(ParticleID::SUSY_tau_2minus)->mass();
VVSLoopVertex::doinit();
// test calc of the width
// for(unsigned int ix=0;ix<2;++ix) {
// Energy mh = getParticleData(25+long(ix)*10)->mass();
// Energy mt = theMSSM->mass(sqr(mh ), thetop);
// Energy mb = theMSSM->mass(sqr(mh ), thebot);
// Energy mtau = theMSSM->mass(sqr(mh ), thetau);
// Energy mhp = getParticleData(ParticleID::Hplus)->mass();
// Energy mc[2] = {getParticleData(ParticleID::SUSY_chi_1plus)->mass(),
// getParticleData(ParticleID::SUSY_chi_2plus)->mass()};
// // sbottom
// Complex rsb1,rsb2;
// if(ix==0) {
// rsb1 =
// +theQb1L*(-sqr(mb/theMw)*(1.-sqr(theSw))*theSinA/theCosB
// -(-0.5+sqr(theSw)/3.)*theSinApB)
// +theQb1R*(-sqr(mb/theMw)*(1.-sqr(theSw))*theSinA/theCosB
// +sqr(theSw)/3.*theSinApB);
// rsb2 =
// +theQb2L*(-sqr(mb/theMw)*(1.-sqr(theSw))*theSinA/theCosB
// -(-0.5+sqr(theSw)/3.)*theSinApB)
// +theQb2R*(-sqr(mb/theMw)*(1.-sqr(theSw))*theSinA/theCosB
// +sqr(theSw)/3.*theSinApB);
// }
// else {
// rsb1 =
// +theQb1L*(+sqr(mb/theMw)*(1.-sqr(theSw))*theCosA/theCosB
// +(-0.5+sqr(theSw)/3.)*theCosApB)
// +theQb1R*(+sqr(mb/theMw)*(1.-sqr(theSw))*theCosA/theCosB
// -sqr(theSw)/3.*theCosApB);
// rsb2 =
// +theQb2L*(+sqr(mb/theMw)*(1.-sqr(theSw))*theCosA/theCosB
// +(-0.5+sqr(theSw)/3.)*theCosApB)
// +theQb2R*(+sqr(mb/theMw)*(1.-sqr(theSw))*theCosA/theCosB
// -sqr(theSw)/3.*theCosApB);
// }
// Complex Isb1 = 3.*sqr(1./3.)*rsb1*sqr(theMw/theSfmass[0])/(1.-sqr(theSw))
// *F0(sqr(2.*theSfmass[0]/mh));
// Complex Isb2 = 3.*sqr(1./3.)*rsb2*sqr(theMw/theSfmass[3])/(1.-sqr(theSw))
// *F0(sqr(2.*theSfmass[3]/mh));
// // stop
// Complex rst1,rst2;
// if(ix==0) {
// rst1 =
// +theQt1L*(+sqr(mt/theMw)*(1.-sqr(theSw))*theCosA/theSinB
// -(+0.5-2.*sqr(theSw)/3.)*theSinApB)
// +theQt1R*(+sqr(mt/theMw)*(1.-sqr(theSw))*theCosA/theSinB
// -2.*sqr(theSw)/3.*theSinApB);
// rst2 =
// +theQt2L*(+sqr(mt/theMw)*(1.-sqr(theSw))*theCosA/theSinB
// -(+0.5-2.*sqr(theSw)/3.)*theSinApB)
// +theQt2R*(+sqr(mt/theMw)*(1.-sqr(theSw))*theCosA/theSinB
// -2.*sqr(theSw)/3.*theSinApB);
// }
// else {
// rst1 =
// +theQt1L*(+sqr(mt/theMw)*(1.-sqr(theSw))*theSinA/theSinB
// +(+0.5-2.*sqr(theSw)/3.)*theCosApB)
// +theQt1R*(+sqr(mt/theMw)*(1.-sqr(theSw))*theSinA/theSinB
// +2.*sqr(theSw)/3.*theCosApB);
// rst2 =
// +theQt2L*(+sqr(mt/theMw)*(1.-sqr(theSw))*theSinA/theSinB
// +(+0.5-2.*sqr(theSw)/3.)*theCosApB)
// +theQt2R*(+sqr(mt/theMw)*(1.-sqr(theSw))*theSinA/theSinB
// +2.*sqr(theSw)/3.*theCosApB);
// }
// Complex Ist1 = 3.*sqr(2./3.)*rst1*sqr(theMw/theSfmass[1])/(1.-sqr(theSw))
// *F0(sqr(2.*theSfmass[1]/mh));
// Complex Ist2 = 3.*sqr(2./3.)*rst2*sqr(theMw/theSfmass[4])/(1.-sqr(theSw))
// *F0(sqr(2.*theSfmass[4]/mh));
// // stau
// Complex rstau1,rstau2;
// if(ix==0) {
// rstau1 =
// +theLt1L*(-sqr(mtau/theMw)*(1.-sqr(theSw))*theSinA/theCosB
// -(-0.5+sqr(theSw))*theSinApB)
// +theLt1R*(-sqr(mtau/theMw)*(1.-sqr(theSw))*theSinA/theCosB
// +sqr(theSw)*theSinApB);
// rstau2 =
// +theLt2L*(-sqr(mtau/theMw)*(1.-sqr(theSw))*theSinA/theCosB
// -(-0.5+sqr(theSw))*theSinApB)
// +theLt2R*(-sqr(mtau/theMw)*(1.-sqr(theSw))*theSinA/theCosB
// +sqr(theSw)*theSinApB);
// }
// else {
// rstau1 =
// +theLt1L*(+sqr(mtau/theMw)*(1.-sqr(theSw))*theCosA/theCosB
// +(-0.5+sqr(theSw))*theCosApB)
// +theLt1R*(+sqr(mtau/theMw)*(1.-sqr(theSw))*theCosA/theCosB
// -sqr(theSw)*theCosApB);
// rstau2 =
// +theLt2L*(+sqr(mtau/theMw)*(1.-sqr(theSw))*theCosA/theCosB
// +(-0.5+sqr(theSw))*theCosApB)
// +theLt2R*(+sqr(mtau/theMw)*(1.-sqr(theSw))*theCosA/theCosB
// -sqr(theSw)*theCosApB);
// }
// Complex Istau1 = rstau1*sqr(theMw/theSfmass[2])/(1.-sqr(theSw))
// *F0(sqr(2.*theSfmass[2]/mh));
// Complex Istau2 = rstau2*sqr(theMw/theSfmass[5])/(1.-sqr(theSw))
// *F0(sqr(2.*theSfmass[5]/mh));
// // charged higgs
// Complex rh;
// if(ix==0) {
// rh = theSinBmA+0.5*(sqr(theCosB)-sqr(theSinB))*theSinApB/(1.-sqr(theSw));
// }
// else {
// rh = theCosBmA-0.5*(sqr(theCosB)-sqr(theSinB))*theCosApB/(1.-sqr(theSw));
// }
// Complex Ih = rh*sqr(theMw/mhp)*F0(sqr(2.*mhp/mh));
// // W
// Complex rw;
// if(ix==0) {
// rw = theSinBmA;
// }
// else {
// rw = theCosBmA;
// }
// Complex IW = rw*F1(sqr(2.*theMw/mh));
// // top
// Complex rt;
// if(ix==0) {
// rt = theCosA/theSinB;
// }
// else {
// rt = theSinA/theSinB;
// }
// Complex Itop = 3.*sqr(2./3.)*rt*FHalf(sqr(2.*mt/mh),1.);
// // bottom
// Complex rb;
// if(ix==0) {
// rb =-theSinA/theCosB;
// }
// else {
// rb = theCosA/theCosB;
// }
// Complex Ibot = 3.*sqr(1./3.)*rb*FHalf(sqr(2.*mb/mh),1.);
// // tau
// Complex rtau;
// if(ix==0) {
// rtau =-theSinA/theCosB;
// }
// else {
// rtau = theCosA/theCosB;
// }
// Complex Itau = rtau*FHalf(sqr(2.*mtau/mh),1.);
// // charginos
// Complex rc[2],IC[2];
// for(unsigned int ic=0;ic<2;++ic) {
// Complex Q = sqrt(0.5)*(*theV)(ic,0)*(*theU)(ic,1);
// Complex S = sqrt(0.5)*(*theV)(ic,1)*(*theU)(ic,0);
// if(ix==0) {
// rc[ic] = 2.*(S*theCosA-Q*theSinA);
// }
// else {
// rc[ic] = 2.*(S*theSinA+Q*theCosA);
// }
// IC[ic] = rc[ic]*FHalf(sqr(2.*mc[ic]/mh),1.)*theMw/mc[ic];
// }
// Energy pre = sqr(mh/theMw)*mh/1024./pow(Constants::pi,3)
// *sqr(weakCoupling(sqr(mh))*sqr(electroMagneticCoupling(sqr(mh)))/4./Constants::pi);
// cerr << "testing lighter sbottom" << ix << " "
// << pre*std::norm(Isb1)/GeV << "\n";
// cerr << "testing heavier sbottom" << ix << " "
// << pre*std::norm(Istau2)/GeV << "\n";
// cerr << "testing lighter stop" << ix << " "
// << pre*std::norm(Ist1)/GeV << "\n";
// cerr << "testing heavier stop" << ix << " "
// << pre*std::norm(Ist2)/GeV << "\n";
// cerr << "testing lighter stau" << ix << " "
// << pre*std::norm(Istau1)/GeV << "\n";
// cerr << "testing heavier stau" << ix << " "
// << pre*std::norm(Isb2)/GeV << "\n";
// cerr << "testing top " << ix << " "
// << pre*std::norm(Itop)/GeV << "\n";
// cerr << "testing bottom " << ix << " "
// << pre*std::norm(Ibot)/GeV << "\n";
// cerr << "testing tau " << ix << " "
// << pre*std::norm(Itau)/GeV << "\n";
// cerr << "testing higgs " << ix << " "
// << pre*std::norm(Ih)/GeV << "\n";
// cerr << "testing W " << ix << " "
// << pre*std::norm(IW)/GeV << "\n";
// cerr << "testing chi1 " << ix << " "
// << pre*std::norm(IC[0])/GeV << "\n";
// cerr << "testing chi2 " << ix << " "
// << pre*std::norm(IC[1])/GeV << "\n";
// cerr << "testing chi " << ix << " "
// << pre*std::norm(IC[0]+IC[1])/GeV << "\n";
// cerr << "testing higgs width " << ix << " "
// << pre*std::norm(Isb1+Isb2+Ist1+Ist2+Istau1+Istau2+
// Itop+Ibot+Itau+Ih+IW+IC[0]+IC[1])/GeV << "\n";
// }
if(loopToolsInitialized()) Looptools::ltexi();
}
diff --git a/Models/Susy/SSHSFSFVertex.cc b/Models/Susy/SSHSFSFVertex.cc
--- a/Models/Susy/SSHSFSFVertex.cc
+++ b/Models/Susy/SSHSFSFVertex.cc
@@ -1,448 +1,449 @@
// -*- C++ -*-
//
// SSHSFSFVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSHSFSFVertex class.
//
#include "SSHSFSFVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include <cassert>
using namespace ThePEG::Helicity;
using namespace Herwig;
SSHSFSFVertex::SSHSFSFVertex() : theMix(3), theTriC(9, complex<Energy>(ZERO)),
theSinA(0.0),
theCosA(0.0), theSinB(0.0), theCosB(0.0),
theTanB(0.0), theSinAB(0.0), theCosAB(0.0),
theMw(ZERO), theMz(ZERO), theMu(ZERO),
theSw(0.0), theCw(0.0), theCoupLast(ZERO),
theq2Last(ZERO), theHLast(0), theSF1Last(0),
theSF2Last(0) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SSHSFSFVertex::doinit() {
int higgs = 25;
//h0,H0
for(unsigned int i = 0; i < 2; ++i) {
if( i == 1 ) higgs = 35;
//quarks
for(unsigned int j = 1; j < 7; ++j) {
long lj = 1000000 + j;
long rj = 2000000 + j;
//LLbar
addToList(higgs,lj,-lj);
//RRbar
addToList(higgs,rj,-rj);
//LRbar
addToList(higgs,lj,-rj);
//RLbar
addToList(higgs,rj,-lj);
}
for(unsigned int j = 11; j < 17; ++j) {
long lj = 1000000 + j;
long rj = 2000000 + j;
addToList(higgs,lj,-lj);
if( j % 2 != 0) {
addToList(higgs,rj,-rj);
//LRbar
addToList(higgs,lj,-rj);
//RLbar
addToList(higgs,rj,-lj);
}
}
}
//A0
for(unsigned int j = 1; j < 7; ++j) {
long lj = 1000000 + j;
long rj = 2000000 + j;
//LRbar
addToList(36,lj,-rj);
//RLbar
addToList(36,rj,-lj);
}
for(unsigned int j = 11; j < 17; j += 2) {
long lj = 1000000 + j;
long rj = 2000000 + j;
addToList(36,lj,-rj);
addToList(36,rj,-lj);
}
//outgoing H+
for(long ii = 2; ii < 7; ii += 2) {
//LL
addToList(37, 999999 + ii, -1000000 - ii);
//RR
addToList(37, 1999999 + ii, -2000000 - ii);
//RL
addToList(37, 1999999 + ii, -1000000 - ii);
//LR
addToList(37, 999999 + ii, -2000000 - ii);
}
for(long ii = 11; ii < 17; ii += 2) {
addToList(37, 1000000 + ii, -1000001 - ii);
addToList(37, 2000000 + ii, -1000001 - ii);
}
//outgoing H-
for(long ii = 2; ii < 7; ii += 2) {
//LL
addToList(-37, 1000000 + ii, -999999 - ii);
//RR
addToList(-37, 2000000 + ii, -1999999 - ii);
//RL
addToList(-37, 1000000 + ii, -1999999 - ii);
//LR
addToList(-37, 2000000 + ii, -999999 - ii);
}
for(long ii = 11; ii < 17; ii += 2) {
addToList(-37, 1000001 + ii, -1000000 - ii);
addToList(-37, 1000001 + ii, -2000000 - ii);}
SSSVertex::doinit();
theMSSM = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !theMSSM )
throw InitException() << "SSHSFSFVertex::doinit - A problem occurred"
<< "while trying to cast the SM pointer to "
<< "a Susy one." << Exception::abortnow;
//mixing vector should have been sized correctly already
assert( theMix.size() == 3 );
theMix[0] = theMSSM->stopMix();
theMix[1] = theMSSM->sbottomMix();
theMix[2] = theMSSM->stauMix();
if(!theMix[0] || !theMix[1] || !theMix[2])
throw InitException() << "SSHSFSFVertex::doinit - "
<< "A null mixing matrix pointer. stop: " << theMix[0]
<< " sbottom: " << theMix[1] << " stau: " << theMix[2]
<< Exception::abortnow;
//trilinear vector should have been sized correctly already
assert( theTriC.size() == 9 );
//vector has been zeroed in constructor
theTriC[4]=theMSSM->bottomTrilinear().real();
theTriC[5]=theMSSM->topTrilinear().real();
theTriC[8]=theMSSM->tauTrilinear().real();
//Masses
theMw = getParticleData(ParticleID::Wplus)->mass();
theMz = getParticleData(ParticleID::Z0)->mass();
//parameters
theSinA = sin(theMSSM->higgsMixingAngle());
theCosA = cos(theMSSM->higgsMixingAngle());
theTanB = theMSSM->tanBeta();
theMu = theMSSM->muParameter();
theSinB = theTanB/sqrt(1. + sqr(theTanB));
theCosB = sqrt( 1. - sqr(theSinB) );
theSinAB = theSinA*theCosB + theCosA*theSinB;
theCosAB = theCosA*theCosB - theSinA*theSinB;
theSw = sqrt(sin2ThetaW());
theCw = sqrt(1. - sin2ThetaW());
}
void SSHSFSFVertex::persistentOutput(PersistentOStream & os) const {
os << theMix << theSinA << theCosA << theSinB << theMSSM
<< theCosB << theTanB << ounit(theMu, GeV) << theSinAB << theCosAB
<< ounit(theMw,GeV) << ounit(theMz,GeV) << theSw << theCw
<< ounit(theTriC,GeV);
}
void SSHSFSFVertex::persistentInput(PersistentIStream & is, int) {
is >> theMix >> theSinA >> theCosA >> theSinB >> theMSSM
>> theCosB >> theTanB >> iunit(theMu, GeV) >> theSinAB >> theCosAB
>> iunit(theMw,GeV) >> iunit(theMz,GeV) >> theSw >> theCw
>> iunit(theTriC,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSHSFSFVertex,SSSVertex>
describeHerwigSSHSFSFVertex("Herwig::SSHSFSFVertex", "HwSusy.so");
void SSHSFSFVertex::Init() {
static ClassDocumentation<SSHSFSFVertex> documentation
("The coupling of an MSSM Higgs to a pair of sfermions.");
}
void SSHSFSFVertex::setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2, tcPDPtr part3) {
// extract particle ids
long higgs(part1->id()), sq1(part2->id()), sq2(part3->id());
// higgs first
if(abs(sq1)<100) swap(higgs,sq1);
if(abs(sq2)<100) swap(higgs,sq2);
// squark second, antisquark third
if(sq1<0) swap(sq1,sq2);
assert( higgs == 25 || higgs == 35 ||
higgs == 36 || abs(higgs) == 37 );
sq2 *=-1;
assert(sq1>0&&sq2>0);
// running coupling
if( q2 != theq2Last || thegLast==0.) {
thegLast = weakCoupling(q2);
theq2Last = q2;
}
if( higgs == theHLast && sq1 == theSF1Last && sq2 == theSF2Last) {
norm(thegLast*theCoupLast*UnitRemoval::InvE);
return;
}
theHLast = higgs;
theSF1Last = sq1;
theSF2Last = sq2;
if( abs(higgs) == ParticleID::Hplus )
chargedHiggs(q2,sq1, sq2);
else {
long sm(0);
unsigned int alpha(sq1/1000000 - 1), beta(sq2/1000000 - 1);
if( sq1/1000000 == 2 )
sm = sq1 - 2000000;
else
sm = sq1 - 1000000;
if( sm < 7 ) {
if( sm % 2 == 0 )
upSF(q2,higgs, sm, alpha, beta);
else
downSF(q2,higgs, sm, alpha, beta);
}
else
leptonSF(q2,higgs, sm, alpha, beta);
}
norm(thegLast*theCoupLast*UnitRemoval::InvE);
}
void SSHSFSFVertex::downSF(Energy2 q2, long higgs, long sm,
unsigned int alpha, unsigned int beta) {
assert( sm < 7 && sm % 2 != 0);
Energy fmass = theMSSM->mass(q2,getParticleData(sm));
double mfacta = 0.5*fmass/theMw;
if( higgs == ParticleID::A0 ) {
theCoupLast = -Complex(0.,1.)*mfacta*(theTriC[sm - 1]*theTanB + theMu);
if(sm == 5) {
// do not revert to *=, breaks with XCode 5.1
theCoupLast = theCoupLast * (
(*theMix[1])(alpha, 1) * (*theMix[1])(beta , 0) -
(*theMix[1])(alpha, 0) * (*theMix[1])(beta , 1) );
}
else if(alpha<beta) theCoupLast *= -1.;
return;
}
Energy mfactb = sqr(fmass)/theMw/theCosB;
Energy facta = theMz/theCw;
double factb = theMSSM->ed()*theSw*theSw;
//mixing parameters
Complex q1a(0.), q1b(0.), q2a(0.), q2b(0.);
if( sm == 1 || sm == 3) {
q1a = (alpha == 0) ? 1.0 : 0.0;
q1b = (beta == 0) ? 1.0 : 0.0;
q2a = (alpha == 0) ? 0.0 : 1.0;
q2b = (beta == 0) ? 0.0 : 1.0;
}
else {
q1a = (*theMix[1])(alpha, 0);
q1b = (*theMix[1])(beta, 0);
q2a = (*theMix[1])(alpha, 1);
q2b = (*theMix[1])(beta, 1);
}
Complex fbrac = (q1a*q1b*(0.5 + factb) - factb*q2a*q2b);
Complex sbrac = (q1a*q1b + q2a*q2b);
Complex tbrac = (q2a*q1b + q1a*q2b);
if( higgs == ParticleID::h0) {
theCoupLast = -facta*theSinAB*fbrac + mfactb*theSinA*sbrac
+ mfacta*(theTriC[sm - 1]*theSinA + theMu*theCosA)*tbrac/theCosB;
}
else if( higgs == ParticleID::H0 ) {
theCoupLast = facta*theCosAB*fbrac - mfactb*theCosA*sbrac
+ mfacta*(theMu*theSinA - theTriC[sm - 1]*theCosA)*tbrac/theCosB;
}
else
throw HelicityConsistencyError()
<< "SSHSFSFVertex::downSF - Unrecognised higgs particle "
<< higgs << Exception::warning;
}
void SSHSFSFVertex::upSF(Energy2 q2, long higgs, long sm,
unsigned int alpha, unsigned int beta) {
assert( sm < 7 && sm % 2 == 0);
Energy fmass = theMSSM->mass(q2,getParticleData(sm));
double mfacta = 0.5*fmass/theMw;
if( higgs == ParticleID::A0 ){
theCoupLast = -Complex(0.,1.)*mfacta*(theTriC[sm - 1]/theTanB + theMu);
if(sm == 6) {
// do not revert to *=, breaks with XCode 5.1
theCoupLast = theCoupLast * (
(*theMix[0])(alpha, 1) * (*theMix[0])(beta , 0) -
(*theMix[0])(alpha, 0) * (*theMix[0])(beta , 1) );
}
else if(alpha<beta) theCoupLast *= -1.;
return;
}
Energy mfactb = sqr(fmass)/theMw/theSinB;
Energy facta = theMz/theCw;
double factb = theMSSM->eu()*sqr(theSw);
//mixing parameters
Complex q1a(0.), q1b(0.), q2a(0.), q2b(0.);
if( sm == 2 || sm == 4) {
q1a = (alpha == 0) ? 1.0 : 0.0;
q1b = (beta == 0) ? 1.0 : 0.0;
q2a = (alpha == 0) ? 0.0 : 1.0;
q2b = (beta == 0) ? 0.0 : 1.0;
}
else {
q1a = (*theMix[0])(alpha, 0);
q1b = (*theMix[0])(beta , 0);
q2a = (*theMix[0])(alpha, 1);
q2b = (*theMix[0])(beta , 1);
}
Complex fbrac = (q1a*q1b*(0.5 - factb) + factb*q2a*q2b);
Complex sbrac = (q1a*q1b + q2a*q2b);
Complex tbrac = (q2a*q1b + q1a*q2b);
if( higgs == ParticleID::h0) {
theCoupLast = facta*theSinAB*fbrac - mfactb*theCosA*sbrac
- mfacta*(theTriC[sm - 1]*theCosA + theMu*theSinA)*tbrac/theSinB;
}
else if( higgs == ParticleID::H0 ) {
theCoupLast = -facta*theCosAB*fbrac - mfactb*theSinA*sbrac
- mfacta*(theTriC[sm - 1]*theSinA - theMu*theCosA )*tbrac/theSinB;
}
else
assert(false);
}
void SSHSFSFVertex::leptonSF(Energy2 q2, long higgs, long sm,
unsigned int alpha, unsigned int beta) {
assert( sm >= 11 && sm <= 16 );
Energy facta = theMz/theCw;
if( sm % 2 == 0 ) {
theCoupLast = complex<Energy>(facta/2.);
if( higgs == ParticleID::h0)
theCoupLast *= theSinAB;
else
theCoupLast *= -theCosAB;
return;
}
Energy fmass = theMSSM->mass(q2,getParticleData(sm));
double mfacta = fmass/2./theMw;
if( higgs == ParticleID::A0 ) {
theCoupLast = -Complex(0.,1.)*mfacta*(theTriC[(sm + 1)/2]*theTanB + theMu);
if(sm == 15) {
// do not revert to *=, breaks with XCode 5.1
theCoupLast = theCoupLast * (
(*theMix[2])(alpha, 1) * (*theMix[2])(beta , 0) -
(*theMix[2])(alpha, 0) * (*theMix[2])(beta , 1) );
}
else if(alpha<beta) theCoupLast *= -1.;
return;
}
Energy mfactb = fmass*fmass/theMw/theCosB;
double factb = theSw*theSw;
//mixing parameters
Complex l1a(0.), l1b(0.), l2a(0.), l2b(0.);
if( sm == 11 || sm == 13) {
l1a = (alpha == 0) ? 1.0 : 0.0;
l1b = (beta == 0) ? 1.0 : 0.0;
l2a = (alpha == 0) ? 0.0 : 1.0;
l2b = (beta == 0) ? 0.0 : 1.0;
}
else {
l1a = (*theMix[2])(alpha, 0);
l1b = (*theMix[2])(beta, 0);
l2a = (*theMix[2])(alpha, 1);
l2b = (*theMix[2])(beta, 1);
}
Complex fbrac = (l1a*l1b*(0.5 - factb) + factb*l2a*l2b);
Complex sbrac = (l1a*l1b + l2a*l2b);
Complex tbrac = (l2a*l1b + l1a*l2b);
if( higgs == ParticleID::h0) {
theCoupLast = -facta*theSinAB*fbrac + mfactb*theSinA*sbrac
+ mfacta*(theTriC[(sm + 1)/2]*theSinA + theMu*theCosA)*tbrac/theCosB;
}
else if( higgs == ParticleID::H0 ) {
theCoupLast = facta*theCosAB*fbrac - mfactb*theCosA*sbrac
+ mfacta*(theMu*theSinA - theTriC[(sm + 1)/2]*theCosA)*tbrac/theCosB;
}
else
throw HelicityConsistencyError()
<< "SSHSFSFVertex::leptonSF - Unrecognised higgs particle "
<< higgs << Exception::warning;
}
void SSHSFSFVertex::chargedHiggs(Energy2 q2, long id1, long id2) {
//have id1 as up-type
if( id1 % 2 != 0)
swap(id1, id2);
unsigned int beta(0);
if( id2/1000000 == 2 )
beta = 1;
else
beta = 0;
long smd = (beta == 0) ? id2 - 1000000 : id2 - 2000000;
Energy mfd = theMSSM->mass(q2,getParticleData(smd));
Energy2 facta = sqr(theMw)*2.*theSinB*theCosB;
if( smd == 11 || smd == 13 || smd == 15) {
Complex l1b = (beta == 0) ? 1.0 : 0.0;
Complex l2b = (beta == 0) ? 0.0 : 1.0;
if( smd == 15 ) {
l1b = (*theMix[2])(beta, 0);
l2b = (*theMix[2])(beta, 1);
}
theCoupLast = ( l1b*(mfd*mfd*theTanB - facta)
+ l2b*mfd*(theTriC[(smd + 1)/2]*theTanB + theMu)
)/theMw/sqrt(2.);
}
else {
unsigned int alpha(0);
if( id1/1000000 == 2 )
alpha = 1;
else
alpha = 0;
long smu = (alpha == 0) ? id1 - 1000000 : id1 - 2000000;
Energy mfu = theMSSM->mass(q2,getParticleData(smu));
Complex q1a(0.0), q1b(0.0), q2a(0.0), q2b(0.0);
if( smu == 2 || smu == 4 ) {
q1a = (alpha == 0) ? 1.0 : 0.0;
q2a = (alpha == 0) ? 0.0 : 1.0;
}
else {
q1a = (*theMix[0])(alpha,0);
q2a = (*theMix[0])(alpha,1);
}
if( smd == 1 || smd == 3 ) {
q1b = (beta == 0) ? 1.0 : 0.0;
q2b = (beta == 0) ? 0.0 : 1.0;
}
else {
q1b = (*theMix[1])(beta,0);
q2b = (*theMix[1])(beta,1);
}
theCoupLast = ( q1a*q1b*(mfd*mfd*theTanB + mfu*mfu/theTanB - facta)
+ q2a*q2b*mfu*mfd*(theTanB + (1./theTanB))
+ q1a*q2b*mfd*(theTriC[smd - 1]*theTanB + theMu)
+ q2a*q1b*mfu*(theMu + theTriC[smu-1]/theTanB)
)/theMw/sqrt(2.);
}
}
diff --git a/Models/Susy/SSNCTVertex.cc b/Models/Susy/SSNCTVertex.cc
--- a/Models/Susy/SSNCTVertex.cc
+++ b/Models/Susy/SSNCTVertex.cc
@@ -1,182 +1,183 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSNCTVertex class.
//
#include "SSNCTVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
using namespace Herwig;
SSNCTVertex::SSNCTVertex() : MX_(2.e16*GeV),
sw_(0.), cw_(0.), mw_(ZERO),
sb_(0.), cb_(0.), q2last_(), couplast_(0.),
leftlast_(0.), rightlast_(0.), idlast_(0),
epsilon_(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
IBPtr SSNCTVertex::clone() const {
return new_ptr(*this);
}
IBPtr SSNCTVertex::fullclone() const {
return new_ptr(*this);
}
void SSNCTVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(MX_,GeV) << nmix_ << sw_ << cw_ << ounit(mw_,GeV)
<< sb_ << cb_ << ounit(q2last_,GeV2) << couplast_
<< leftlast_ << rightlast_ << idlast_ << epsilon_;
}
void SSNCTVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(MX_,GeV) >> nmix_ >> sw_ >> cw_ >> iunit(mw_,GeV)
>> sb_ >> cb_ >> iunit(q2last_,GeV2) >> couplast_
>> leftlast_ >> rightlast_ >> idlast_ >> epsilon_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSNCTVertex,Helicity::FFSVertex>
describeHerwigSSNCTVertex("Herwig::SSNCTVertex", "HwSusy.so");
void SSNCTVertex::Init() {
static ClassDocumentation<SSNCTVertex> documentation
("The SSNCTVertex class implements the flavour violating"
" coupling of the top quark to a charm quark and a neutralino");
static Parameter<SSNCTVertex,Energy> interfaceMX
("MX",
"Unification scale for the loop",
&SSNCTVertex::MX_, GeV, 2.e16*GeV, 1.e14*GeV, 1.e20*GeV,
false, false, Interface::limited);
}
void SSNCTVertex::doinit() {
long neut[5] = {1000022, 1000023, 1000025, 1000035, 1000045};
for(unsigned int nl = 0; nl < 5; ++nl) {
addToList( neut[nl], 4, -1000006 );
addToList( neut[nl], -4, 1000006 );
}
FFSVertex::doinit();
// get the MSSM
MSSMPtr model = dynamic_ptr_cast<MSSMPtr>(generator()->standardModel());
if(!model)
throw InitException() << "SSNCTVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
// standard SUSY couplings
// neutralino mixing
nmix_ = model->neutralinoMix();
if(!nmix_) throw InitException() << "SSNCTVertex::doinit() "
<< "The neutralino mixing matrix pointer is null."
<< Exception::abortnow;
sw_ = sqrt(sin2ThetaW());
mw_ = getParticleData(24)->mass();
double tb = model->tanBeta();
cw_ = sqrt(1. - sqr(sw_));
sb_ = tb/sqrt(1 + sqr(tb));
cb_ = sqrt(1 - sqr(sb_));
// susy breaking scale
Energy mSUSY =
sqrt(max(sqr(getParticleData(ParticleID::Z0)->mass()),
model->Mq3L()*model->MtR()));
// CKM factor
ThePEG::Ptr<Herwig::StandardCKM>::transient_const_pointer
CKMptr = ThePEG::dynamic_ptr_cast< ThePEG::Ptr<Herwig::StandardCKM>::
transient_const_pointer>(model->CKM());
if(!CKMptr)
throw Exception() << "Must have access to the Herwig::StandardCKM object"
<< "for the CKM matrix in SSNCTVertex::doinit()"
<< Exception::runerror;
vector< vector<Complex > > CKM;
CKM = CKMptr->getUnsquaredMatrix(generator()->standardModel()->families());
// SM masses
Energy mb = getParticleData(ParticleID::b)->mass();
Energy mt = getParticleData(ParticleID::t)->mass();
// squark masses
Energy mt1 = getParticleData(1000006)->mass();
Energy mcL = getParticleData(1000004)->mass();
// mixing parameter
Complex pre = sqr(weakCoupling(sqr(mSUSY)))/16./sqr(Constants::pi)*
log(MX_/mSUSY)*sqr(double(mb/mw_))/sqr(cb_)*conj(CKM[2][2])*CKM[1][2];
complex<Energy2> deltaL = -0.5*pre*(sqr(model->Mq2L())+sqr(model->Mq3L()) +
2.*model->Mh12()+2.*sqr(model->MbR()) +
2.*real( model->bottomTrilinear()*
conj(model->bottomTrilinear())));
complex<Energy2> deltaR = pre*mt*conj(model->bottomTrilinear());
if(abs(mt1-mcL)/abs(mt1+mcL)<1e-10) {
epsilon_ = 0.;
}
else {
epsilon_ = (deltaL*(*model->stopMix())(0,0)-
deltaR*(*model->stopMix())(0,1))/(sqr(mt1)-sqr(mcL));
}
}
void SSNCTVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr ) {
long ism(abs(part1->id())), ineut(abs(part2->id()));
tcPDPtr smfermion = part1;
if( ism / 1000000 == 1 ) {
swap( ism, ineut);
smfermion = part2;
}
if(q2!= q2last_ || couplast_==0.) {
couplast_ = -sqrt(2)*weakCoupling(q2);
q2last_=q2;
}
norm(couplast_);
if( ineut != idlast_) {
idlast_ = ineut;
// determine neutralino
unsigned nl(0);
switch( ineut ) {
case 1000022 : nl = 0;
break;
case 1000023 : nl = 1;
break;
case 1000025 : nl = 2;
break;
case 1000035 : nl = 3;
break;
case 1000045 : nl = 4;
break;
default : assert(false);
}
// common primed neutralino matrices
Complex n2prime = (*nmix_)(nl,1)*cw_ - (*nmix_)(nl,0)*sw_;
Complex n1prime = (*nmix_)(nl,0)*cw_ + (*nmix_)(nl,1)*sw_;
tcPDPtr smf = getParticleData(ism);
double qf = smf->charge()/eplus;
//Complex bracketl = qf*sw_*( conj(n1prime) - sw_*conj(n2prime)/cw_ );
double lambda(0.);
//neutralino mixing element
Complex nlf(0.);
lambda = -0.5 + qf*sqr(sw_);
nlf = (*nmix_)(nl,3);
Complex bracketr = sw_*qf*n1prime - n2prime*lambda/cw_;
leftlast_ = 0.;
rightlast_ = epsilon_*bracketr;
}
//determine the helicity order of the vertex
if( smfermion->id() < 0 ) {
left(conj(rightlast_));
right(conj(leftlast_));
}
else {
left(leftlast_);
right(rightlast_);
}
}
diff --git a/Models/Susy/SSNFSVertex.cc b/Models/Susy/SSNFSVertex.cc
--- a/Models/Susy/SSNFSVertex.cc
+++ b/Models/Susy/SSNFSVertex.cc
@@ -1,226 +1,227 @@
// -*- C++ -*-
//
// SSNFSVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSNFSVertex class.
//
#include "SSNFSVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSNFSVertex::SSNFSVertex() : _sw(0.), _cw(0.), _mw(),
_sb(0.), _cb(0.), _q2last(), _couplast(0.),
_leftlast(0.), _rightlast(0.), _id1last(0),
_id2last(0),
yukawa_(1) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SSNFSVertex::persistentOutput(PersistentOStream & os) const {
os << _stop << _sbot << _stau << _nmix << _theSS << _sw << _cw
<< ounit(_mw,GeV) << _sb << _cb << yukawa_;
}
void SSNFSVertex::persistentInput(PersistentIStream & is, int) {
is >> _stop >> _sbot >> _stau >> _nmix >> _theSS >> _sw >> _cw
>> iunit(_mw,GeV) >> _sb >> _cb >> yukawa_;
}
void SSNFSVertex::doinit() {
long neut[5] = {1000022, 1000023, 1000025, 1000035, 1000045};
for(unsigned int nl = 0; nl < 5; ++nl) {
//quarks
for(long ix=1;ix<7;++ix){
addToList( neut[nl], ix, -(1000000+ix) );
addToList( neut[nl], ix, -(2000000+ix) );
addToList( neut[nl], -ix, (1000000+ix) );
addToList( neut[nl], -ix, (2000000+ix) );
}
//leptons
for(long ix=11;ix<17;++ix) {
addToList( neut[nl], ix, -(1000000+ix) );
addToList( neut[nl], -ix, (1000000+ix) );
if( ix % 2 != 0 ) {
addToList( neut[nl], ix, -(2000000+ix) );
addToList( neut[nl], -ix, (2000000+ix) );
}
}
}
FFSVertex::doinit();
_theSS = dynamic_ptr_cast<MSSMPtr>(generator()->standardModel());
if(!_theSS)
throw InitException() << "SSGSSVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
_stop = _theSS->stopMix();
_sbot = _theSS->sbottomMix();
_stau = _theSS->stauMix();
_nmix = _theSS->neutralinoMix();
if(!_stop || !_stau || !_sbot || !_nmix)
throw InitException() << "SSNFSVertex::doinit() - "
<< "A mixing matrix pointer is null."
<< " stop: " << _stop << " sbottom: "
<< _sbot << " stau: " << _stau
<< " N: " << _nmix << Exception::abortnow;
_sw = sqrt(sin2ThetaW());
_mw = getParticleData(24)->mass();
double tb = _theSS->tanBeta();
_cw = sqrt(1. - sqr(_sw));
_sb = tb/sqrt(1 + sqr(tb));
_cb = sqrt(1 - sqr(_sb));
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSNFSVertex,FFSVertex>
describeHerwigSSNFSVertex("Herwig::SSNFSVertex", "HwSusy.so");
void SSNFSVertex::Init() {
static ClassDocumentation<SSNFSVertex> documentation
("The SSNFSVertex implements the coupling of a neutralino to "
"a fermion-sfermion");
static Switch<SSNFSVertex,unsigned int> interfaceYukawa
("Yukawa",
"Whether or not to include the Yukawa type couplings",
&SSNFSVertex::yukawa_, 1, false, false);
static SwitchOption interfaceYukawaYes
(interfaceYukawa,
"Yes",
"Include the terms",
1);
static SwitchOption interfaceYukawaNo
(interfaceYukawa,
"No",
"Don't include them",
0);
static SwitchOption interfaceYukawa3rdGen
(interfaceYukawa,
"ThirdGeneration",
"Only include for the third generation",
2);
}
void SSNFSVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
long isc(abs(part3->id())), ism(abs(part1->id())),
ineut(abs(part2->id()));
tcPDPtr smfermion = part1;
if( ism / 1000000 == 1 ) {
swap( ism, ineut);
smfermion = part2;
}
if(q2!=_q2last || _couplast==0.) {
_couplast = -sqrt(2)*weakCoupling(q2);
_q2last=q2;
}
norm(_couplast);
if( ineut != _id1last || ism != _id2last || isc != _id3last ) {
_id1last = ineut;
_id2last = ism;
_id3last = isc;
// determine neutralino and squark eigenstates
unsigned int alpha(isc/1000000 - 1), nl(0);
switch( ineut ) {
case 1000022 : nl = 0;
break;
case 1000023 : nl = 1;
break;
case 1000025 : nl = 2;
break;
case 1000035 : nl = 3;
break;
case 1000045 : nl = 4;
break;
default : assert(false);
}
// common primed neutralino matrices
Complex n2prime = (*_nmix)(nl,1)*_cw - (*_nmix)(nl,0)*_sw;
//handle neutrinos first
if( ism == 12 || ism == 14 || ism == 16 ) {
_leftlast = Complex(0., 0.);
_rightlast = n2prime/2./_cw;
}
else {
Complex n1prime = (*_nmix)(nl,0)*_cw + (*_nmix)(nl,1)*_sw;
tcPDPtr smf = getParticleData(ism);
double qf = smf->charge()/eplus;
Complex bracketl = qf*_sw*( conj(n1prime) - _sw*conj(n2prime)/_cw );
double y = 0.;
if(yukawa_==1 || ((ism==5 || ism==6 || ism==15) && yukawa_==2))
y = double(_theSS->mass(q2, smf)/2./_mw);
double lambda(0.);
//neutralino mixing element
Complex nlf(0.);
if( ism % 2 == 0 ) {
y /= _sb;
lambda = -0.5 + qf*sqr(_sw);
nlf = (*_nmix)(nl,3);
}
else {
y /= _cb;
lambda = 0.5 + qf*sqr(_sw);
nlf = (*_nmix)(nl,2);
}
Complex bracketr = _sw*qf*n1prime - n2prime*lambda/_cw;
//heavy quarks/sleptons
if( ism == 5 || ism == 6 || ism == 15 ) {
Complex ma1(0.), ma2(0.);
if( ism == 5 ) {
ma1 = (*_sbot)(alpha,0);
ma2 = (*_sbot)(alpha,1);
}
else if( ism == 6 ) {
ma1 = (*_stop)(alpha,0);
ma2 = (*_stop)(alpha,1);
}
else {
ma1 = (*_stau)(alpha,0);
ma2 = (*_stau)(alpha,1);
}
_leftlast = y*conj(nlf)*ma1 - ma2*bracketl;
_rightlast = y*nlf*ma2 + ma1*bracketr;
}
else {
if( alpha == 0 ) {
_leftlast = y*conj(nlf);
_rightlast = bracketr;
}
else {
_leftlast = -bracketl;
_rightlast = y*nlf;
}
}
}
}
//determine the helicity order of the vertex
if( smfermion->id() < 0 ) {
left(conj(_rightlast));
right(conj(_leftlast));
}
else {
left(_leftlast);
right(_rightlast);
}
}
diff --git a/Models/Susy/SSNNPVertex.cc b/Models/Susy/SSNNPVertex.cc
--- a/Models/Susy/SSNNPVertex.cc
+++ b/Models/Susy/SSNNPVertex.cc
@@ -1,366 +1,367 @@
// -*- C++ -*-
//
// SSNNPVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSNNPVertex class.
//
#include "SSNNPVertex.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/Susy/MixingMatrix.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Looptools/clooptools.h"
#include "Herwig/Utilities/Maths.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSNNPVertex::SSNNPVertex() : _includeOnShell(false), _realIntegral(false),
_sw(0.), _cw(0.), _id1last(0),
_id2last(0), _q2last(ZERO), _couplast(0.),
_leftlast(ZERO), _rightlast(ZERO) {
orderInGem(3);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void SSNNPVertex::doinit() {
Looptools::ltini();
int ineu[5] = {1000022,1000023,1000025,1000035,1000045};
for(unsigned int i = 0; i < 5; ++i) {
for(unsigned int j = 0; j < 5; ++j) {
addToList(ineu[i], ineu[j], 22);
}
}
GeneralFFVVertex::doinit();
tMSSMPtr theSS = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if(!theSS)
throw InitException() << "SSNNPVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
_theN = theSS->neutralinoMix();
_theU = theSS->charginoUMix();
_theV = theSS->charginoVMix();
if(!_theN || !_theU || ! _theV)
throw InitException() << "SSNNPVertex::doinit - The neutralino "
<< "mixing matrix pointer is null."
<< Exception::abortnow;
_sw = sqrt(sin2ThetaW());
_cw = sqrt(1 - _sw*_sw);
_mw = getParticleData(ParticleID::Wplus)->mass();
double tb = theSS->tanBeta();
_sb = tb/sqrt(1 + sqr(tb));
_cb = sqrt(1 - sqr(_sb));
_stop = theSS->stopMix();
_sbot = theSS->sbottomMix();
_stau = theSS->stauMix();
Looptools::ltexi();
}
void SSNNPVertex::dofinish() {
Looptools::ltexi();
GeneralFFVVertex::dofinish();
}
void SSNNPVertex::doinitrun() {
Looptools::ltini();
GeneralFFVVertex::doinitrun();
}
void SSNNPVertex::persistentOutput(PersistentOStream & os) const {
os << _sw << _cw << _theN << ounit(_mw,GeV) << _sb << _cb
<< _stop << _sbot << _stau << _theU << _theV << _includeOnShell
<< _realIntegral;
}
void SSNNPVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw >> _cw >> _theN >> iunit(_mw,GeV) >> _sb >> _cb
>> _stop >> _sbot >> _stau >> _theU >> _theV >> _includeOnShell
>> _realIntegral;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSNNPVertex,Helicity::GeneralFFVVertex>
describeSSNNPVertex("Herwig::SSNNPVertex", "HwSusy.so");
void SSNNPVertex::Init() {
static ClassDocumentation<SSNNPVertex> documentation
("The loop-mediated coupling of the photon to a pair of neutralinos");
static Switch<SSNNPVertex,bool> interfaceIncludeOnShellIntermediates
("IncludeOnShellIntermediates",
"Whether or not to include on-shell intermediate states",
&SSNNPVertex::_includeOnShell, false, false, false);
static SwitchOption interfaceIncludeOnShellIntermediatesYes
(interfaceIncludeOnShellIntermediates,
"Yes",
"Include them",
true);
static SwitchOption interfaceIncludeOnShellIntermediatesNo
(interfaceIncludeOnShellIntermediates,
"No",
"Don't incldue them",
false);
static Switch<SSNNPVertex,bool> interfaceRealIntegral
("RealIntegral",
"Only include the real parts of the integrals",
&SSNNPVertex::_realIntegral, false, false, false);
static SwitchOption interfaceRealIntegralYes
(interfaceRealIntegral,
"Yes",
"Only include the real part",
true);
static SwitchOption interfaceRealIntegralNo
(interfaceRealIntegral,
"No",
"Don't include the real part",
false);
}
void SSNNPVertex::setCoupling(Energy2 q2, tcPDPtr part1,
#ifndef NDEBUG
tcPDPtr part2,tcPDPtr part3) {
#else
tcPDPtr part2,tcPDPtr) {
#endif
int o[2]={1,0};
long in1 = part1->id();
long in2 = part2->id();
Energy Mj = part1->mass();
Energy Mi = part2->mass();
// checks of the particle ids
assert(part3->id()==ParticleID::gamma);
assert(in1 == ParticleID::SUSY_chi_10 || in1 == ParticleID::SUSY_chi_20 ||
in1 == ParticleID::SUSY_chi_30 || in1 == ParticleID::SUSY_chi_40 ||
in1 == 1000045 );
assert(in2 == ParticleID::SUSY_chi_10 || in2 == ParticleID::SUSY_chi_20 ||
in2 == ParticleID::SUSY_chi_30 || in2 == ParticleID::SUSY_chi_40 ||
in2 == 1000045 );
// normal couplings are zero
setLeft (0.);
setRight(0.);
if(in1==in2) {
_leftlast = ZERO;
_rightlast = ZERO;
setLeftSigma (_leftlast );
setRightSigma(_rightlast);
return;
}
if(q2 != _q2last || _couplast==0.) {
_q2last = q2;
_couplast = sqr(weakCoupling(q2))*
electroMagneticCoupling(q2)/32./sqr(Constants::pi);
}
if(in1 != _id1last || in2 != _id2last) {
_leftlast = ZERO;
_rightlast = ZERO;
_id1last = in1;
_id2last = in2;
unsigned int neu1(in1 - 1000022), neu2(in2 - 1000022);
if(neu1 > 1) neu1 = (in1-1000005)/10;
if(neu2 > 1) neu2 = (in2-1000005)/10;
Complex n1prime[2] = { (*_theN)(neu2,0)*_cw + (*_theN)(neu2,1)*_sw ,
(*_theN)(neu1,0)*_cw + (*_theN)(neu1,1)*_sw };
Complex n2prime[2] = { (*_theN)(neu2,1)*_cw - (*_theN)(neu2,0)*_sw ,
(*_theN)(neu1,1)*_cw - (*_theN)(neu1,0)*_sw };
// sfermion/fermion loops
for(long iferm=1;iferm<16;++iferm) {
if(iferm==7) iferm=11;
if(iferm%2==0&&iferm>11) ++iferm;
tcPDPtr smf = getParticleData(iferm);
Energy mf = smf->mass();
double qf = smf->charge()/eplus;
double y = 0.5*mf/_mw;
Complex bracketl[2] = { qf*_sw*( conj(n1prime[0]) - _sw*conj(n2prime[0])/_cw ) ,
qf*_sw*( conj(n1prime[1]) - _sw*conj(n2prime[1])/_cw ) };
double lambda(0.);
//neutralino mixing element
Complex nlf[2]={0.,0.};
if( iferm % 2 == 0 ) {
y /= _sb;
lambda = -0.5 + qf*sqr(_sw);
nlf[0] = (*_theN)(neu2,3);
nlf[1] = (*_theN)(neu1,3);
}
else {
y /= _cb;
lambda = 0.5 + qf*sqr(_sw);
nlf[0] = (*_theN)(neu2,2);
nlf[1] = (*_theN)(neu1,2);
}
Complex bracketr[2] = { _sw*qf*n1prime[0] - n2prime[0]*lambda/_cw ,
_sw*qf*n1prime[1] - n2prime[1]*lambda/_cw };
for(long iy=0;iy<2;++iy) {
long isf = 1000000*(1+iy)+iferm;
Energy msf = getParticleData(isf)->mass();
if(!_includeOnShell&&(mf+msf<Mj||mf+msf<Mi)) continue;
Complex g[2][2];
Complex ma1(0.), ma2(0.);
// heavy fermions
if( iferm == 5 || iferm == 6 || iferm == 15 ) {
if( iferm == 5 ) {
ma1 = (*_sbot)(iy,0);
ma2 = (*_sbot)(iy,1);
}
else if( iferm == 6 ) {
ma1 = (*_stop)(iy,0);
ma2 = (*_stop)(iy,1);
}
else {
ma1 = (*_stau)(iy,0);
ma2 = (*_stau)(iy,1);
}
}
else if(iy==0) {
ma1 = 1.;
}
else {
ma2 = 1.;
}
for(unsigned int ix=0;ix<2;++ix) {
g[ix][0] = y*conj(nlf[ix])*ma1 - ma2*bracketl[ix];
g[ix][1] = y*nlf[ix]*ma2 + ma1*bracketr[ix];
}
swap(g[0][0],g[0][1]);
complex<InvEnergy2> I,J,K,I2;
loopIntegrals(Mi,Mj,msf,mf,I,J,K,I2);
complex<InvEnergy> coup[2];
for(unsigned int ix=0;ix<2;++ix) {
coup[ix] = Mj*(I2-K)*(g[0][ix]*g[1][o[ix]]-conj(g[0][o[ix]]*g[1][ix]))
+Mi*K*(g[0][o[ix]]*g[1][ix]-conj(g[0][ix]*g[1][o[ix]]))
+mf*I*(g[0][ix]*g[1][ix]-conj(g[0][o[ix]]*g[1][o[ix]]));
}
double fact = 4.*qf;
if(iferm<=6) fact *=3.;
_leftlast += fact*coup[0];
_rightlast += fact*coup[1];
}
}
// the chargino W contribution
for(unsigned int ic=0;ic<2;++ic) {
long id = ic==0 ?
ParticleID::SUSY_chi_1plus : ParticleID::SUSY_chi_2plus;
Energy Mk = getParticleData(id)->mass();
if(!_includeOnShell&&(Mk+_mw<Mj||Mk+_mw<Mi)) continue;
complex<InvEnergy2> I,J,K,I2;
loopIntegrals(Mi,Mj,_mw,Mk,I,J,K,I2);
Complex g[2][2];
for(unsigned int ix=0;ix<2;++ix) {
unsigned int in = ix==0 ? neu2 : neu1;
g[ix][0] =
conj((*_theN)(in, 1))*(*_theV)(ic, 0) -
conj((*_theN)(in, 3))*(*_theV)(ic, 1)/sqrt(2);
g[ix][1] =
(*_theN)(in, 1)*conj((*_theU)(ic, 0)) +
(*_theN)(in, 2)*conj((*_theU)(ic, 1))/sqrt(2);
}
complex<InvEnergy> coup[2];
for(unsigned int ix=0;ix<2;++ix) {
coup[ix] =
Mj*(I2-J-K)*(g[0][o[ix]]*g[1][o[ix]]-conj(g[0][ix]*g[1][ix]))-
Mi*(J-K)*(g[0][ix]*g[1][ix]-conj(g[0][o[ix]]*g[1][o[ix]]))+
2.*Mk*J*(g[0][o[ix]]*g[1][ix]-conj(g[0][ix]*g[1][o[ix]]));
}
_leftlast += 4.*coup[0];
_rightlast += 4.*coup[1];
}
// the chargino charged higgs contribution
Energy mh = getParticleData(ParticleID::Hplus)->mass();
for(unsigned int ic=0;ic<2;++ic) {
long id = ic==0 ?
ParticleID::SUSY_chi_1plus : ParticleID::SUSY_chi_2plus;
Energy Mk = getParticleData(id)->mass();
if(!_includeOnShell&&(Mk+mh<Mj||Mk+mh<Mi)) continue;
complex<InvEnergy2> I,J,K,I2;
loopIntegrals(Mi,Mj,mh,Mk,I,J,K,I2);
Complex g[2][2];
for(unsigned int ix=0;ix<2;++ix) {
unsigned int in = ix==0 ? neu2 : neu1;
g[ix][0] = (*_theN)(in, 3)*(*_theV)(ic,0)
+ ((*_theN)(in,1) + (*_theN)(in,0)*_sw/_cw)*
(*_theV)(ic,1)/sqrt(2);
g[ix][0] *= _cb;
g[ix][1] = conj((*_theN)(in, 2)*(*_theU)(ic,0)
- ((*_theN)(in,1) + (*_theN)(in,0)*_sw/_cw)*
(*_theU)(ic,1)/sqrt(2));
g[ix][1] *= _sb;
}
swap(g[1][0],g[1][1]);
complex<InvEnergy> coup[2];
for(unsigned int ix=0;ix<2;++ix) {
coup[ix] = Mj*(I2-K)*(g[0][ix]*g[1][o[ix]]-conj(g[0][o[ix]]*g[1][ix]))
+Mi*K*(g[0][o[ix]]*g[1][ix]-conj(g[0][ix]*g[1][o[ix]]))
+Mk*I*(g[0][ix]*g[1][ix]-conj(g[0][o[ix]]*g[1][o[ix]]));
}
_leftlast += 2.*coup[0];
_rightlast += 2.*coup[1];
}
// the chargino goldstone contribution
for(unsigned int ic=0;ic<2;++ic) {
long id = ic==0 ?
ParticleID::SUSY_chi_1plus : ParticleID::SUSY_chi_2plus;
Energy Mk = getParticleData(id)->mass();
if(!_includeOnShell&&(Mk+_mw<Mj||Mk+_mw<Mi)) continue;
complex<InvEnergy2> I,J,K,I2;
loopIntegrals(Mi,Mj,_mw,Mk,I,J,K,I2);
Complex g[2][2];
for(unsigned int ix=0;ix<2;++ix) {
unsigned int in = ix==0 ? neu2 : neu1;
g[ix][0] = (*_theN)(in, 3)*(*_theV)(ic,0)
+ ((*_theN)(in,1) + (*_theN)(in,0)*_sw/_cw)*
(*_theV)(ic,1)/sqrt(2);
g[ix][0] *=-_sb;
g[ix][1] = conj((*_theN)(in, 2)*(*_theU)(ic,0)
- ((*_theN)(in,1) + (*_theN)(in,0)*_sw/_cw)*
(*_theU)(ic,1)/sqrt(2));
g[ix][1] *= _cb;
}
swap(g[1][0],g[1][1]);
complex<InvEnergy> coup[2];
for(unsigned int ix=0;ix<2;++ix) {
coup[ix] = Mj*(I2-K)*(g[0][ix]*g[1][o[ix]]-conj(g[0][o[ix]]*g[1][ix]))
+Mi*K*(g[0][o[ix]]*g[1][ix]-conj(g[0][ix]*g[1][o[ix]]))
+Mk*I*(g[0][ix]*g[1][ix]-conj(g[0][o[ix]]*g[1][o[ix]]));
}
_leftlast += 2.*coup[0];
_rightlast += 2.*coup[1];
}
}
norm(_couplast);
setLeftSigma ( _leftlast);
setRightSigma(_rightlast);
}
void SSNNPVertex::loopIntegrals(Energy Mi, Energy Mj, Energy M, Energy m,
complex<InvEnergy2> & I, complex<InvEnergy2> & J,
complex<InvEnergy2> & K, complex<InvEnergy2> & I2) {
Energy2 m2(sqr(m)),M2(sqr(M)),Mi2(sqr(Mi)),Mj2(sqr(Mj));
double min2 = Mj2*UnitRemoval::InvE2;
double mout2 = Mi2*UnitRemoval::InvE2;
double mf2 = m2 *UnitRemoval::InvE2;
double ms2 = M2 *UnitRemoval::InvE2;
I = Looptools::C0i(Looptools::cc0,min2,mout2,0.,mf2,ms2,mf2)*UnitRemoval::InvE2;
J = Looptools::C0i(Looptools::cc0,min2,mout2,0.,ms2,mf2,ms2)*UnitRemoval::InvE2;
I2 =-Looptools::C0i(Looptools::cc1,min2,mout2,0.,mf2,ms2,mf2)*UnitRemoval::InvE2;
K = (1.+Complex(m2*I+M2*J-Mj2*I2))/(Mi2-Mj2);
if(_realIntegral) {
I = I .real();
J = J .real();
I2 = I2.real();
K = K .real();
}
}
diff --git a/Models/Susy/SSNNZVertex.cc b/Models/Susy/SSNNZVertex.cc
--- a/Models/Susy/SSNNZVertex.cc
+++ b/Models/Susy/SSNNZVertex.cc
@@ -1,125 +1,126 @@
// -*- C++ -*-
//
// SSNNZVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSNNZVertex class.
//
#include "SSNNZVertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "MixingMatrix.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSNNZVertex::SSNNZVertex() : _sw(0.), _cw(0.), _id1last(0),
_id2last(0), _q2last(), _couplast(0.),
_leftlast(0.), _rightlast(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void SSNNZVertex::doinit() {
long neu[] = { 1000022, 1000023, 1000025, 1000035, 1000045 };
for(unsigned int i = 0; i < 5; ++i)
for(unsigned int j = 0; j < 5; ++j)
addToList(neu[i], neu[j], 23);
FFVVertex::doinit();
tSusyBasePtr theSS = dynamic_ptr_cast<SusyBasePtr>(generator()->standardModel());
if(!theSS)
throw InitException() << "SSNNZVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
_theN = theSS->neutralinoMix();
if(!_theN)
throw InitException() << "SSNNZVertex::doinit - The neutralino "
<< "mixing matrix pointer is null."
<< Exception::abortnow;
_sw = sqrt(sin2ThetaW());
_cw = sqrt(1 - _sw*_sw);
}
void SSNNZVertex::persistentOutput(PersistentOStream & os) const {
os << _sw << _cw << _theN;
}
void SSNNZVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw >> _cw >> _theN;
_id1last = 0;
_id2last = 0;
_q2last = ZERO;
_couplast = 0.;
_leftlast = 0.;
_rightlast = 0.;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSNNZVertex,Helicity::FFVVertex>
describeSSNNZVertex("Herwig::SSNNZVertex", "HwSusy.so");
void SSNNZVertex::Init() {
static ClassDocumentation<SSNNZVertex> documentation
("The coupling of a Z-boson to a pair of neutralinos");
}
void SSNNZVertex::setCoupling(Energy2 q2,tcPDPtr part1,
#ifndef NDEBUG
tcPDPtr part2,tcPDPtr part3) {
#else
tcPDPtr part2,tcPDPtr) {
#endif
assert(part3->id() == ParticleID::Z0);
long ic1 = part2->id();
long ic2 = part1->id();
assert(ic1 == ParticleID::SUSY_chi_10 || ic1 == ParticleID::SUSY_chi_20 ||
ic1 == ParticleID::SUSY_chi_30 || ic1 == ParticleID::SUSY_chi_40 ||
ic1 == 1000045);
assert(ic2 == ParticleID::SUSY_chi_10 || ic2 == ParticleID::SUSY_chi_20 ||
ic2 == ParticleID::SUSY_chi_30 || ic2 == ParticleID::SUSY_chi_40 ||
ic2 == 1000045);
if(q2 != _q2last || _couplast==0.) {
_q2last = q2;
_couplast = weakCoupling(q2)/_cw;
}
if(ic1 != _id1last || ic2 != _id2last) {
_id1last = ic1;
_id2last = ic2;
unsigned int neu1(ic1 - 1000022), neu2(ic2 - 1000022);
if(neu1 > 1) {
if(ic1 == 1000025)
neu1 = 2;
else if(ic1 == 1000035)
neu1 = 3;
else
neu1 = 4;
}
if(neu2 > 1) {
if(ic2 == 1000025)
neu2 = 2;
else if(ic2 == 1000035)
neu2 = 3;
else
neu2 = 4;
}
_leftlast = 0.5*( (*_theN)(neu1, 3)*conj((*_theN)(neu2, 3)) -
(*_theN)(neu1, 2)*conj((*_theN)(neu2, 2)) );
_rightlast = -conj(_leftlast);
}
norm(_couplast);
left(_leftlast);
right(_rightlast);
}
diff --git a/Models/Susy/SSWGSSVertex.cc b/Models/Susy/SSWGSSVertex.cc
--- a/Models/Susy/SSWGSSVertex.cc
+++ b/Models/Susy/SSWGSSVertex.cc
@@ -1,201 +1,202 @@
// -*- C++ -*-
//
// SSWGSSVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSWGSSVertex class.
//
#include "SSWGSSVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSWGSSVertex::SSWGSSVertex() : _sw(0.), _cw(0.), _q2last(),_emcouplast(0.),
_scouplast(0.), _ulast(0), _dlast(0),
- _gblast(0), _factlast(0.)
-{}
+ _gblast(0), _factlast(0.) {
+ colourStructure(ColourStructure::SU3TFUND);
+}
void SSWGSSVertex::doinit() {
//W-
//LL-squarks
for(long ix=1000001;ix<1000006;ix+=2) {
addToList(-24,21,ix+1,-ix);
}
//1-2 stop sbottom
addToList(-24,21,1000006,-2000005);
//2-1 stop sbottom
addToList(-24,21,2000006,-1000005);
//2-2 stop sbottom
addToList(-24,21,2000006,-2000005);
//W+
for(long ix=1000001;ix<1000006;ix+=2) {
addToList(24,21,-(ix+1),ix);
}
//1-2 stop sbottom
addToList(24,21,-1000006,2000005);
//2-1 stop sbottom
addToList(24,21,-2000006,1000005);
//2-2 stop sbottom
addToList(24,21,-2000006,2000005);
//---Z0----
//LL squarks
for(long ix=1000001;ix<1000007;++ix) {
addToList(23,21,ix,-ix);
}
//RR squarks
for(long ix=2000001;ix<2000007;++ix) {
addToList(23,21,ix,-ix);
}
//L-Rbar stop
addToList(23,21,1000006,-2000006);
//Lbar-R stop
addToList(23,21,-1000006,2000006);
//L-Rbar sbottom
addToList(23,21,1000005,-2000005);
//Lbar-R sbottom
addToList(23,21,-1000005,2000005);
//----gamma----
//squarks
for(long ix=1000001;ix<1000007;++ix) {
addToList(22,21,ix,-ix);
}
for(long ix=2000001;ix<2000007;++ix) {
addToList(22,21,ix,-ix);
}
orderInGem(1);
orderInGs(1);
VVSSVertex::doinit();
tMSSMPtr theSS = dynamic_ptr_cast<MSSMPtr>(generator()->standardModel());
if(!theSS)
throw InitException() << "SSWGSSVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
_sw = sqrt(sin2ThetaW());
_cw = sqrt( 1. - sqr(_sw) );
_stop = theSS->stopMix();
_sbottom = theSS->sbottomMix();
if(!_stop || !_sbottom)
throw InitException() << "SSWGSSVertex::doinit() - "
<< "A mixing matrix pointer is null."
<< " stop: " << _stop << " sbottom: " << _sbottom
<< Exception::abortnow;
}
void SSWGSSVertex::persistentOutput(PersistentOStream & os) const {
os << _sw << _cw << _stop << _sbottom;
}
void SSWGSSVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw >> _cw >> _stop >> _sbottom;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSWGSSVertex,VVSSVertex>
describeHerwigSSWGSSVertex("Herwig::SSWGSSVertex", "HwSusy.so");
void SSWGSSVertex::Init() {
static ClassDocumentation<SSWGSSVertex> documentation
("This implements the gluon-gluon-squark-squark vertex.");
}
void SSWGSSVertex::setCoupling(Energy2 q2, tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3,tcPDPtr part4) {
long boson(abs(part1->id()));
long gluon(abs(part2->id()));
if (gluon > boson) swap(gluon, boson);
if( boson != ParticleID::Wplus && boson != ParticleID::Z0 &&
boson != ParticleID::gamma ) {
throw HelicityConsistencyError()
<< "SSWGSSVertex::setCoupling() - Vector particle in this "
<< "vertex is not a W/Z/gamma. " << boson << Exception::warning;
norm(0.);
}
if( gluon != ParticleID::g ) {
throw HelicityConsistencyError()
<< "SSWGSSVertex::setCoupling() - Vector particle in this "
<< "vertex is not a gluon. " << gluon << Exception::warning;
norm(0.);
}
long sq1(abs(part3->id())),sq2(abs(part4->id()));
if( (sq1 < 1000001 && sq1 > 1000006 && sq1 < 2000001 && sq1 > 2000006) ||
(sq2 < 1000001 && sq2 > 1000006 && sq2 < 2000001 && sq2 > 2000006))
throw HelicityConsistencyError()
<< "SSWGSSVertex::setCoupling() - There are no squarks in "
<< "this vertex! " << part3->id() << " " << part4->id()
<< Exception::warning;
if( sq1 % 2 != 0 ) swap(sq1, sq2);
if( sq1 != _ulast || sq2 != _dlast || boson != _gblast) {
_gblast = boson;
_ulast = sq1;
_dlast = sq2;
//photon is simplest
if( boson == ParticleID::gamma )
_factlast = -2.*getParticleData(sq1)->charge()/eplus;
else {
//determine which helicity state
unsigned int alpha(sq1/1000000 - 1), beta(sq2/1000000 - 1);
//mixing factors
Complex m1a(0.), m1b(0.);
if( sq1 == ParticleID::SUSY_t_1 || sq1 == ParticleID::SUSY_t_2 )
m1a = (*_stop)(alpha, 0);
else if( sq1 == ParticleID::SUSY_b_1 || sq1 == ParticleID::SUSY_b_2 )
m1a = (*_sbottom)(alpha, 0);
else
m1a = (alpha == 0) ? Complex(1.) : Complex(0.);
if( sq2 == ParticleID::SUSY_t_1 || sq2 == ParticleID::SUSY_t_2 )
m1b = (*_stop)(beta, 0);
else if( sq2 == ParticleID::SUSY_b_1 || sq2 == ParticleID::SUSY_b_2 )
m1b = (*_sbottom)(beta, 0);
else
m1b = (beta == 0) ? Complex(1.) : Complex(0.);
//W boson
if( boson == ParticleID::Wplus ) {
_factlast = -1.*m1a*m1b*sqrt(2)/_sw;
}
//Z boson
else {
double lmda(1.);
if( sq2 % 2 == 0 ) lmda = -1.;
_factlast = lmda*m1a*m1b;
if( alpha == beta) {
double ef = getParticleData(sq1)->charge()/eplus;
_factlast += 2.*ef*sqr(_sw);
}
_factlast *= 1./_cw/_sw;
}
}
}
if( q2 != _q2last || _emcouplast==0. || _scouplast==0. ) {
_q2last = q2;
_emcouplast = electroMagneticCoupling(q2);
_scouplast = strongCoupling(q2);
}
norm(-_emcouplast*_scouplast*_factlast);
}
diff --git a/Models/Susy/SSWHHVertex.cc b/Models/Susy/SSWHHVertex.cc
--- a/Models/Susy/SSWHHVertex.cc
+++ b/Models/Susy/SSWHHVertex.cc
@@ -1,128 +1,129 @@
// -*- C++ -*-
//
// SSWHHVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSWHHVertex class.
//
#include "SSWHHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include <cassert>
using namespace ThePEG::Helicity;
using namespace Herwig;
SSWHHVertex::SSWHHVertex() :
theSw(0.), theS2w(0.), theC2w(0.), thesbma(0.), thecbma(0.),
theq2last(ZERO), theElast(0.) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
void SSWHHVertex::doinit() {
addToList(22,37,-37);
addToList(23,36,25);
addToList(23,36,35);
addToList(23,37,-37);
//outgoing W+
addToList(24,-37,25);
addToList(24,-37,35);
addToList(24,-37,36);
//outgoing W-
addToList(-24,37,25);
addToList(-24,37,35);
addToList(-24,37,36);
VSSVertex::doinit();
tMSSMPtr theMSSM = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !theMSSM )
throw InitException()
<< "SSWHHVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
theSw = sqrt(sin2ThetaW());
double cw = sqrt(1. - sqr(theSw));
theS2w = 2.*theSw*cw;
theC2w = cw*cw - theSw*theSw;
double sina = sin(theMSSM->higgsMixingAngle());
double cosa = sqrt(1. - sqr(sina));
double tanb = theMSSM->tanBeta();
double sinb = tanb/sqrt(1. + sqr(tanb));
double cosb = sqrt( 1. - sqr(sinb) );
thesbma = sinb*cosa - sina*cosb;
thecbma = cosa*cosb + sina*sinb;
}
void SSWHHVertex::persistentOutput(PersistentOStream & os) const {
os << theSw << theS2w << theC2w << thesbma << thecbma;
}
void SSWHHVertex::persistentInput(PersistentIStream & is, int) {
is >> theSw >> theS2w >> theC2w >> thesbma >> thecbma;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSWHHVertex,VSSVertex>
describeHerwigSSWHHVertex("Herwig::SSWHHVertex", "HwSusy.so");
void SSWHHVertex::Init() {
static ClassDocumentation<SSWHHVertex> documentation
("The coupling of a pair of higgs bosons and a SM gauge boson");
}
void SSWHHVertex::setCoupling(Energy2 q2, tcPDPtr particle1,
tcPDPtr particle2, tcPDPtr particle3) {
long gboson = particle1->id();
assert( gboson == ParticleID::Z0 ||
gboson == ParticleID::gamma ||
abs(gboson) == ParticleID::Wplus );
long h1ID = particle2->id();
long h2ID = particle3->id();
Complex coup(0.);
if( gboson == ParticleID::Z0 ) {
if( abs(h1ID) == ParticleID::Hplus ) {
coup = theC2w/theS2w;
if(h1ID<0) coup *= -1.;
}
else if( h1ID == ParticleID::h0 ||
h2ID == ParticleID::h0 ) {
coup = Complex(0., 1.)*thecbma/theS2w;
}
else {
coup =-Complex(0., 1.)*thesbma/theS2w;
}
if(h2ID==ParticleID::A0) coup *=-1.;
}
else if( gboson == ParticleID::gamma ) {
coup = 1.;
if(h1ID<0) coup *= -1.;
}
else {
long higgs = abs(h1ID) == ParticleID::Hplus ? h2ID : h1ID;
if( higgs == ParticleID::h0 ) {
coup = 0.5*thecbma/theSw;
}
else if( higgs == ParticleID::H0)
coup = -0.5*thesbma/theSw;
else
coup = -Complex(0., 0.5)/theSw;
if(abs(h2ID) == ParticleID::Hplus ) coup *= -1.;
if(gboson<0&&higgs!=ParticleID::A0) coup *= -1.;
}
if( q2 != theq2last || theElast==0.) {
theq2last = q2;
theElast = electroMagneticCoupling(q2);
}
norm(theElast*coup);
}
diff --git a/Models/Susy/SSWSSVertex.cc b/Models/Susy/SSWSSVertex.cc
--- a/Models/Susy/SSWSSVertex.cc
+++ b/Models/Susy/SSWSSVertex.cc
@@ -1,237 +1,238 @@
// -*- C++ -*-
//
// SSWSSVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSWSSVertex class.
//
#include "SSWSSVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
SSWSSVertex::SSWSSVertex():_sw(0.), _cw(0.), _q2last(),_couplast(0.),
_ulast(0), _dlast(0), _gblast(0),
_factlast(0.) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::DELTA);
}
void SSWSSVertex::doinit() {
//W-
//LL-squarks
for(long ix=1000001;ix<1000006;ix+=2) {
addToList(-24,ix+1,-ix);
}
//1-2 stop sbottom
addToList(-24,1000006,-2000005);
//2-1 stop sbottom
addToList(-24,2000006,-1000005);
//2-2 stop sbottom
addToList(-24,2000006,-2000005);
//LL-sleptons
for(long ix=1000011;ix<1000016;ix+=2) {
addToList(-24,-ix,ix+1);
}
//2-L stau
addToList(-24,-2000015,1000016);
//W+
for(long ix=1000001;ix<1000006;ix+=2) {
addToList(24,-(ix+1),ix);
}
//1-2 stop sbottom
addToList(24,-1000006,2000005);
//2-1 stop sbottom
addToList(24,-2000006,1000005);
//2-2 stop sbottom
addToList(24,-2000006,2000005);
//LL-sleptons
for(long ix=1000011;ix<1000016;ix+=2) {
addToList(24,ix,-ix-1);
}
//2-L stau
addToList(24,2000015,-1000016);
//---Z0----
//LL-sleptons
for(long ix=1000011;ix<1000017;++ix) {
addToList(23,ix,-ix);
}
//RR-sleptons
for(long ix=2000011;ix<2000016;ix+=2) {
addToList(23,ix,-ix);
}
//L-Rbar stau
addToList(23,1000015,-2000015);
//Lbar-R stau
addToList(23,-1000015,2000015);
//LL squarks
for(long ix=1000001;ix<1000007;++ix) {
addToList(23,ix,-ix);
}
//RR squarks
for(long ix=2000001;ix<2000007;++ix) {
addToList(23,ix,-ix);
}
//L-Rbar stop
addToList(23,1000006,-2000006);
//Lbar-R stop
addToList(23,-1000006,2000006);
//L-Rbar sbottom
addToList(23,1000005,-2000005);
//Lbar-R sbottom
addToList(23,-1000005,2000005);
//----gamma----
//sleptons
for(long ix=1000011;ix<1000016;ix+=2) {
addToList(22,ix,-ix);
}
for(long ix=2000011;ix<2000016;ix+=2) {
addToList(22,ix,-ix);
}
//squarks
for(long ix=1000001;ix<1000007;++ix) {
addToList(22,ix,-ix);
}
for(long ix=2000001;ix<2000007;++ix) {
addToList(22,ix,-ix);
}
VSSVertex::doinit();
tMSSMPtr theSS = dynamic_ptr_cast<MSSMPtr>(generator()->standardModel());
if(!theSS)
throw InitException() << "SSWSSVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
_sw = sqrt(sin2ThetaW());
_cw = sqrt( 1. - sqr(_sw) );
_stop = theSS->stopMix();
_sbottom = theSS->sbottomMix();
_stau = theSS->stauMix();
if(!_stop || !_stau || !_sbottom)
throw InitException() << "SSWSSVertex::doinit() - "
<< "A mixing matrix pointer is null."
<< " stop: " << _stop << " sbottom: " << _sbottom
<< " stau: " << _stau << Exception::abortnow;
}
void SSWSSVertex::persistentOutput(PersistentOStream & os) const {
os << _sw << _cw << _stau << _stop << _sbottom;
}
void SSWSSVertex::persistentInput(PersistentIStream & is, int) {
is >> _sw >> _cw >> _stau >> _stop >> _sbottom;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSWSSVertex,VSSVertex>
describeHerwigSSWSSVertex("Herwig::SSWSSVertex", "HwSusy.so");
void SSWSSVertex::Init() {
static ClassDocumentation<SSWSSVertex> documentation
("This is the implementation of the coupling of an SM boson "
"a pair of sfermions");
}
void SSWSSVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3) {
long boson(abs(part1->id()));
assert( boson == ParticleID::Wplus || boson == ParticleID::Z0 ||
boson == ParticleID::gamma );
long sf1(abs(part2->id())),sf2(abs(part3->id()));
assert( (sf1 >= 1000001 && sf1 <= 1000006)
|| (sf1 >= 1000011 && sf1 <= 1000016)
|| (sf1 >= 2000001 && sf1 <= 2000006)
|| (sf1 >= 2000011 && sf1 <= 2000016) );
assert( (sf2 >= 1000001 && sf2 <= 1000006)
|| (sf2 >= 1000011 && sf2 <= 1000016)
|| (sf2 >= 2000001 && sf2 <= 2000006)
|| (sf2 >= 2000011 && sf2 <= 2000016) );
if( sf1 % 2 != 0 ) swap(sf1, sf2);
if( sf1 != _ulast || sf2 != _dlast || boson != _gblast) {
_gblast = boson;
_ulast = sf1;
_dlast = sf2;
//photon is simplest
if( boson == ParticleID::gamma )
_factlast = getParticleData(sf1)->charge()/eplus;
else {
//determine which helicity state
unsigned int alpha(sf1/1000000 - 1), beta(sf2/1000000 - 1);
//mixing factors
Complex m1a(0.), m1b(0.);
if( sf1 == ParticleID::SUSY_t_1 || sf1 == ParticleID::SUSY_t_2 )
m1a = (*_stop)(alpha, 0);
else if( sf1 == ParticleID::SUSY_b_1 || sf1 == ParticleID::SUSY_b_2 )
m1a = (*_sbottom)(alpha, 0);
else if( sf1 == ParticleID::SUSY_tau_1minus ||
sf1 == ParticleID::SUSY_tau_2minus )
m1a = (*_stau)(alpha, 0);
else
m1a = (alpha == 0) ? Complex(1.) : Complex(0.);
if( sf2 == ParticleID::SUSY_t_1 || sf2 == ParticleID::SUSY_t_2 )
m1b = (*_stop)(beta, 0);
else if( sf2 == ParticleID::SUSY_b_1 || sf2 == ParticleID::SUSY_b_2 )
m1b = (*_sbottom)(beta, 0);
else if( sf2 == ParticleID::SUSY_tau_1minus ||
sf2 == ParticleID::SUSY_tau_2minus )
m1b = (*_stau)(beta, 0);
else
m1b = (beta == 0) ? Complex(1.) : Complex(0.);
//W boson
if( boson == ParticleID::Wplus ) {
_factlast = m1a*m1b/sqrt(2)/_sw;
}
//Z boson
else {
if( sf1 == ParticleID::SUSY_nu_eL || sf1 == ParticleID::SUSY_nu_muL ||
sf1 == ParticleID::SUSY_nu_tauL ) {
_factlast = 1./_cw/2./_sw;
}
else {
double lmda(1.);
if( sf2 % 2 == 0 ) lmda = -1.;
_factlast = lmda*m1a*m1b;
if( alpha == beta) {
double ef = getParticleData(sf1)->charge()/eplus;
_factlast += 2.*ef*sqr(_sw);
}
_factlast *= -1./2./_cw/_sw;
}
}
}
}
if( q2 != _q2last || _couplast==0. ) {
_q2last = q2;
_couplast = electroMagneticCoupling(q2);
}
if(part2->id()>0)
norm(-_couplast*_factlast);
else
norm(+_couplast*_factlast);
}
diff --git a/Models/Susy/SSWWHHVertex.cc b/Models/Susy/SSWWHHVertex.cc
--- a/Models/Susy/SSWWHHVertex.cc
+++ b/Models/Susy/SSWWHHVertex.cc
@@ -1,181 +1,182 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSWWHHVertex class.
//
#include "SSWWHHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "MSSM.h"
using namespace Herwig;
SSWWHHVertex::SSWWHHVertex() : couplast_(0.), q2last_(ZERO) {
orderInGs(0);
orderInGem(2);
+ colourStructure(ColourStructure::SINGLET);
}
IBPtr SSWWHHVertex::clone() const {
return new_ptr(*this);
}
IBPtr SSWWHHVertex::fullclone() const {
return new_ptr(*this);
}
void SSWWHHVertex::persistentOutput(PersistentOStream & os) const {
os << coup_;
}
void SSWWHHVertex::persistentInput(PersistentIStream & is, int) {
is >> coup_;
}
// Static variable needed for the type description system in ThePEG.
DescribeClass<SSWWHHVertex,VVSSVertex>
describeHerwigSSWWHHVertex("Herwig::SSWWHHVertex", "HwSusy.so");
void SSWWHHVertex::Init() {
static ClassDocumentation<SSWWHHVertex> documentation
("The SSWWHHVertex class implements the coupling of two Higgs bosons and"
"two electroweak vector bosons in the MSSM.");
}
void SSWWHHVertex::doinit() {
int id[3]={25,35,36};
for(unsigned int ix=0;ix<3;++ix) {
addToList( 24,-24,id[ix],id[ix]);
addToList( 23, 23,id[ix],id[ix]);
addToList( 22, 24,id[ix],-37);
addToList( 22,-24,id[ix], 37);
addToList( 23, 24,id[ix],-37);
addToList( 23,-24,id[ix], 37);
}
addToList( 24,-24, 37,-37);
addToList( 23, 23, 37,-37);
addToList( 22, 23, 37,-37);
addToList( 22, 22, 37,-37);
VVSSVertex::doinit();
tMSSMPtr model = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !model )
throw Exception()
<< "SSWWHHVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
coup_.resize(11);
double sw2 = sin2ThetaW();
double sw = sqrt(sw2);
double cw2 = 1.-sw2;
double cw = sqrt(cw2);
double c2w = cw2-sw2;
double sinalp = sin(model->higgsMixingAngle());
double cosalp = sqrt(1. - sqr(sinalp));
double tanbeta = model->tanBeta();
double sinbeta = tanbeta/sqrt(1. + sqr(tanbeta));
double cosbeta = sqrt( 1. - sqr(sinbeta) );
double sinbma = sinbeta*cosalp - cosbeta*sinalp;
double cosbma = cosbeta*cosalp + sinbeta*sinalp;
// WWHH
coup_[0] = 0.5/sw2;
// ZZH0H0
coup_[1] = 0.5/sw2/cw2;
// ZZH+H-
coup_[2] = 0.5*sqr(c2w)/cw2/sw2;
// Z W h0 H+
coup_[3] =-0.5/cw*cosbma;
// Z W H0 H+
coup_[4] = 0.5/cw*sinbma;
// Z W A0 H+
coup_[5] =-Complex(0.,0.5)/cw;
// A A H+H-
coup_[6] = 2.;
// A Z H+H-
coup_[7] = c2w/sw/cw;
// A W h0 H+
coup_[8] = 0.5*cosbma/sw;
// A W H0 H+
coup_[9] =-0.5*sinbma/sw;
// A W A0 H+
coup_[10] = Complex(0.,0.5)/sw;
}
void SSWWHHVertex::setCoupling(Energy2 q2,tcPDPtr part1,tcPDPtr part2,
tcPDPtr part3, tcPDPtr part4) {
if(q2!=q2last_||couplast_==0.) {
couplast_ = sqr(electroMagneticCoupling(q2));
q2last_=q2;
}
int ibos1 = part1->id(), ibos2 = part2->id();
int isca1 = part3->id(), isca2 = part4->id();
if(abs(ibos1)==abs(ibos2)) {
if(abs(ibos1)==ParticleID::Wplus) {
norm(couplast_*coup_[0]);
}
else if(ibos1==ParticleID::Z0) {
if(abs(isca1)==ParticleID::Hplus)
norm(couplast_*coup_[2]);
else
norm(couplast_*coup_[1]);
}
else if(ibos1==ParticleID::gamma) {
norm(couplast_*coup_[6]);
}
else
assert(false);
}
else if(abs(ibos1)==ParticleID::Wplus ||
abs(ibos2)==ParticleID::Wplus) {
if(abs(ibos1)==ParticleID::gamma ||
abs(ibos2)==ParticleID::gamma) {
if(abs(isca1)==ParticleID::h0 ||
abs(isca2)==ParticleID::h0) {
norm(couplast_*coup_[8]);
}
else if(abs(isca1)==ParticleID::H0 ||
abs(isca2)==ParticleID::H0) {
norm(couplast_*coup_[9]);
}
else if(abs(isca1)==ParticleID::A0 ||
abs(isca2)==ParticleID::A0) {
if(isca1==ParticleID::Hplus ||
isca2==ParticleID::Hplus) {
norm(couplast_* coup_[10] );
}
else {
norm(couplast_*conj(coup_[10]));
}
}
else
assert(false);
}
else {
if(abs(isca1)==ParticleID::h0 ||
abs(isca2)==ParticleID::h0) {
norm(couplast_*coup_[3]);
}
else if(abs(isca1)==ParticleID::H0 ||
abs(isca2)==ParticleID::H0) {
norm(couplast_*coup_[4]);
}
else if(abs(isca1)==ParticleID::A0 ||
abs(isca2)==ParticleID::A0) {
if(isca1==ParticleID::Hplus ||
isca2==ParticleID::Hplus) {
norm(couplast_* coup_[5] );
}
else {
norm(couplast_*conj(coup_[5]));
}
}
else
assert(false);
}
}
else {
norm(couplast_*coup_[7]);
}
}
diff --git a/Models/Susy/SSWWHVertex.cc b/Models/Susy/SSWWHVertex.cc
--- a/Models/Susy/SSWWHVertex.cc
+++ b/Models/Susy/SSWWHVertex.cc
@@ -1,103 +1,104 @@
// -*- C++ -*-
//
// SSWWHVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSWWHVertex class.
//
#include "SSWWHVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
#include <cassert>
using namespace ThePEG::Helicity;
using namespace Herwig;
SSWWHVertex::SSWWHVertex() : theh0Wfact(ZERO), theH0Wfact(ZERO),
theh0Zfact(ZERO), theH0Zfact(ZERO),
theCoupLast(ZERO), theElast(0.0),
theq2last(ZERO), theHlast(0),
theGBlast(0) {
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SINGLET);
}
void SSWWHVertex::doinit() {
addToList(23,23,25);
addToList(-24,24,25);
addToList(23,23,35);
addToList(-24,24,35);
VVSVertex::doinit();
tMSSMPtr model = dynamic_ptr_cast<tMSSMPtr>(generator()->standardModel());
if( !model )
throw InitException()
<< "SSWWHVertex::doinit() - The pointer to the MSSM object is null!"
<< Exception::abortnow;
Energy mw = getParticleData(ParticleID::Wplus)->mass();
Energy mz = getParticleData(ParticleID::Z0)->mass();
double sw = sqrt(sin2ThetaW());
double sinalp = sin(model->higgsMixingAngle());
double cosalp = sqrt(1. - sqr(sinalp));
double tanbeta = model->tanBeta();
double sinbeta = tanbeta/sqrt(1. + sqr(tanbeta));
double cosbeta = sqrt( 1. - sqr(sinbeta) );
double sinbma = sinbeta*cosalp - cosbeta*sinalp;
double cosbma = cosbeta*cosalp + sinbeta*sinalp;
theh0Wfact = mw*sinbma/sw;
theH0Wfact = mw*cosbma/sw;
theh0Zfact = mz*sinbma/sw/sqrt(1. - sw*sw);
theH0Zfact = mz*cosbma/sw/sqrt(1. - sw*sw);
}
void SSWWHVertex::persistentOutput(PersistentOStream & os) const {
os << ounit(theh0Wfact,GeV) << ounit(theH0Wfact,GeV)
<< ounit(theh0Zfact,GeV) << ounit(theH0Zfact,GeV);
}
void SSWWHVertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(theh0Wfact,GeV) >> iunit(theH0Wfact,GeV)
>> iunit(theh0Zfact,GeV) >> iunit(theH0Zfact,GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSWWHVertex,VVSVertex>
describeHerwigSSWWHVertex("Herwig::SSWWHVertex", "HwSusy.so");
void SSWWHVertex::Init() {
static ClassDocumentation<SSWWHVertex> documentation
("This is the coupling of a pair of SM gauge bosons"
"to the higgs particles in the MSSM");
}
void SSWWHVertex::setCoupling(Energy2 q2, tcPDPtr particle1, tcPDPtr,
tcPDPtr particle3) {
long bosonID = abs(particle1->id());
long higgsID = particle3->id();
assert( higgsID == ParticleID::h0 || higgsID == ParticleID::H0 );
assert( bosonID == ParticleID::Wplus || bosonID == ParticleID::Z0 );
if( higgsID != theHlast || bosonID != theGBlast) {
if( higgsID == ParticleID::h0 )
theCoupLast = (bosonID == ParticleID::Z0) ? theh0Zfact : theh0Wfact;
else
theCoupLast = (bosonID == ParticleID::Z0) ? theH0Zfact : theH0Wfact;
}
if( q2 != theq2last ) {
theq2last = q2;
theElast = electroMagneticCoupling(q2);
}
norm(theElast*theCoupLast*UnitRemoval::InvE);
}
diff --git a/Models/Susy/SSWWSSVertex.cc b/Models/Susy/SSWWSSVertex.cc
--- a/Models/Susy/SSWWSSVertex.cc
+++ b/Models/Susy/SSWWSSVertex.cc
@@ -1,267 +1,269 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SSWWSSVertex class.
//
#include "SSWWSSVertex.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"
using namespace Herwig;
SSWWSSVertex::SSWWSSVertex() : sw_(0.), cw_(0.), q2last_(), couplast_(0.),
ulast_(0), dlast_(0), gblast1_(0), gblast2_(0),
- factlast_(0.) {}
+ factlast_(0.) {
+ colourStructure(ColourStructure::DELTA);
+}
IBPtr SSWWSSVertex::clone() const {
return new_ptr(*this);
}
IBPtr SSWWSSVertex::fullclone() const {
return new_ptr(*this);
}
void SSWWSSVertex::persistentOutput(PersistentOStream & os) const {
os << sw_ << cw_ << stau_ << stop_ << sbottom_;
}
void SSWWSSVertex::persistentInput(PersistentIStream & is, int) {
is >> sw_ >> cw_ >> stau_ >> stop_ >> sbottom_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<SSWWSSVertex,VVSSVertex>
describeHerwigSSWWSSVertex("Herwig::SSWWSSVertex", "HwSusy.so");
void SSWWSSVertex::Init() {
static ClassDocumentation<SSWWSSVertex> documentation
("The SSWWSSVertex class implements the coupling of two"
" weak bosons and two scalar fermions");
}
void SSWWSSVertex::doinit() {
// gamma gamma, gamma Z0 and Z0 Z0 PAIRS
for(long ib1=22;ib1<24;++ib1) {
for(long ib2=22;ib2<24;++ib2) {
// sleptons
long istep = ib1==23&&ib2==23 ? 1 : 2;
for(long ix=1000011;ix<1000017;ix+=istep) {
addToList(ib1,ib2,ix,-ix);
}
for(long ix=2000011;ix<2000017;ix+=2) {
addToList(ib1,ib2,ix,-ix);
}
// squarks
for(long ix=1000001;ix<1000007;++ix) {
addToList(ib1,ib2,ix,-ix);
}
for(long ix=2000001;ix<2000007;++ix) {
addToList(ib1,ib2,ix,-ix);
}
// L/R mixing if Z
if(ib2==23) {
//L-Rbar stau
addToList(ib1,ib2,1000015,-2000015);
//Lbar-R stau
addToList(ib1,ib2,-1000015,2000015);
//L-Rbar stop
addToList(ib1,ib2,1000006,-2000006);
//Lbar-R stop
addToList(ib1,ib2,-1000006,2000006);
//L-Rbar sbottom
addToList(ib1,ib2,1000005,-2000005);
//Lbar-R sbottom
addToList(ib1,ib2,-1000005,2000005);
}
}
// W- gamma/Z0
// LL-squarks
for(long ix=1000001;ix<1000006;ix+=2) {
addToList(-24,ib1,ix+1,-ix);
}
// 1-2 stop sbottom
addToList(-24,ib1,1000006,-2000005);
// 2-1 stop sbottom
addToList(-24,ib1,2000006,-1000005);
// 2-2 stop sbottom
addToList(-24,ib1,2000006,-2000005);
// LL-sleptons
for(long ix=1000011;ix<1000016;ix+=2) {
addToList(-24,ib1,-ix,ix+1);
}
//2-L stau
addToList(-24,ib1,-2000015,1000016);
// W+ gamma/Z0
// LL-squarks
for(long ix=1000001;ix<1000006;ix+=2) {
addToList(24,ib1,-(ix+1),ix);
}
// 1-2 stop sbottom
addToList(24,ib1,-1000006,2000005);
// 2-1 stop sbottom
addToList(24,ib1,-2000006,1000005);
// 2-2 stop sbottom
addToList(24,ib1,-2000006,2000005);
// LL-sleptons
for(long ix=1000011;ix<1000016;ix+=2) {
addToList(24,ib1,ix,-ix-1);
}
//2-L stau
addToList(24,ib1,2000015,-1000016);
}
// finally WW pairs
// sleptons
for(long ix=1000011;ix<=1000017;++ix) {
addToList(24,-24,ix,-ix);
}
addToList(24,-24,1000015,-2000015);
addToList(24,-24,2000015,-1000015);
// squarks
for(long ix=1000001;ix<=1000007;++ix) {
addToList(24,-24,ix,-ix);
}
addToList(24,-24,1000005,-2000005);
addToList(24,-24,2000005,-1000005);
addToList(24,-24,1000006,-2000006);
addToList(24,-24,2000006,-1000006);
// couplings etc
orderInGem(2);
orderInGs(0);
VVSSVertex::doinit();
tMSSMPtr model = dynamic_ptr_cast<MSSMPtr>(generator()->standardModel());
if(!model)
throw InitException() << "SSWWSSVertex::doinit() - "
<< "The model pointer is null."
<< Exception::abortnow;
sw_ = sqrt(sin2ThetaW());
cw_ = sqrt( 1. - sqr(sw_) );
stop_ = model->stopMix();
sbottom_ = model->sbottomMix();
stau_ = model->stauMix();
if(!stop_ || !stau_ || !sbottom_)
throw InitException() << "SSWWSSVertex::doinit() - "
<< "A mixing matrix pointer is null."
<< " stop: " << stop_ << " sbottom: " << sbottom_
<< " stau: " << stau_ << Exception::abortnow;
}
void SSWWSSVertex::setCoupling(Energy2 q2,tcPDPtr part1,
tcPDPtr part2,tcPDPtr part3,
tcPDPtr part4) {
long boson[2] = {abs(part1->id()),abs(part2->id())};
assert( boson[0] == ParticleID::Wplus || boson[0] == ParticleID::Z0 ||
boson[0] == ParticleID::gamma );
assert( boson[1] == ParticleID::Wplus || boson[1] == ParticleID::Z0 ||
boson[1] == ParticleID::gamma );
long sf1(abs(part3->id())),sf2(abs(part4->id()));
assert( (sf1 >= 1000001 && sf1 <= 1000006)
|| (sf1 >= 1000011 && sf1 <= 1000016)
|| (sf1 >= 2000001 && sf1 <= 2000006)
|| (sf1 >= 2000011 && sf1 <= 2000016) );
assert( (sf2 >= 1000001 && sf2 <= 1000006)
|| (sf2 >= 1000011 && sf2 <= 1000016)
|| (sf2 >= 2000001 && sf2 <= 2000006)
|| (sf2 >= 2000011 && sf2 <= 2000016) );
if( sf1 % 2 != 0 ) swap(sf1, sf2);
if(boson[0]>boson[1]) swap(boson[0],boson[1]);
if( sf1 != ulast_ || sf2 != dlast_ ||
boson[0] != gblast1_ || boson[1] != gblast2_) {
gblast1_ = boson[0];
gblast2_ = boson[1];
ulast_ = sf1;
dlast_ = sf2;
double ef1 = getParticleData(sf1)->charge()/eplus;
double ef2 = getParticleData(sf2)->charge()/eplus;
// photon pairs are simplest
if(gblast1_ == ParticleID::gamma &&
gblast2_ == ParticleID::gamma ) {
factlast_ = 2.*sqr( ef1 );
}
// otherwise we need the helicity states
else {
//determine which helicity state
unsigned int alpha(sf1/1000000 - 1), beta(sf2/1000000 - 1);
//mixing factors
Complex m1a(0.), m1b(0.);
if( sf1 == ParticleID::SUSY_t_1 || sf1 == ParticleID::SUSY_t_2 )
m1a = (*stop_)(alpha, 0);
else if( sf1 == ParticleID::SUSY_b_1 || sf1 == ParticleID::SUSY_b_2 )
m1a = (*sbottom_)(alpha, 0);
else if( sf1 == ParticleID::SUSY_tau_1minus ||
sf1 == ParticleID::SUSY_tau_2minus )
m1a = (*stau_)(alpha, 0);
else
m1a = (alpha == 0) ? Complex(1.) : Complex(0.);
if( sf2 == ParticleID::SUSY_t_1 || sf2 == ParticleID::SUSY_t_2 )
m1b = (*stop_)(beta, 0);
else if( sf2 == ParticleID::SUSY_b_1 || sf2 == ParticleID::SUSY_b_2 )
m1b = (*sbottom_)(beta, 0);
else if( sf2 == ParticleID::SUSY_tau_1minus ||
sf2 == ParticleID::SUSY_tau_2minus )
m1b = (*stau_)(beta, 0);
else
m1b = (beta == 0) ? Complex(1.) : Complex(0.);
// if either boson is a W
if(gblast2_==ParticleID::Wplus) {
// WW
if(gblast1_==ParticleID::Wplus) {
factlast_ = 0.5*m1a*m1b/sqr(sw_);
}
// gamma W
else if(gblast1_==ParticleID::gamma) {
factlast_ = sqrt(0.5)*m1a*m1b/sw_*(ef1+ef2);
}
// Z0 W
else if(gblast1_==ParticleID::Z0) {
factlast_ = -sqrt(0.5)*m1a*m1b/cw_*(ef1+ef2);
}
}
else {
// compute the Z coupling
factlast_=1.;
if(gblast1_==ParticleID::Z0||gblast2_==ParticleID::Z0) {
if( sf1 == ParticleID::SUSY_nu_eL || sf1 == ParticleID::SUSY_nu_muL ||
sf1 == ParticleID::SUSY_nu_tauL ) {
factlast_ = 0.5/cw_/sw_;
}
else {
double lmda = sf2 % 2 == 0 ? 1. : -1.;
factlast_ = lmda*m1a*m1b;
if( alpha == beta) factlast_ -= 2.*ef1*sqr(sw_);
factlast_ *= 0.5/cw_/sw_;
}
}
// photon Z
if(gblast1_ == ParticleID::gamma &&
gblast2_ == ParticleID::Z0 ) {
factlast_ *= 2.*ef1;
}
// Z pairs
else if(gblast1_ == ParticleID::Z0 &&
gblast2_ == ParticleID::Z0 ) {
factlast_ *= 2.*factlast_;
}
}
}
}
if( q2 != q2last_ || couplast_==0. ) {
q2last_ = q2;
couplast_ = sqr(electroMagneticCoupling(q2));
}
norm(couplast_*factlast_);
}
diff --git a/Models/TTbAsymm/TTbAModelAGQQVertex.cc b/Models/TTbAsymm/TTbAModelAGQQVertex.cc
--- a/Models/TTbAsymm/TTbAModelAGQQVertex.cc
+++ b/Models/TTbAsymm/TTbAModelAGQQVertex.cc
@@ -1,103 +1,101 @@
// -*- C++ -*-
//
// TTbAModelAGQQVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TTbAModelAGQQVertex class.
//
#include "TTbAModelAGQQVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Config/Constants.h"
using namespace Herwig;
IBPtr TTbAModelAGQQVertex::clone() const {
return new_ptr(*this);
}
IBPtr TTbAModelAGQQVertex::fullclone() const {
return new_ptr(*this);
}
TTbAModelAGQQVertex::TTbAModelAGQQVertex() {
orderInGem(1);
orderInGs(1);
addToList(-1,1,63);
addToList(-2,2,63);
addToList(-3,3,63);
addToList(-4,4,63);
addToList(-5,5,63);
addToList(-6,6,63);
-
-
-
+ colourStructure(ColourStructure::DELTA);
}
void TTbAModelAGQQVertex::doinit() {
_theModel = generator()->standardModel();
tcHwTTbAPtr hwTTbA=dynamic_ptr_cast<tcHwTTbAPtr>(_theModel);
if(hwTTbA) {
_cAGQQ_R =hwTTbA->_cAGQQ_right();
_cAGQQ_L =hwTTbA->_cAGQQ_left();
_cAGTT_R =hwTTbA->_cAGTT_right();
_cAGTT_L =hwTTbA->_cAGTT_left();
_models = hwTTbA->_model();
}
FFVVertex::doinit();
}
void TTbAModelAGQQVertex::persistentOutput(PersistentOStream & os) const {
os << _cAGQQ_R << _cAGQQ_L << _cAGTT_R << _cAGTT_L << _models;
}
void TTbAModelAGQQVertex::persistentInput(PersistentIStream & is, int) {
is >> _cAGQQ_R >> _cAGQQ_L >>_cAGTT_R >> _cAGTT_L >> _models;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TTbAModelAGQQVertex,FFVVertex>
describeHerwigTTbAModelAGQQVertex("Herwig::TTbAModelAGQQVertex", "Herwig.so");
void TTbAModelAGQQVertex::Init() {
static ClassDocumentation<TTbAModelAGQQVertex> documentation
("The TTbAModelAGQQVertex class is the implementation"
" of the helicity amplitude calculation of the TTbA"
" quark-lepton vertex.");
}
void TTbAModelAGQQVertex::setCoupling(Energy2 q2,tcPDPtr aa ,tcPDPtr bb, tcPDPtr cc) {
double _cL = 0, _cR = 0;
double gstrong = 1.0;
gstrong = strongCoupling(q2);
if(abs(aa->id()) == 63 || abs(bb->id()) == 63 || abs(cc->id()) == 63) {
if(abs(aa->id()) !=6 && abs(bb->id()) !=6 && abs(cc->id()) != 6) {
_cR = _cAGQQ_R;
_cL = _cAGQQ_L;
} else {
_cR = _cAGTT_R;
_cL = _cAGTT_L;
}
}
if(_models!=2) { _cL = 1E-10; _cR = 1E-10; }
left(_cL);
right(_cR);
norm(gstrong);
}
diff --git a/Models/TTbAsymm/TTbAModelSU2XVertex.cc b/Models/TTbAsymm/TTbAModelSU2XVertex.cc
--- a/Models/TTbAsymm/TTbAModelSU2XVertex.cc
+++ b/Models/TTbAsymm/TTbAModelSU2XVertex.cc
@@ -1,186 +1,186 @@
// -*- C++ -*-
//
// TTbAModelSU2XVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TTbAModelSU2XVertex class.
//
#include "TTbAModelSU2XVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Config/Constants.h"
using namespace Herwig;
IBPtr TTbAModelSU2XVertex::clone() const {
return new_ptr(*this);
}
IBPtr TTbAModelSU2XVertex::fullclone() const {
return new_ptr(*this);
}
TTbAModelSU2XVertex::TTbAModelSU2XVertex() {
orderInGem(1);
orderInGs(1);
addToList(-6,6,70);
addToList(-2,2,70);
addToList(-2,6,70);
addToList(2,-6,70);
addToList(-6,6,71);
addToList(-2,2,71);
addToList(-2,6,71);
addToList(2,-6,71);
addToList(-6,6,-71);
addToList(-2,2,-71);
addToList(-2,6,-71);
addToList(2,-6,-71);
-
+ colourStructure(ColourStructure::DELTA);
}
void TTbAModelSU2XVertex::doinit() {
_theModel = generator()->standardModel();
tcHwTTbAPtr hwTTbA=dynamic_ptr_cast<tcHwTTbAPtr>(_theModel);
if(hwTTbA) {
_alphaX =hwTTbA->_alphaX_value();
_costhetaX =hwTTbA->_costhetaX_value();
_models =hwTTbA->_model();
}
FFVVertex::doinit();
}
void TTbAModelSU2XVertex::persistentOutput(PersistentOStream & os) const {
os << _alphaX << _costhetaX << _models;
}
void TTbAModelSU2XVertex::persistentInput(PersistentIStream & is, int) {
is >> _alphaX >> _costhetaX >> _models;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TTbAModelSU2XVertex,FFVVertex>
describeHerwigTTbAModelSU2XVertex("Herwig::TTbAModelSU2XVertex", "Herwig.so");
void TTbAModelSU2XVertex::Init() {
static ClassDocumentation<TTbAModelSU2XVertex> documentation
("The TTbAModelSU2XVertex class is the implementation"
" of the helicity amplitude calculation of the TTbA"
" SU(2)_X vertex.");
}
void TTbAModelSU2XVertex::setCoupling(Energy2,tcPDPtr aa ,tcPDPtr bb, tcPDPtr cc) {
double _cR = 0, _fac = 0;
_gX = sqrt( 4 * Constants::pi * _alphaX );
double ct = _costhetaX;
double st = sqrt(1 - pow(ct,2));
//Vz
if( abs(aa->id()) == 70 || abs(bb->id()) == 70 || abs(cc->id()) == 70) {
_fac = _gX / 2.0;
if( aa->id() == 6 || bb->id() == 6 || cc->id() == 6) {
if( aa->id() == -6 || bb->id() == -6 || cc->id() == -6) {
_cR = pow(ct,2) - pow(st,2);
}
}
if( aa->id() == 2 || bb->id() == 2 || cc->id() == 2) {
if( aa->id() == -2 || bb->id() == -2 || cc->id() == -2) {
_cR = pow(st,2) - pow(ct,2);
}
}
if( abs(aa->id()) == 2 || abs(bb->id()) == 2 || abs(cc->id()) == 2) {
if( abs(aa->id()) == 6 || abs(bb->id()) == 6 || abs(cc->id()) == 6) {
_cR = 2 * ct * st;
}
}
}
//Ym
if( aa->id() == -71 || bb->id() == -71 || cc->id() == -71 ) {
_fac = _gX / sqrt(2.0);
if( aa->id() == 6 || bb->id() == 6 || cc->id() == 6) {
if( aa->id() == -6 || bb->id() == -6 || cc->id() == -6) {
_cR = - ct * st;
}
}
if( aa->id() == 2 || bb->id() == 2 || cc->id() == 2) {
if( aa->id() == -2 || bb->id() == -2 || cc->id() == -2) {
_cR = ct * st;
}
}
if( aa->id() == 2 || bb->id() == 2 || cc->id() == 2) {
if( aa->id() == -6 || bb->id() == -6 || cc->id() == -6) {
_cR = - pow(st,2);
}
}
if( aa->id() == -2 || bb->id() == -2 || cc->id() == -2) {
if( aa->id() == 6 || bb->id() == 6 || cc->id() == 6) {
_cR = pow(ct,2);
}
}
}
//Yp
if( aa->id() == 71 || bb->id() == 71 || cc->id() == 71 ) {
_fac = _gX / sqrt(2.0);
if( aa->id() == 6 || bb->id() == 6 || cc->id() == 6) {
if( aa->id() == -6 || bb->id() == -6 || cc->id() == -6) {
_cR = - ct * st;
}
}
if( aa->id() == 2 || bb->id() == 2 || cc->id() == 2) {
if( aa->id() == -2 || bb->id() == -2 || cc->id() == -2) {
_cR = ct * st;
}
}
if( aa->id() == 2 || bb->id() == 2 || cc->id() == 2) {
if( aa->id() == -6 || bb->id() == -6 || cc->id() == -6) {
_cR = pow(ct,2);
}
}
if( aa->id() == -2 || bb->id() == -2 || cc->id() == -2) {
if( aa->id() == 6 || bb->id() == 6 || cc->id() == 6) {
_cR = - pow(st,2);
}
}
}
//normalise according to Lagrangian factor
_cR *= _fac;
//If this model is not selected set coupling to zero.
if(_models!=3) { _cR = 1E-10; }
right(_cR);
left(0.);
norm(1.0);
}
diff --git a/Models/TTbAsymm/TTbAModelWPTDVertex.cc b/Models/TTbAsymm/TTbAModelWPTDVertex.cc
--- a/Models/TTbAsymm/TTbAModelWPTDVertex.cc
+++ b/Models/TTbAsymm/TTbAModelWPTDVertex.cc
@@ -1,85 +1,86 @@
// -*- C++ -*-
//
// TTbAModelWPTDVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TTbAModelWPTDVertex class.
//
#include "TTbAModelWPTDVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Config/Constants.h"
using namespace Herwig;
IBPtr TTbAModelWPTDVertex::clone() const {
return new_ptr(*this);
}
IBPtr TTbAModelWPTDVertex::fullclone() const {
return new_ptr(*this);
}
TTbAModelWPTDVertex::TTbAModelWPTDVertex() {
addToList(-1,6,-34);
addToList(-6,1,34);
orderInGem(1);
orderInGs(1);
+ colourStructure(ColourStructure::DELTA);
}
void TTbAModelWPTDVertex::doinit() {
_theModel = generator()->standardModel();
tcHwTTbAPtr hwTTbA=dynamic_ptr_cast<tcHwTTbAPtr>(_theModel);
if(hwTTbA) {
_cWPTD_R =hwTTbA->_cWPTD_right();
_cWPTD_L =hwTTbA->_cWPTD_left();
_models =hwTTbA->_model();
}
FFVVertex::doinit();
}
void TTbAModelWPTDVertex::persistentOutput(PersistentOStream & os) const {
os << _cWPTD_R << _cWPTD_L << _models;
}
void TTbAModelWPTDVertex::persistentInput(PersistentIStream & is, int) {
is >> _cWPTD_R >> _cWPTD_L >> _models;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TTbAModelWPTDVertex,FFVVertex>
describeHerwigTTbAModelWPTDVertex("Herwig::TTbAModelWPTDVertex", "Herwig.so");
void TTbAModelWPTDVertex::Init() {
static ClassDocumentation<TTbAModelWPTDVertex> documentation
("The TTbAModelWPTDVertex class is the implementation"
" of the helicity amplitude calculation of the TTbA"
" quark-lepton vertex.");
}
void TTbAModelWPTDVertex::setCoupling(Energy2,tcPDPtr aa ,tcPDPtr bb, tcPDPtr cc) {
double _cL = 0, _cR = 0;
if(abs(aa->id()) == 34 || abs(bb->id()) == 34 || abs(cc->id()) == 34) {
_cR = _cWPTD_R;
_cL = _cWPTD_L;
}
if(_models!=0) { _cL = 1E-10; _cR = 1E-10; }
left(_cL);
right(_cR);
norm(1.0);
}
diff --git a/Models/TTbAsymm/TTbAModelZPQQVertex.cc b/Models/TTbAsymm/TTbAModelZPQQVertex.cc
--- a/Models/TTbAsymm/TTbAModelZPQQVertex.cc
+++ b/Models/TTbAsymm/TTbAModelZPQQVertex.cc
@@ -1,101 +1,102 @@
// -*- C++ -*-
//
// TTbAModelZPQQVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the TTbAModelZPQQVertex class.
//
#include "TTbAModelZPQQVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Config/Constants.h"
using namespace Herwig;
IBPtr TTbAModelZPQQVertex::clone() const {
return new_ptr(*this);
}
IBPtr TTbAModelZPQQVertex::fullclone() const {
return new_ptr(*this);
}
TTbAModelZPQQVertex::TTbAModelZPQQVertex() {
addToList(-2,6,32);
addToList(-6,2,32);
addToList(-2,2,32);
addToList(-4,4,32);
orderInGem(1);
orderInGs(1);
+ colourStructure(ColourStructure::DELTA);
}
void TTbAModelZPQQVertex::doinit() {
_theModel = generator()->standardModel();
tcHwTTbAPtr hwTTbA=dynamic_ptr_cast<tcHwTTbAPtr>(_theModel);
if(hwTTbA) {
_cZPTU_R =hwTTbA->_cZPTU_right();
_cZPTU_L =hwTTbA->_cZPTU_left();
_cZPUU_R =hwTTbA->_cZPUU_right();
_cZPUU_L =hwTTbA->_cZPUU_left();
_cZPCC_R =hwTTbA->_cZPCC_right();
_cZPCC_L =hwTTbA->_cZPCC_left();
_models =hwTTbA->_model();
}
FFVVertex::doinit();
}
void TTbAModelZPQQVertex::persistentOutput(PersistentOStream & os) const {
os << _cZPTU_R << _cZPTU_L << _cZPUU_R << _cZPUU_L << _cZPCC_R << _cZPCC_L << _models;
}
void TTbAModelZPQQVertex::persistentInput(PersistentIStream & is, int) {
is >> _cZPTU_R >> _cZPTU_L >> _cZPUU_R >> _cZPUU_L >> _cZPCC_R >> _cZPCC_L >> _models;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<TTbAModelZPQQVertex,FFVVertex>
describeHerwigTTbAModelZPQQVertex("Herwig::TTbAModelZPQQVertex", "Herwig.so");
void TTbAModelZPQQVertex::Init() {
static ClassDocumentation<TTbAModelZPQQVertex> documentation
("The TTbAModelZPQQVertex class is the implementation"
" of the helicity amplitude calculation of the TTbA"
" Z prime Quark-antiQuark vertex.");
}
void TTbAModelZPQQVertex::setCoupling(Energy2,tcPDPtr aa ,tcPDPtr bb, tcPDPtr cc) {
double _cR = 0, _cL = 0;
if( abs(aa->id()) == 6 || abs(bb->id()) == 6 || abs(cc->id()) == 6) {
_cR = _cZPTU_R;
_cL = _cZPTU_L;
} else {
if( abs(aa->id()) != 4 && abs(bb->id()) != 4 && abs(cc->id()) != 4) {
_cR = _cZPUU_R;
_cL = _cZPUU_L;
}
if( abs(aa->id()) == 4 || abs(bb->id()) == 4 || abs(cc->id()) == 4) {
_cR = _cZPCC_R;
_cL = _cZPCC_L;
}
}
if(_models!=1) { _cL = 1E-10; _cR = 1E-10; }
right(_cR);
left(_cL);
norm(1.0);
}
diff --git a/Models/Transplanckian/METRP2to2.cc b/Models/Transplanckian/METRP2to2.cc
--- a/Models/Transplanckian/METRP2to2.cc
+++ b/Models/Transplanckian/METRP2to2.cc
@@ -1,350 +1,344 @@
// -*- C++ -*-
//
// METRP2to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2009-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the METRP2to2 class.
//
#include "METRP2to2.h"
#include "ThePEG/Utilities/SimplePhaseSpace.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/MatrixElement/Tree2toNDiagram.h"
#include "Herwig/Models/StandardModel/StandardModel.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/Cuts/Cuts.h"
#include "Herwig/Utilities/Interpolator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include <fstream>
using namespace Herwig;
DescribeClass<METRP2to2,HwMEBase>
describeHerwigMETRP2to2("Herwig::METRP2to2","HwTransplanck.so");
HERWIG_INTERPOLATOR_CLASSDESC(METRP2to2,double,double)
METRP2to2::METRP2to2()
: _maxflavour(2), _ndim(6), _planckmass(1500.0*GeV), _process(0) {
- massOption(vector<unsigned int>(2,0));
+ massOption({{0,0}});
}
void METRP2to2::doinit() {
HwMEBase::doinit();
setup_interpolator();
}
void METRP2to2::rebind(const TranslationMap & trans) {
_interpol = trans.translate(_interpol);
HwMEBase::rebind(trans);
}
IVector METRP2to2::getReferences() {
IVector ret = HwMEBase::getReferences();
ret.push_back(_interpol);
return ret;
}
void METRP2to2::setup_interpolator() {
- static const double xmatrix1[103] = {0.0, 0.02, 0.10, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3., 3.2, 3.4, 3.6, 3.8, 4., 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6., 6.2, 6.4, 6.6, 6.8, 7., 7.2, 7.4, 7.6, 7.8, 8., 8.2, 8.4, 8.6, 8.8, 9., 9.2, 9.4, 9.6, 9.8, 10., 10.2, 10.4, 10.6, 10.8, 11., 11.2, 11.4, 11.6, 11.8, 12., 12.2, 12.4, 12.6, 12.8, 13., 13.2, 13.4, 13.6, 13.8, 14., 14.2, 14.4, 14.6, 14.8, 15., 15.2, 15.4, 15.6, 15.8, 16., 16.2, 16.4, 16.6, 16.8, 17., 17.2, 17.4, 17.6, 17.8, 18., 18.2, 18.4, 18.6, 18.8, 19., 19.2, 19.4, 19.6, 19.8, 20.0 };
- static const double xmatrix2[102] = {0.02, 0.10, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3., 3.2, 3.4, 3.6, 3.8, 4., 4.2, 4.4, 4.6, 4.8, 5., 5.2, 5.4, 5.6, 5.8, 6., 6.2, 6.4, 6.6, 6.8, 7., 7.2, 7.4, 7.6, 7.8, 8., 8.2, 8.4, 8.6, 8.8, 9., 9.2, 9.4, 9.6, 9.8, 10., 10.2, 10.4, 10.6, 10.8, 11., 11.2, 11.4, 11.6, 11.8, 12., 12.2, 12.4, 12.6, 12.8, 13., 13.2, 13.4, 13.6, 13.8, 14., 14.2, 14.4, 14.6, 14.8, 15., 15.2, 15.4, 15.6, 15.8, 16., 16.2, 16.4, 16.6, 16.8, 17., 17.2, 17.4, 17.6, 17.8, 18., 18.2, 18.4, 18.6, 18.8, 19., 19.2, 19.4, 19.6, 19.8, 20.0 };
- static const double datamatrix2[102] = {4.32048, 2.74662, 2.090560, 1.457590, 1.113050, 0.885216, 0.720795, 0.597404, 0.501483, 0.425543, 0.364668, 0.315299, 0.274983, 0.241792, 0.214466, 0.191698, 0.172689, 0.156841, 0.143329, 0.131919, 0.122174, 0.113656, 0.106339, 0.099869, 0.094101, 0.089013, 0.084378, 0.080185, 0.076376, 0.072856, 0.069622, 0.066624, 0.063844, 0.061242, 0.058820, 0.056561, 0.054417, 0.052433, 0.05055, 0.048772, 0.047129, 0.045546, 0.044056, 0.042673, 0.041328, 0.040078, 0.038895, 0.037749, 0.036688, 0.035666, 0.034687, 0.033771, 0.032883, 0.032041, 0.031239, 0.030467, 0.029731, 0.029025, 0.028350, 0.027698, 0.027075, 0.026479, 0.025896, 0.025347, 0.024812, 0.024291, 0.023804, 0.023318, 0.022854, 0.022416, 0.021974, 0.021561, 0.021160, 0.020761, 0.020390, 0.020021, 0.019662, 0.019325, 0.01898, 0.018662, 0.018351, 0.018041, 0.017747, 0.017459, 0.017177, 0.016906, 0.016641, 0.016384, 0.016132, 0.015889, 0.015651, 0.015418, 0.015196, 0.014973, 0.014759, 0.014553, 0.014345, 0.014149, 0.013956, 0.013762, 0.013582, 0.013399};
- static const double datamatrix3[103] = {1.33947, 1.32238, 1.25505, 1.17491, 1.02696, 0.89463, 0.77688, 0.67270, 0.58105, 0.50095, 0.43143, 0.37156, 0.32046, 0.27726, 0.24113, 0.21126, 0.18684, 0.16707, 0.15118, 0.13843, 0.12815, 0.11974, 0.11271, 0.10670, 0.10141, 0.09663, 0.09224, 0.08814, 0.08427, 0.08061, 0.07715, 0.07387, 0.07077, 0.06785, 0.06511, 0.06254, 0.06014, 0.05790, 0.05582, 0.05388, 0.05207, 0.05038, 0.04879, 0.04731, 0.04591, 0.04459, 0.04334, 0.04216, 0.04103, 0.03996, 0.03894, 0.03796, 0.03702, 0.03612, 0.03526, 0.03443, 0.03363, 0.03287, 0.03214, 0.03143, 0.03075, 0.03010, 0.02947, 0.02887, 0.02829, 0.02773, 0.02719, 0.02666, 0.02616, 0.02567, 0.0250, 0.02475, 0.02431, 0.02388, 0.02347, 0.02306, 0.02267, 0.02230, 0.02193, 0.02157, 0.02123, 0.02089, 0.02056, 0.02025, 0.01994, 0.01964, 0.01934, 0.01906, 0.018, 0.01851, 0.01825, 0.01799, 0.01774, 0.01750, 0.01726, 0.01703, 0.01680, 0.01658, 0.01637, 0.01616, 0.01595, 0.01575, 0.01555};
- static const double datamatrix4[103] = {0.88623, 0.885845, 0.879328, 0.86361, 0.81617, 0.75594, 0.68928, 0.62036, 0.55206, 0.48641, 0.42484, 0.36832, 0.31749, 0.27273, 0.23419, 0.20185, 0.17547, 0.15464, 0.13871, 0.12685, 0.11813, 0.11162, 0.10654, 0.10229, 0.09844, 0.09475, 0.09107, 0.08738, 0.08368, 0.08000, 0.07641, 0.07295, 0.06967, 0.06660, 0.06377, 0.06118, 0.05883, 0.05670, 0.05476, 0.05300, 0.05138, 0.04989, 0.04849, 0.04716, 0.04590, 0.04469, 0.04353, 0.04240, 0.04131, 0.04026, 0.03924, 0.03826, 0.037, 0.03642, 0.03556, 0.03473, 0.03394, 0.03319, 0.03247, 0.03178, 0.03112, 0.03049, 0.02988, 0.02930, 0.02873, 0.02819, 0.02767, 0.02716, 0.02667, 0.02619, 0.02573, 0.02529, 0.02486, 0.02444, 0.02403, 0.02364, 0.02326, 0.02289, 0.02253, 0.02218, 0.02184, 0.02152, 0.02120, 0.02089, 0.02058, 0.02029, 0.02000, 0.01972, 0.01944, 0.01918, 0.01892, 0.01866, 0.01841, 0.01816, 0.01792, 0.01769, 0.01746, 0.01724, 0.01702, 0.01681, 0.01660, 0.01639, 0.01619 };
- static const double datamatrix5[103] = {0.744596, 0.744489, 0.742327, 0.73584, 0.71183, 0.67590, 0.63118, 0.58053, 0.52645, 0.47109, 0.41628, 0.36351, 0.31401, 0.26878, 0.22857, 0.19396, 0.16533, 0.14280, 0.12611, 0.11459, 0.10713, 0.10244, 0.09934, 0.09690, 0.09453, 0.09189, 0.08887, 0.08548, 0.08180, 0.07796, 0.07410, 0.07035, 0.06681, 0.06358, 0.06068, 0.05815, 0.05595, 0.05405, 0.05240, 0.05094, 0.04962, 0.04838, 0.04720, 0.04604, 0.04489, 0.04375, 0.04262, 0.04150, 0.04040, 0.03934, 0.03831, 0.03733, 0.03639, 0.03551, 0.03469, 0.03391, 0.03317, 0.03247, 0.03181, 0.03118, 0.03057, 0.02998, 0.02941, 0.02886, 0.02832, 0.02779, 0.02728, 0.02678, 0.02630, 0.02583, 0.02538, 0.02494, 0.02452, 0.02412, 0.02373, 0.02335, 0.02299, 0.02264, 0.02230, 0.02197, 0.02165, 0.02134, 0.02104, 0.02074, 0.02045, 0.02016, 0.01989, 0.01961, 0.01935, 0.01909, 0.01883, 0.01858, 0.01834, 0.01810, 0.01787, 0.01764, 0.01742, 0.01721, 0.01699, 0.01679, 0.01659, 0.01639, 0.01620};
- static const double datamatrix6[103] = {0.67759, 0.677074, 0.675686, 0.67139, 0.65466, 0.62818, 0.59351, 0.55242, 0.50671, 0.45815, 0.40837, 0.35888, 0.31104, 0.26603, 0.22490, 0.18855, 0.15777, 0.13319, 0.11510, 0.10322, 0.09650, 0.09333, 0.09206, 0.09137, 0.09045, 0.08888, 0.08652, 0.08343, 0.07977, 0.07574, 0.07157, 0.06747, 0.06364, 0.06020, 0.05725, 0.05479, 0.05281, 0.05121, 0.04991, 0.04880, 0.04779, 0.04680, 0.04580, 0.04475, 0.04364, 0.04249, 0.04130, 0.04012, 0.03895, 0.03783, 0.03677, 0.03579, 0.03488, 0.03405, 0.03330, 0.03261, 0.03197, 0.03137, 0.03080, 0.03025, 0.02970, 0.02917, 0.02863, 0.02811, 0.02758, 0.02707, 0.02657, 0.02608, 0.02560, 0.02515, 0.02471, 0.02430, 0.02390, 0.02351, 0.02314, 0.02279, 0.02244, 0.02211, 0.02178, 0.02146, 0.02115, 0.02084, 0.02054, 0.02025, 0.01996, 0.01968, 0.01941, 0.01915, 0.01890, 0.01865, 0.01841, 0.01818, 0.01795, 0.01773, 0.01751, 0.01730, 0.01710, 0.01690, 0.01670, 0.01650, 0.01631, 0.01612, 0.01593 };
-
- const double * datamatrix = 0;
- const double * xmatrix = 0;
- int xsize = 0;
-
- //assign the appropriate tabulated points for the number of extra dimensions
- switch ( _ndim ) {
- case 2 : datamatrix = datamatrix2; xmatrix = xmatrix2; xsize = 102; break;
- case 3 : datamatrix = datamatrix3; xmatrix = xmatrix1; xsize = 103; break;
- case 4 : datamatrix = datamatrix4; xmatrix = xmatrix1; xsize = 103; break;
- case 5 : datamatrix = datamatrix5; xmatrix = xmatrix1; xsize = 103; break;
- case 6 : datamatrix = datamatrix6; xmatrix = xmatrix1; xsize = 103; break;
- default : assert(false);
- }
- _interpol = make_InterpolatorPtr(xsize, datamatrix, 1.0, xmatrix, 1.0, 1);
+ static const array<double,103> xmatrix1 = {{0.0, 0.02, 0.10, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3., 3.2, 3.4, 3.6, 3.8, 4., 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6., 6.2, 6.4, 6.6, 6.8, 7., 7.2, 7.4, 7.6, 7.8, 8., 8.2, 8.4, 8.6, 8.8, 9., 9.2, 9.4, 9.6, 9.8, 10., 10.2, 10.4, 10.6, 10.8, 11., 11.2, 11.4, 11.6, 11.8, 12., 12.2, 12.4, 12.6, 12.8, 13., 13.2, 13.4, 13.6, 13.8, 14., 14.2, 14.4, 14.6, 14.8, 15., 15.2, 15.4, 15.6, 15.8, 16., 16.2, 16.4, 16.6, 16.8, 17., 17.2, 17.4, 17.6, 17.8, 18., 18.2, 18.4, 18.6, 18.8, 19., 19.2, 19.4, 19.6, 19.8, 20.0 }};
+ static const array<double,102> xmatrix2 = {{0.02, 0.10, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3., 3.2, 3.4, 3.6, 3.8, 4., 4.2, 4.4, 4.6, 4.8, 5., 5.2, 5.4, 5.6, 5.8, 6., 6.2, 6.4, 6.6, 6.8, 7., 7.2, 7.4, 7.6, 7.8, 8., 8.2, 8.4, 8.6, 8.8, 9., 9.2, 9.4, 9.6, 9.8, 10., 10.2, 10.4, 10.6, 10.8, 11., 11.2, 11.4, 11.6, 11.8, 12., 12.2, 12.4, 12.6, 12.8, 13., 13.2, 13.4, 13.6, 13.8, 14., 14.2, 14.4, 14.6, 14.8, 15., 15.2, 15.4, 15.6, 15.8, 16., 16.2, 16.4, 16.6, 16.8, 17., 17.2, 17.4, 17.6, 17.8, 18., 18.2, 18.4, 18.6, 18.8, 19., 19.2, 19.4, 19.6, 19.8, 20.0 }};
+ static const array<double,102> datamatrix2 = {{4.32048, 2.74662, 2.090560, 1.457590, 1.113050, 0.885216, 0.720795, 0.597404, 0.501483, 0.425543, 0.364668, 0.315299, 0.274983, 0.241792, 0.214466, 0.191698, 0.172689, 0.156841, 0.143329, 0.131919, 0.122174, 0.113656, 0.106339, 0.099869, 0.094101, 0.089013, 0.084378, 0.080185, 0.076376, 0.072856, 0.069622, 0.066624, 0.063844, 0.061242, 0.058820, 0.056561, 0.054417, 0.052433, 0.05055, 0.048772, 0.047129, 0.045546, 0.044056, 0.042673, 0.041328, 0.040078, 0.038895, 0.037749, 0.036688, 0.035666, 0.034687, 0.033771, 0.032883, 0.032041, 0.031239, 0.030467, 0.029731, 0.029025, 0.028350, 0.027698, 0.027075, 0.026479, 0.025896, 0.025347, 0.024812, 0.024291, 0.023804, 0.023318, 0.022854, 0.022416, 0.021974, 0.021561, 0.021160, 0.020761, 0.020390, 0.020021, 0.019662, 0.019325, 0.01898, 0.018662, 0.018351, 0.018041, 0.017747, 0.017459, 0.017177, 0.016906, 0.016641, 0.016384, 0.016132, 0.015889, 0.015651, 0.015418, 0.015196, 0.014973, 0.014759, 0.014553, 0.014345, 0.014149, 0.013956, 0.013762, 0.013582, 0.013399 }};
+ static const array<double,103> datamatrix3 = {{1.33947, 1.32238, 1.25505, 1.17491, 1.02696, 0.89463, 0.77688, 0.67270, 0.58105, 0.50095, 0.43143, 0.37156, 0.32046, 0.27726, 0.24113, 0.21126, 0.18684, 0.16707, 0.15118, 0.13843, 0.12815, 0.11974, 0.11271, 0.10670, 0.10141, 0.09663, 0.09224, 0.08814, 0.08427, 0.08061, 0.07715, 0.07387, 0.07077, 0.06785, 0.06511, 0.06254, 0.06014, 0.05790, 0.05582, 0.05388, 0.05207, 0.05038, 0.04879, 0.04731, 0.04591, 0.04459, 0.04334, 0.04216, 0.04103, 0.03996, 0.03894, 0.03796, 0.03702, 0.03612, 0.03526, 0.03443, 0.03363, 0.03287, 0.03214, 0.03143, 0.03075, 0.03010, 0.02947, 0.02887, 0.02829, 0.02773, 0.02719, 0.02666, 0.02616, 0.02567, 0.0250, 0.02475, 0.02431, 0.02388, 0.02347, 0.02306, 0.02267, 0.02230, 0.02193, 0.02157, 0.02123, 0.02089, 0.02056, 0.02025, 0.01994, 0.01964, 0.01934, 0.01906, 0.018, 0.01851, 0.01825, 0.01799, 0.01774, 0.01750, 0.01726, 0.01703, 0.01680, 0.01658, 0.01637, 0.01616, 0.01595, 0.01575, 0.01555}};
+ static const array<double,103> datamatrix4 = {{0.88623, 0.885845, 0.879328, 0.86361, 0.81617, 0.75594, 0.68928, 0.62036, 0.55206, 0.48641, 0.42484, 0.36832, 0.31749, 0.27273, 0.23419, 0.20185, 0.17547, 0.15464, 0.13871, 0.12685, 0.11813, 0.11162, 0.10654, 0.10229, 0.09844, 0.09475, 0.09107, 0.08738, 0.08368, 0.08000, 0.07641, 0.07295, 0.06967, 0.06660, 0.06377, 0.06118, 0.05883, 0.05670, 0.05476, 0.05300, 0.05138, 0.04989, 0.04849, 0.04716, 0.04590, 0.04469, 0.04353, 0.04240, 0.04131, 0.04026, 0.03924, 0.03826, 0.037, 0.03642, 0.03556, 0.03473, 0.03394, 0.03319, 0.03247, 0.03178, 0.03112, 0.03049, 0.02988, 0.02930, 0.02873, 0.02819, 0.02767, 0.02716, 0.02667, 0.02619, 0.02573, 0.02529, 0.02486, 0.02444, 0.02403, 0.02364, 0.02326, 0.02289, 0.02253, 0.02218, 0.02184, 0.02152, 0.02120, 0.02089, 0.02058, 0.02029, 0.02000, 0.01972, 0.01944, 0.01918, 0.01892, 0.01866, 0.01841, 0.01816, 0.01792, 0.01769, 0.01746, 0.01724, 0.01702, 0.01681, 0.01660, 0.01639, 0.01619 }};
+ static const array<double,103> datamatrix5 = {{0.744596, 0.744489, 0.742327, 0.73584, 0.71183, 0.67590, 0.63118, 0.58053, 0.52645, 0.47109, 0.41628, 0.36351, 0.31401, 0.26878, 0.22857, 0.19396, 0.16533, 0.14280, 0.12611, 0.11459, 0.10713, 0.10244, 0.09934, 0.09690, 0.09453, 0.09189, 0.08887, 0.08548, 0.08180, 0.07796, 0.07410, 0.07035, 0.06681, 0.06358, 0.06068, 0.05815, 0.05595, 0.05405, 0.05240, 0.05094, 0.04962, 0.04838, 0.04720, 0.04604, 0.04489, 0.04375, 0.04262, 0.04150, 0.04040, 0.03934, 0.03831, 0.03733, 0.03639, 0.03551, 0.03469, 0.03391, 0.03317, 0.03247, 0.03181, 0.03118, 0.03057, 0.02998, 0.02941, 0.02886, 0.02832, 0.02779, 0.02728, 0.02678, 0.02630, 0.02583, 0.02538, 0.02494, 0.02452, 0.02412, 0.02373, 0.02335, 0.02299, 0.02264, 0.02230, 0.02197, 0.02165, 0.02134, 0.02104, 0.02074, 0.02045, 0.02016, 0.01989, 0.01961, 0.01935, 0.01909, 0.01883, 0.01858, 0.01834, 0.01810, 0.01787, 0.01764, 0.01742, 0.01721, 0.01699, 0.01679, 0.01659, 0.01639, 0.01620}};
+ static const array<double,103> datamatrix6 = {{0.67759, 0.677074, 0.675686, 0.67139, 0.65466, 0.62818, 0.59351, 0.55242, 0.50671, 0.45815, 0.40837, 0.35888, 0.31104, 0.26603, 0.22490, 0.18855, 0.15777, 0.13319, 0.11510, 0.10322, 0.09650, 0.09333, 0.09206, 0.09137, 0.09045, 0.08888, 0.08652, 0.08343, 0.07977, 0.07574, 0.07157, 0.06747, 0.06364, 0.06020, 0.05725, 0.05479, 0.05281, 0.05121, 0.04991, 0.04880, 0.04779, 0.04680, 0.04580, 0.04475, 0.04364, 0.04249, 0.04130, 0.04012, 0.03895, 0.03783, 0.03677, 0.03579, 0.03488, 0.03405, 0.03330, 0.03261, 0.03197, 0.03137, 0.03080, 0.03025, 0.02970, 0.02917, 0.02863, 0.02811, 0.02758, 0.02707, 0.02657, 0.02608, 0.02560, 0.02515, 0.02471, 0.02430, 0.02390, 0.02351, 0.02314, 0.02279, 0.02244, 0.02211, 0.02178, 0.02146, 0.02115, 0.02084, 0.02054, 0.02025, 0.01996, 0.01968, 0.01941, 0.01915, 0.01890, 0.01865, 0.01841, 0.01818, 0.01795, 0.01773, 0.01751, 0.01730, 0.01710, 0.01690, 0.01670, 0.01650, 0.01631, 0.01612, 0.01593 }};
+ //assign the appropriate tabulated points for the number of extra dimensions
+ switch ( _ndim ) {
+ case 2 : _interpol = make_InterpolatorPtr(datamatrix2, xmatrix2, 1); break;
+ case 3 : _interpol = make_InterpolatorPtr(datamatrix3, xmatrix1, 1); break;
+ case 4 : _interpol = make_InterpolatorPtr(datamatrix4, xmatrix1, 1); break;
+ case 5 : _interpol = make_InterpolatorPtr(datamatrix5, xmatrix1, 1); break;
+ case 6 : _interpol = make_InterpolatorPtr(datamatrix6, xmatrix1, 1); break;
+ default : assert(false);
+ }
}
IBPtr METRP2to2::clone() const {
return new_ptr(*this);
}
IBPtr METRP2to2::fullclone() const {
return new_ptr(*this);
}
void METRP2to2::persistentOutput(PersistentOStream & os) const {
os << _interpol << _maxflavour << _process << _ndim << ounit(_planckmass,GeV);
}
void METRP2to2::persistentInput(PersistentIStream & is, int) {
is >> _interpol >> _maxflavour >> _process >> _ndim >> iunit(_planckmass,GeV);
}
Energy2 METRP2to2::scale() const {
Energy2 invbcsq = 1 / sqr(bccalc(sHat()));
return ( -tHat() > invbcsq ) ? invbcsq : -tHat();
}
void METRP2to2::Init() {
static ClassDocumentation<METRP2to2> documentation
("The METRP2to2 class implements the transplanckian 2->2 processes in hadron-hadron"
" collisions");
static Parameter<METRP2to2,unsigned int> interfaceMaximumFlavour
("MaximumFlavour",
"The maximum flavour of the quarks in the process",
&METRP2to2::_maxflavour, 2, 1, 5,
false, false, Interface::limited);
static Parameter<METRP2to2, Energy> interfacePlanckMass
("PlanckMass",
"The Planck Mass",
&METRP2to2::_planckmass, GeV, 2000.0*GeV, 200.0*GeV, 200000.0*GeV,
false, false, Interface::limited);
static Parameter<METRP2to2, unsigned int> interfaceNumberExtraDimensions
("NumberExtraDimensions",
"The number of extra dimensions to consider",
&METRP2to2::_ndim, 6, 2, 6,
false, false, Interface::limited);
static Switch<METRP2to2,unsigned int> interfaceProcess
("Process",
"Which subprocesses to include",
&METRP2to2::_process, 0, false, false);
static SwitchOption interfaceProcessAll
(interfaceProcess,
"All",
"Include all subprocesses",
0);
static SwitchOption interfaceProcess1
(interfaceProcess,
"gg2gg",
"Include only gg->gg subprocesses",
1);
static SwitchOption interfaceProcessqgqg
(interfaceProcess,
"qg2qg",
"Include only q g -> q g processes",
4);
static SwitchOption interfaceProcessqbargqbarg
(interfaceProcess,
"qbarg2qbarg",
"Include only qbar g -> qbar g processes",
5);
static SwitchOption interfaceProcessqqqq
(interfaceProcess,
"qq2qq",
"Include only q q -> q q processes",
6);
static SwitchOption interfaceProcessqbarqbarqbarqbar
(interfaceProcess,
"qbarqbar2qbarqbar",
"Include only qbar qbar -> qbar qbar processes",
7);
static SwitchOption interfaceProcessqqbarqqbar
(interfaceProcess,
"qqbar2qqbar",
"Include only q qbar -> q qbar processes",
8);
}
Selector<MEBase::DiagramIndex>
METRP2to2::diagrams(const DiagramVector & diags) const {
// select the diagram, this is easy for us as we have already done it
Selector<DiagramIndex> sel;
for ( DiagramIndex i = 0; i < diags.size(); ++i ) {
sel.insert(1.0, i);
}
return sel;
}
void METRP2to2::getDiagrams() const {
// get the particle data objects
PDPtr gluon = getParticleData(ParticleID::g);
PDPtr trpon = getParticleData(39);
vector<PDPtr> quark,antiquark;
for(int ix=1;ix<=int(_maxflavour);++ix) {
quark.push_back( getParticleData( ix));
antiquark.push_back(getParticleData(-ix));
}
// gg-> gg subprocess
if(_process==0||_process==1) {
add(new_ptr((Tree2toNDiagram(3),gluon,trpon,gluon,
1,gluon, 2,gluon,-2)));
}
// processes involving one quark line
for(unsigned int ix=0;ix<_maxflavour;++ix) {
// q g -> q g subprocesses
if(_process==0||_process==4) {
add(new_ptr((Tree2toNDiagram(3),quark[ix],trpon,gluon,
1,quark[ix],2,gluon,-12)));
}
// qbar g -> qbar g subprocesses
if(_process==0||_process==5) {
add(new_ptr((Tree2toNDiagram(3),antiquark[ix],trpon,gluon,
1,antiquark[ix],2,gluon,-15)));
}
// processes involving two quark lines
for(unsigned int iy=0;iy<_maxflavour;++iy) {
// q q -> q q subprocesses
if(_process==0||_process==6) {
// t-channel
add(new_ptr((Tree2toNDiagram(3),quark[ix],trpon,quark[iy],
1,quark[ix],2,quark[iy],-16)));
//exchange for identical quarks
if(ix==iy)
add(new_ptr((Tree2toNDiagram(3),quark[ix],trpon,quark[iy],
2,quark[ix],1,quark[iy],-17)));
}
// qbar qbar -> qbar qbar subprocesses
if(_process==0||_process==7) {
// t-channel
add(new_ptr((Tree2toNDiagram(3),antiquark[ix],trpon,antiquark[iy],
1,antiquark[ix],2,antiquark[iy],-18)));
//exchange for identical quarks
if(ix==iy)
add(new_ptr((Tree2toNDiagram(3),antiquark[ix],trpon,antiquark[iy],
2,antiquark[ix],1,antiquark[iy],-19)));
}
// q qbar -> q qbar
if(_process==0||_process==8) {
add(new_ptr((Tree2toNDiagram(3),quark[ix],trpon,antiquark[iy],
1,quark[ix],2,antiquark[iy],-21)));
}
}
}
}
Selector<const ColourLines *>
METRP2to2::colourGeometries(tcDiagPtr diag) const {
// colour lines for gg to gg
static const ColourLines cgggg("1 4, -1 -4, 3 5, -3 -5");
// colour lines for q g to q g
static const ColourLines cqgqg("1 4, 3 5, -3 -5");
// colour lines for qbar g -> qbar g
static const ColourLines cqbgqbg("-1 -4, -3 -5, 3 5");
// colour lines for q q -> q q
static const ColourLines cqqqq("1 4,3 5");
// colour lines for qbar qbar -> qbar qbar
static const ColourLines cqbqbqbqb("-1 -4,-3 -5");
// colour lines for q qbar -> q qbar
static const ColourLines cqqbqqb("1 4,-3 -5");
// select the colour flow (as already picked just insert answer)
Selector<const ColourLines *> sel;
switch(abs(diag->id())) {
//gg -> gg
case 2:
sel.insert(1.0, &cgggg);
break;
// q g -> q g subprocess
case 12:
sel.insert(1.0, &cqgqg);
break;
// qbar g -> qbar g subprocess
case 15:
sel.insert(1.0, &cqbgqbg);
break;
// q q -> q q subprocess
case 16: case 17:
sel.insert(1.0, &cqqqq);
break;
// qbar qbar -> qbar qbar subprocess
case 18: case 19:
sel.insert(1.0, &cqbqbqbqb);
break;
// q qbar -> q qbar subprocess
case 21:
sel.insert(1.0, &cqqbqqb);
break;
}
return sel;
}
double METRP2to2::me2() const {
double me(0.), me_exch(0.);
double fac1(1.), fac2(0.);
if ( mePartonData()[0]->id() == mePartonData()[1]->id() ) {
if ( mePartonData()[0]->id()>0 ) {
me_exch = - A_ny(sHat(),uHat());
fac1 = 2./3.;
fac2 = 1./6.;
}
else if ( mePartonData()[0]->id() == ParticleID::g ) {
me_exch = A_ny(sHat(),uHat());
fac1 = 7./8.;
fac2 = 1./16.;
}
}
me = A_ny(sHat(),tHat());
return fac1 * sqr(me) + fac2 * sqr(me+me_exch);
}
// Calculate the constant b_c which depends on s_hat and the number of
// extra dimensions
InvEnergy METRP2to2::bccalc(Energy2 s) const {
static const double fourpi = 4.0*Constants::pi;
return 1/_planckmass * sqrt(fourpi) *
pow( (0.5 * s / (sqr(_planckmass) * fourpi)) * Math::gamma(_ndim/2.0),
1.0/_ndim);
}
//Calculation of the matrix element squared using the function F_n(y)
double METRP2to2::A_ny(Energy2 s, Energy2 t) const {
InvEnergy bc = bccalc(s);
double fny = 0;
double y = bc * sqrt(-t);
if ( y >= 20.0 )
fny = fnyasympt(y);
else
fny = fpoint(y);
return 4. * Constants::pi * fny * s * sqr(bc);
}
//The asymptotic form of the F_n functions; used for x > 20
double METRP2to2::fnyasympt(double y) const {
return pow( _ndim, 1.0/(_ndim+1.0) ) * pow( y, -(_ndim+2.0)/(_ndim+1.0) ) / sqrt(_ndim+1.0);
}
//fpoint uses the interpolator to calculate the value of F_n for intermediate values of the argument
double METRP2to2::fpoint(double x) const {
assert( x < 20.0 );
if ( _ndim == 2 && x < 0.02 ) {
return sqrt( sqr(-log(x/1.4)) + sqr(Constants::pi)/16 );
}
else {
return (*_interpol)(x);
}
}
diff --git a/Models/UED/UEDF1F0G1Vertex.cc b/Models/UED/UEDF1F0G1Vertex.cc
--- a/Models/UED/UEDF1F0G1Vertex.cc
+++ b/Models/UED/UEDF1F0G1Vertex.cc
@@ -1,100 +1,101 @@
// -*- C++ -*-
//
// UEDF1F0G1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDF1F0G1Vertex class.
//
#include "UEDF1F0G1Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDF1F0G1Vertex::UEDF1F0G1Vertex() : theq2Last(ZERO), theCoupLast(0.) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TFUND);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<UEDF1F0G1Vertex,FFVVertex>
describeHerwigUEDF1F0G1Vertex("Herwig::UEDF1F0G1Vertex", "HwUED.so");
void UEDF1F0G1Vertex::Init() {
static ClassDocumentation<UEDF1F0G1Vertex> documentation
("This class implements the F^1-F^0-G^1 vertex.");
}
void UEDF1F0G1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long ifermN;
if(part1->id() == 5100021) {
if(abs(part2->id()) > 5100000)
ifermN = part2->id();
else
ifermN = part3->id();
}
else if(part2->id() == 5100021) {
if(abs(part1->id()) > 5100000)
ifermN = part1->id();
else
ifermN = part3->id();
}
else if(part3->id() == 5100021) {
if(abs(part2->id()) > 5100000)
ifermN = part2->id();
else
ifermN = part1->id();
}
else
throw HelicityLogicalError() << "UEDF1F0G1Vertex::setCoupling - "
<< "There is no KK gluon in this vertex!"
<< Exception::warning;
if((abs(ifermN) >= 5100001 && abs(ifermN) <= 5100006) ||
(abs(ifermN) >= 6100001 && abs(ifermN) <= 6100006)) {
if(q2 != theq2Last || theCoupLast == 0.) {
theq2Last = q2;
theCoupLast = -strongCoupling(q2);
}
norm(theCoupLast);
int state = abs(ifermN)/1000000;
if(state == 5) {
left(1.);
right(0.);
}
else {
left(0.);
right(1.);
}
}
else
throw HelicityLogicalError() << "UEDF1F0G1Vertex::setCoupling - "
<< "There is an unknown particle in this vertex! "
<< ifermN
<< Exception::warning;
}
void UEDF1F0G1Vertex::doinit() {
long boson = 5100021;
//QQ
for(long i = 1; i < 7; ++i) {
addToList(-i, i + 5100000, boson);
addToList(-(i + 5100000), i, boson);
addToList(-i, i + 6100000, boson);
addToList(-(i + 6100000), i, boson);
}
FFVVertex::doinit();
}
diff --git a/Models/UED/UEDF1F0H1Vertex.cc b/Models/UED/UEDF1F0H1Vertex.cc
--- a/Models/UED/UEDF1F0H1Vertex.cc
+++ b/Models/UED/UEDF1F0H1Vertex.cc
@@ -1,205 +1,206 @@
// -*- C++ -*-
//
// UEDF1F0H1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDF1F0H1Vertex class.
//
#include "UEDF1F0H1Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDF1F0H1Vertex::UEDF1F0H1Vertex() : theRadius(ZERO), theMw(ZERO),
theSinThetaW(0.), theq2Last(ZERO),
theCoupLast(0.), theLeftLast(0.),
theRightLast(0.), theAntiLast(0),
theFermLast(0), theHLast(0) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
void UEDF1F0H1Vertex::doinit() {
long heavy[3] = {5, 6, 15};
//h0
for( unsigned int i = 0; i < 3; ++i ) {
addToList(-5100000 - i, 5100000 + i, 25);
addToList(-6100000 - i, 6100000 + i, 25);
addToList(-5100000 - i, 6100000 + i, 25);
addToList(-6100000 - i, 5100000 + i, 25);
}
// Neutral KK-Higgs
long higgs[2] = {5100025, 5100036};
for( unsigned int h = 0; h < 2; ++h ) {
for( unsigned int i = 0; i < 3; ++i ) {
addToList(-heavy[i], 5100000 + heavy[i], higgs[h]);
addToList(-5100000 - heavy[i], heavy[i], higgs[h]);
addToList(-heavy[i], 6100000 + heavy[i], higgs[h]);
addToList(-6100000 - heavy[i], heavy[i], higgs[h]);
}
}
//KK-charged higgs
//outgoing H+
addToList(-5100006, 5, 5100037);
addToList(-6100006, 5, 5100037);
addToList(-6, 5100005, 5100037);
addToList(-6, 6100005, 5100037);
addToList(-5100016, 15, 5100037);
addToList(-6100016, 15, 5100037);
addToList(-16, 5100015, 5100037);
addToList(-16, 6100015, 5100037);
//outgoing H-
addToList(-5100005, 6,-5100037);
addToList(-6100005, 6,-5100037);
addToList(-5, 5100006,-5100037);
addToList(-5, 6100006,-5100037);
addToList(-5100015, 16,-5100037);
addToList(-6100015, 16,-5100037);
addToList(-15, 5100016,-5100037);
addToList(-15, 6100016,-5100037);
FFSVertex::doinit();
tUEDBasePtr UEDBase =
dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!UEDBase)
throw InitException() << "UEDF1F0H1Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
theRadius = UEDBase->compactRadius();
theSinThetaW = sqrt(sin2ThetaW());
theCosThetaW = sqrt(1. - sin2ThetaW());
theMw = getParticleData(24)->mass();
theMz = getParticleData(23)->mass();
}
void UEDF1F0H1Vertex::persistentOutput(PersistentOStream & os) const {
os << ounit(theRadius,1/GeV) << ounit(theMw,GeV) << theSinThetaW
<< ounit(theMz, GeV) << theCosThetaW;
}
void UEDF1F0H1Vertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(theRadius,1/GeV) >> iunit(theMw,GeV) >> theSinThetaW
>> iunit(theMz, GeV) >> theCosThetaW;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDF1F0H1Vertex,FFSVertex>
describeHerwigUEDF1F0H1Vertex("Herwig::UEDF1F0H1Vertex", "HwUED.so");
void UEDF1F0H1Vertex::Init() {
static ClassDocumentation<UEDF1F0H1Vertex> documentation
("The coupling involving a KK-Higgs and a pair of fermions.");
}
void UEDF1F0H1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long anti(abs(part1->id())), ferm(abs(part2->id())), higgs(part3->id());
if( ferm > 17 ) swap( ferm, anti);
if( anti != theAntiLast || ferm != theFermLast || higgs != theHLast ) {
theAntiLast = anti;
theFermLast = ferm;
theHLast = higgs;
tcPDPtr pd;
if( higgs != 25 ) {
pd = getParticleData(ferm);
}
else {
long smid = ( ferm/1000000 == 5 ) ? ferm - 5100000 : ferm - 6100000;
pd = getParticleData(smid);
}
Energy mf = pd->mass();
double alpha = mf*theRadius/2.;
double salpha = sin(alpha);
double calpha = cos(alpha);
double fact(0.);
if( abs(higgs) == 5100037 ) {
fact = theRadius/2./sqrt(1. + sqr(theMw*theRadius)) * UnitRemoval::E;
theRightLast = theRadius*theMw;
if(anti/1000000 == 5) {
Energy mfk = getParticleData(anti - 5100000)->mass();
theLeftLast = (theMw*calpha - (mfk*salpha/theRadius/theMw))
* UnitRemoval::InvE;
theRightLast *= calpha*mfk* UnitRemoval::InvE;
}
else {
Energy mfk = getParticleData(anti - 6100000)->mass();
theLeftLast = (theMw*salpha +(mfk*calpha/theRadius/theMw))
* UnitRemoval::InvE;
theRightLast *= -salpha*mfk*UnitRemoval::InvE;
}
theLeftLast *= fact;
theRightLast *= fact;
if( higgs < 0 ) swap( theLeftLast, theRightLast );
}
else if( higgs == 5100025 ) {
fact = mf/theMw/2.;
if( anti/1000000 == 5 )
theLeftLast = salpha + calpha;
else
theLeftLast = salpha - calpha;
theRightLast = theLeftLast;
theLeftLast *= fact;
theRightLast *= fact;
}
else if( higgs == 5100036 ) {
fact = theRadius/theCosThetaW/sqrt(1.+sqr(theMz*theRadius))*UnitRemoval::E;
double i3f = ( ferm % 2 == 0 ) ? 0.5 : -0.5;
double qf = pd->charge()/eplus;
if( anti/1000000 == 5 ) {
theLeftLast = (theMz*calpha*(i3f - qf*sqr(theSinThetaW))
- mf*salpha/theRadius/theMw) * UnitRemoval::InvE;
theRightLast = (-theMz*salpha*qf*sqr(theSinThetaW)
+ mf*calpha/theRadius/theMw) * UnitRemoval::InvE;
}
else {
theLeftLast = (theMz*salpha*(i3f - qf*sqr(theSinThetaW))
- mf*calpha/theRadius/theMw) * UnitRemoval::InvE;
theRightLast = (-theMz*calpha*qf*sqr(theSinThetaW)
+ mf*salpha/theRadius/theMw)*UnitRemoval::InvE;
}
theLeftLast *= fact;
theRightLast *= fact;
}
else {
theLeftLast = mf*calpha*salpha/2./theMw;
if( ferm/1000000 == 5 ) theLeftLast *= -1.;
theRightLast = theLeftLast;
}
}
if(q2 != theq2Last || theCoupLast == 0.) {
theq2Last = q2;
theCoupLast = weakCoupling(q2);
}
norm(theCoupLast);
left(theLeftLast);
right(theRightLast);
}
diff --git a/Models/UED/UEDF1F0W1Vertex.cc b/Models/UED/UEDF1F0W1Vertex.cc
--- a/Models/UED/UEDF1F0W1Vertex.cc
+++ b/Models/UED/UEDF1F0W1Vertex.cc
@@ -1,186 +1,187 @@
// -*- C++ -*-
//
// UEDF1F0W1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDF1F0W1Vertex class.
//
#include "UEDF1F0W1Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Models/StandardModel/StandardCKM.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDF1F0W1Vertex::UEDF1F0W1Vertex() : theSinW(0.), theCosW(0.), theSinOne(0.),
theCosOne(0.), theSinWmO(0.),
theCosWmO(0.),
theCKM(0, vector<Complex>(0, 0.)),
theq2last(),
theCouplast(0.), theLlast(0.),
theRlast(0.), theGBlast(0),
theKKlast(0), theSMlast(0) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
void UEDF1F0W1Vertex::doinit() {
//outgoing W+
for(long i = 2; i < 7; i += 2) {
for(long j = 1; j < 6; j += 2) {
addToList( -i, 5100000 + j, 5100024 );
addToList( -(5100000 + i), j, 5100024 );
}
}
for(long i = 11; i < 17; i += 2) {
addToList( -i-1, 5100000 + i, 5100024 );
addToList( -(5100001 + i), i, 5100024 );
}
//outgoing W-
for(long i = 1; i < 6; i += 2) {
for(long j = 2 ; j < 7; j += 2) {
addToList( -i, 5100000 + j, -5100024 );
addToList( -(5100000 + i), j, -5100024 );
}
}
for(long i = 11; i < 17; i += 2) {
addToList( -i, 5100001 + i, -5100024 );
addToList(-(5100000 + i), i + 1, -5100024);
}
long boson[2] = {5100022,5100023};
for(long b = 0; b < 2; ++b) {
//QQ
for(int i = 1; i < 7; ++i) {
addToList( -i, i + 5100000, boson[b]);
addToList(-(i + 5100000), i, boson[b]);
addToList(-i, i + 6100000, boson[b]);
addToList(-(i + 6100000), i, boson[b]);
}
//LL
for(int i = 11; i < 17; ++i) {
addToList( -i, i + 5100000, boson[b]);
addToList(-(i + 5100000), i, boson[b]);
if( i % 2 != 0 ) {
addToList(-i, i + 6100000, boson[b]);
addToList(-(i + 6100000), i, boson[b]);
}
}
}
FFVVertex::doinit();
tUEDBasePtr UEDBase =
dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!UEDBase)
throw InitException() << "UEDF1F0W1Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
theSinW = sqrt(sin2ThetaW());
theCosW = sqrt( 1. - sqr(theSinW));
theSinOne = UEDBase->sinThetaOne();
theCosOne = sqrt(1. - sqr(theSinOne));
theSinWmO = theSinW*theCosOne - theSinOne*theCosW;
theCosWmO = theCosW*theCosOne + theSinW*theSinOne;
theCKM = dynamic_ptr_cast<Ptr<StandardCKM>::transient_pointer>
(UEDBase->CKM())->getUnsquaredMatrix(UEDBase->families());
}
void UEDF1F0W1Vertex::persistentOutput(PersistentOStream & os) const {
os << theSinW << theCosW << theSinOne << theCosOne
<< theSinWmO << theCosWmO << theCKM;
}
void UEDF1F0W1Vertex::persistentInput(PersistentIStream & is, int) {
is >> theSinW >> theCosW >> theSinOne >> theCosOne
>> theSinWmO >> theCosWmO >> theCKM;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDF1F0W1Vertex,FFVVertex>
describeHerwigUEDF1F0W1Vertex("Herwig::UEDF1F0W1Vertex", "HwUED.so");
void UEDF1F0W1Vertex::Init() {
static ClassDocumentation<UEDF1F0W1Vertex> documentation
("This is the coupling of a KK1 W boson to a KK1 fermion and "
"a SM fermion.");
}
void UEDF1F0W1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long id1(abs(part1->id())), id2(abs(part2->id())),
gboson(abs(part3->id())), kkparticle(0), smID(0);
assert( gboson == 5100022 || gboson == 5100023 || gboson == 5100024 );
if( id1 > 5000000 ) {
kkparticle = id1;
smID = id2;
}
else {
kkparticle = id2;
smID = id1;
}
if( (kkparticle >= 5100001 && kkparticle <= 5100006) ||
(kkparticle >= 6100001 && kkparticle <= 6100006) ||
(kkparticle >= 5100011 && kkparticle <= 5100016) ||
(kkparticle >= 6100011 && kkparticle <= 6100016) ) {
if(q2 != theq2last || theCouplast == 0.) {
theq2last = q2;
theCouplast = electroMagneticCoupling(q2);
}
if( gboson != theGBlast || kkparticle != theKKlast || smID != theSMlast ) {
theGBlast = gboson;
theKKlast = kkparticle;
theSMlast = smID;
if( gboson == 5100024 ) {
Complex ckm(1.);
if( smID >= 1 && smID <= 6 ) {
long smIDb(kkparticle - 5100000);
if( smID % 2 != 0 ) swap(smID, smIDb);
ckm = theCKM[smID/2 - 1][(smIDb - 1)/2];
}
theLlast = -ckm/sqrt(2)/theSinW;
theRlast = 0.;
}
else if( gboson == 5100022 || gboson == 5100023 ) {
double Qf = getParticleData(smID)->charge()/eplus;
if( kkparticle/1000000 == 5 ) {
theRlast = 0.;
double I3f = (abs(smID) % 2 == 0) ? 0.5 : -0.5;
if( gboson == 5100023 )
theLlast = (Qf*theSinOne
- I3f*theCosWmO/theSinW)/theCosW;
else
theLlast = -(Qf*theCosOne
- I3f*theSinWmO/theSinW)/theCosW;
}
else {
theLlast = 0.;
if( gboson == 5100023 )
theRlast = Qf*theSinOne/theCosW;
else
theRlast = -Qf*theCosOne/theCosW;
}
}
}
norm(theCouplast);
left(theLlast);
right(theRlast);
}
else
throw HelicityLogicalError() << "UEDF1F0W1Vertex::setCoupling - "
<< "There is an unknown particle in this vertex! "
<< kkparticle
<< Exception::warning;
}
diff --git a/Models/UED/UEDF1F1G0Vertex.cc b/Models/UED/UEDF1F1G0Vertex.cc
--- a/Models/UED/UEDF1F1G0Vertex.cc
+++ b/Models/UED/UEDF1F1G0Vertex.cc
@@ -1,79 +1,80 @@
// -*- C++ -*-
//
// UEDF1F1G0Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDF1F1G0Vertex class.
//
#include "UEDF1F1G0Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDF1F1G0Vertex::UEDF1F1G0Vertex()
: theq2Last(ZERO), theCoupLast(0.) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3TFUND);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<UEDF1F1G0Vertex,FFVVertex>
describeHerwigUEDF1F1G0Vertex("Herwig::UEDF1F1G0Vertex", "HwUED.so");
void UEDF1F1G0Vertex::Init() {
static ClassDocumentation<UEDF1F1G0Vertex> documentation
("This class implements the F^1 F^1 G^0 vertex.");
}
void UEDF1F1G0Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long iferm;
if(part1->id() == ParticleID::g)
iferm = abs(part2->id());
else if(part2->id() == ParticleID::g)
iferm = abs(part1->id());
else if(part3->id() == ParticleID::g)
iferm = abs(part1->id());
else
throw HelicityLogicalError() << "UEDF1F1G0Vertex::setCoupling - "
<< "There is no gluon in this vertex!"
<< Exception::warning;
if((iferm >= 5100001 && iferm <= 5100006) ||
(iferm >= 6100001 && iferm <= 6100006)) {
if(q2 != theq2Last || theCoupLast ==0. ) {
theCoupLast = -strongCoupling(q2);
theq2Last=q2;
}
norm(theCoupLast);
left(1.);
right(1.);
}
else
throw HelicityLogicalError() << "UEDF1F1G0Vertex::setCoupling - "
<< "There is an unknown particle in this vertex! "
<< iferm
<< Exception::warning;
}
void UEDF1F1G0Vertex::doinit() {
long boson = 21;
//QQ
for(long i = 5100001; i < 6100007; ++i) {
if(i == 5100007) i += 999994;
addToList(-i, i, boson);
}
FFVVertex::doinit();
}
diff --git a/Models/UED/UEDF1F1P0Vertex.cc b/Models/UED/UEDF1F1P0Vertex.cc
--- a/Models/UED/UEDF1F1P0Vertex.cc
+++ b/Models/UED/UEDF1F1P0Vertex.cc
@@ -1,108 +1,109 @@
// -*- C++ -*-
//
// UEDF1F1P0Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDF1F1P0Vertex class.
//
#include "UEDF1F1P0Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDF1F1P0Vertex::UEDF1F1P0Vertex() : coupLast_(0.0), q2Last_(ZERO),
fermLast_(0), LRLast_(0.0),
charges_(3) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
void UEDF1F1P0Vertex::persistentOutput(PersistentOStream & os) const {
os << charges_;
}
void UEDF1F1P0Vertex::persistentInput(PersistentIStream & is, int) {
is >> charges_;
}
void UEDF1F1P0Vertex::doinit() {
long photon = 22;
//quarks
for(long i = 1; i < 7; ++i) {
//left
addToList(-5100000 - i, 5100000 + i, photon);
//right
addToList(-6100000 - i, 6100000 + i, photon);
}
//leptons
for(long i = 11; i < 17; i += 2) {
//left
addToList(-5100000 - i, 5100000 + i, photon);
//right
addToList(-6100000 - i, 6100000 + i, photon);
}
FFVVertex::doinit();
tUEDBasePtr UEDBase =
dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!UEDBase)
throw InitException() << "UEDF1F1P0Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
charges_[0] = UEDBase->ee();
charges_[1] = UEDBase->ed();
charges_[2] = UEDBase->eu();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDF1F1P0Vertex,FFVVertex>
describeHerwigUEDF1F1P0Vertex("Herwig::UEDF1F1P0Vertex", "HwUED.so");
void UEDF1F1P0Vertex::Init() {
static ClassDocumentation<UEDF1F1P0Vertex> documentation
("This class couples a pair of level-1 KK fermions to an SM "
"photon.");
}
void UEDF1F1P0Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr ,
#ifndef NDEBUG
tcPDPtr part3) {
#else
tcPDPtr ) {
#endif
long iferm = abs(part1->id());
assert(part3->id()==ParticleID::gamma);
assert((iferm >= 5100001 && iferm <= 5100006) ||
(iferm >= 5100011 && iferm <= 5100016) ||
(iferm >= 6100001 && iferm <= 6100006) ||
(iferm >= 6100011 && iferm <= 6100016));
if(q2 != q2Last_ || coupLast_ == 0. ) {
q2Last_ = q2;
coupLast_ = -electroMagneticCoupling(q2);
}
norm(coupLast_);
if(iferm != fermLast_) {
fermLast_ = iferm;
int smtype = (iferm > 6000000) ? iferm - 6100000 : iferm - 5100000;
if(smtype >= 11)
LRLast_ = charges_[0];
else
LRLast_ = (smtype % 2 == 0) ? charges_[2] : charges_[1];
}
left(LRLast_);
right(LRLast_);
}
diff --git a/Models/UED/UEDF1F1W0Vertex.cc b/Models/UED/UEDF1F1W0Vertex.cc
--- a/Models/UED/UEDF1F1W0Vertex.cc
+++ b/Models/UED/UEDF1F1W0Vertex.cc
@@ -1,183 +1,184 @@
// -*- C++ -*-
//
// UEDF1F1W0Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDF1F1W0Vertex class.
//
#include "UEDF1F1W0Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDF1F1W0Vertex::UEDF1F1W0Vertex(): includeMixing_(true),
theRadius(ZERO), theQ2Last(ZERO),
theCoupLast(0.),
thefermALast(0), thefermBLast(0) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
void UEDF1F1W0Vertex::doinit() {
//outgoing W+
for( long i = 2; i < 17; i += 2 ) {
if( i == 7 ) i += 5;
addToList(-5100000 - i, 5100000 + i - 1, 24);
if( i < 7 ) {
addToList(-6100000 - i, 6100000 + i - 1, 24);
}
}
if(includeMixing_) {
addToList(-6100006, 5100005, 24);
addToList(-5100006, 6100005, 24);
}
//outgoing W-
for( long i = 1; i < 16; i += 2 ) {
if( i == 6 ) i += 5;
addToList(-5100000 - i, 5100001 + i, -24);
if( i < 6 ) {
addToList(-6100000 - i, 6100001 + i, -24);
}
}
if(includeMixing_) {
addToList(-6100005, 5100006, -24);
addToList(-5100005, 6100006, -24);
}
FFVVertex::doinit();
tUEDBasePtr model = dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!model)
throw InitException() << "UEDF1F1W0Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
theRadius = model->compactRadius();
}
void UEDF1F1W0Vertex::persistentOutput(PersistentOStream & os) const {
os << ounit(theRadius,1/GeV) << includeMixing_;
}
void UEDF1F1W0Vertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(theRadius,1/GeV) >> includeMixing_;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDF1F1W0Vertex,FFVVertex>
describeHerwigUEDF1F1W0Vertex("Herwig::UEDF1F1W0Vertex", "HwUED.so");
void UEDF1F1W0Vertex::Init() {
static ClassDocumentation<UEDF1F1W0Vertex> documentation
("This class implements the coupling of a pair of level-1 KK fermions"
"to an SM W boson");
static Switch<UEDF1F1W0Vertex,bool> interfaceIncludeMixing
("IncludeMixing",
"Include the mixing",
&UEDF1F1W0Vertex::includeMixing_, true, false, false);
static SwitchOption interfaceIncludeMixingYes
(interfaceIncludeMixing,
"Yes",
"Include mixing",
true);
static SwitchOption interfaceIncludeMixingNo
(interfaceIncludeMixing,
"No",
"Don't include mixing",
false);
}
void UEDF1F1W0Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
#ifndef NDEBUG
tcPDPtr part3) {
#else
tcPDPtr) {
#endif
long ianti(abs(part1->id())), iferm(abs(part2->id()));
assert( abs(part3->id()) == 24 );
bool ferma = (iferm >= 5100001 && iferm <= 5100006) ||
(iferm >= 6100001 && iferm <= 6100006) ||
(iferm >= 5100011 && iferm <= 5100016) ||
(iferm >= 6100011 && iferm <= 6100016);
bool fermb = (ianti >= 5100001 && ianti <= 5100006) ||
(ianti >= 6100001 && ianti <= 6100006) ||
(ianti >= 5100011 && ianti <= 5100016) ||
(ianti >= 6100011 && ianti <= 6100016);
if( !ferma || !fermb )
throw HelicityLogicalError() << "UEDF1F1W0Vertex::setCoupling - "
<< "There is an unknown particle(s) in the "
<< "UED F^(1) F^(1) W^(0) vertex. ID: "
<< ianti << " " << iferm
<< Exception::runerror;
if(q2 != theQ2Last || theCoupLast == 0. ) {
theQ2Last = q2;
theCoupLast = sqrt(0.5)*weakCoupling(q2);
}
if(iferm != thefermALast || ianti != thefermBLast) {
thefermALast = iferm;
thefermBLast = ianti;
int stateA(ianti/1000000), stateB(iferm/1000000);
long sma = (stateA == 6) ? ianti - 6100000 : ianti - 5100000;
long smb = (stateB == 6) ? iferm - 6100000 : iferm - 5100000;
double afu(0.), afd(0.);
if(includeMixing_) {
if( sma % 2 == 0 ) {
afu = atan(getParticleData(sma)->mass()*theRadius)/2.;
afd = atan(getParticleData(smb)->mass()*theRadius)/2.;
}
else {
afd = atan(getParticleData(sma)->mass()*theRadius)/2.;
afu = atan(getParticleData(smb)->mass()*theRadius)/2.;
}
}
else {
afd = afu = 0.;
}
if( stateA == stateB ) {
if( stateA == 5 ) {
left(cos(afu)*cos(afd));
right(cos(afu)*cos(afd));
}
else {
left(sin(afu)*sin(afd));
right(sin(afu)*sin(afd));
}
}
else {
if( sma % 2 == 0 ) {
if( stateA == 5 ) {
left(cos(afu)*sin(afd));
right(-cos(afu)*sin(afd));
}
else {
left(sin(afu)*cos(afd));
right(-sin(afu)*cos(afd));
}
}
else {
if( stateA == 5 ) {
left(sin(afu)*cos(afd));
right(-sin(afu)*cos(afd));
}
else {
left(cos(afu)*sin(afd));
right(-cos(afu)*sin(afd));
}
}
}
}
norm(theCoupLast);
}
diff --git a/Models/UED/UEDF1F1Z0Vertex.cc b/Models/UED/UEDF1F1Z0Vertex.cc
--- a/Models/UED/UEDF1F1Z0Vertex.cc
+++ b/Models/UED/UEDF1F1Z0Vertex.cc
@@ -1,161 +1,162 @@
// -*- C++ -*-
//
// UEDF1F1Z0Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDF1F1Z0Vertex class.
//
#include "UEDF1F1Z0Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDF1F1Z0Vertex::UEDF1F1Z0Vertex() : theSin2ThW(0.0), theCosThW(0.0), theRadius(),
theID1Last(0), theID2Last(0) ,
theq2Last(ZERO), theCoupLast(0.),
theLeftLast(0.), theRightLast(0.) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::DELTA);
}
void UEDF1F1Z0Vertex::doinit() {
long boson = 23;
//QQ, uu, dd
for(long i = 5100001; i < 6100007; ++i) {
if(i == 5100007) i += 999994;
addToList(-i, i, boson);
}
//top/bottom quark l/r mixing
addToList(-5100006, 6100006, boson);
addToList(-6100006, 5100006, boson);
addToList(-5100005, 6100005, boson);
addToList(-6100005, 5100005, boson);
//leptons
for(long i = 5100011; i < 5100017; ++i) {
addToList(-i, i, boson);
}
for(long i = 6100011; i < 6100017; i +=2) {
addToList(-i, i, boson);
}
FFVVertex::doinit();
UEDBasePtr model = dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!model)
throw InitException() << "UEDF1F1Z0Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
theSin2ThW = sin2ThetaW();
theCosThW = sqrt(1. - theSin2ThW);
theRadius = model->compactRadius();
}
void UEDF1F1Z0Vertex::persistentOutput(PersistentOStream & os) const {
os << theSin2ThW << theCosThW << ounit(theRadius,1/GeV);
}
void UEDF1F1Z0Vertex::persistentInput(PersistentIStream & is, int) {
is >> theSin2ThW >> theCosThW >> iunit(theRadius,1/GeV);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDF1F1Z0Vertex,FFVVertex>
describeHerwigUEDF1F1Z0Vertex("Herwig::UEDF1F1Z0Vertex", "HwUED.so");
void UEDF1F1Z0Vertex::Init() {
static ClassDocumentation<UEDF1F1Z0Vertex> documentation
("This is the implementation of the level-1 fermion pair Z_0 boson "
"coupling.");
}
void UEDF1F1Z0Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
if( part3->id() != 23 ) {
norm(0.0);
left(0.0);
right(0.0);
throw HelicityLogicalError()
<< "UEDF1F1Z0Vertex::setCoupling - The vector boson in this vertex "
<< "is not a Z^0 boson. ID: " << part3->id() << "\n"
<< Exception::warning;
return;
}
long ianti(abs(part1->id())), iferm(abs(part2->id()));
bool ferma = (iferm >= 5100001 && iferm <= 5100006) ||
(iferm >= 6100001 && iferm <= 6100006) ||
(iferm >= 5100011 && iferm <= 5100016) ||
(iferm >= 6100011 && iferm <= 6100016);
bool fermb = (ianti >= 5100001 && ianti <= 5100006) ||
(ianti >= 6100001 && ianti <= 6100006) ||
(ianti >= 5100011 && ianti <= 5100016) ||
(ianti >= 6100011 && ianti <= 6100016);
if( ferma && fermb ) {
if(q2 != theq2Last || theCoupLast == 0. ) {
theq2Last = q2;
theCoupLast = 0.5*weakCoupling(q2)/theCosThW;
}
if( ianti != theID1Last || iferm != theID2Last) {
theID1Last = ianti;
theID2Last = iferm;
int stateA = ianti/1000000;
int stateB = iferm/1000000;
long smID = (stateA == 6) ? ianti - 6100000 : ianti - 5100000;
// L/R mixing
double alpha = atan(getParticleData(smID)->mass()*theRadius)/2.;
double sin2al = sqr(sin(alpha));
double cos2al = 1. - sin2al;
if(stateA == 5 && stateB == 5) {
if(smID >= 11 && smID <= 16)
theLeftLast = -cos2al + 2.*theSin2ThW;
else if(smID <= 6 && smID % 2 == 0)
theLeftLast = cos2al - 4.*theSin2ThW/3.;
else
theLeftLast = -cos2al + 2.*theSin2ThW/3.;
theRightLast = theLeftLast;
}
else if(stateA == 6 && stateB == 6) {
if(smID >= 11 && smID <= 16)
theLeftLast = -sin2al + 2.*theSin2ThW;
else if(smID <=6 && smID % 2 == 0)
theLeftLast = sin2al - 4.*theSin2ThW/3.;
else
theLeftLast = -sin2al + 2.*theSin2ThW/3.;
theRightLast = theLeftLast;
}
else {
theLeftLast = sqrt(sin2al*cos2al);
if(smID % 2 == 0) theLeftLast *= -1.;
theRightLast = -theLeftLast;
}
}
norm(theCoupLast);
left(theLeftLast);
right(theRightLast);
}
else {
throw HelicityLogicalError() << "UEDF1F1Z0Vertex::setCoupling - "
<< "There is an unknown particle(s) in the "
<< "UED F^(1) F^(1) Z^(0) vertex. ID: "
<< ianti << " " << iferm
<< Exception::warning;
norm(0.0);
left(0.0);
right(0.0);
}
}
diff --git a/Models/UED/UEDG0G0G1G1Vertex.cc b/Models/UED/UEDG0G0G1G1Vertex.cc
--- a/Models/UED/UEDG0G0G1G1Vertex.cc
+++ b/Models/UED/UEDG0G0G1G1Vertex.cc
@@ -1,65 +1,64 @@
// -*- C++ -*-
//
// UEDG0G0G1G1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDG0G0G1G1Vertex class.
//
#include "UEDG0G0G1G1Vertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "UEDBase.h"
using namespace Herwig;
UEDG0G0G1G1Vertex::UEDG0G0G1G1Vertex() :
theq2Last(ZERO), theCoupLast(0.) {
orderInGs(2);
orderInGem(0);
+ colourStructure(ColourStructure::SU3FF);
}
void UEDG0G0G1G1Vertex::doinit() {
long kk1g = 5100021, smgl = 21;
addToList(smgl, smgl, kk1g, kk1g);
VVVVVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<UEDG0G0G1G1Vertex,Helicity::VVVVVertex>
describeUEDG0G0G1G1Vertex("Herwig::UEDG0G0G1G1Vertex", "HwUED.so");
void UEDG0G0G1G1Vertex::Init() {
static ClassDocumentation<UEDG0G0G1G1Vertex> documentation
("This class implements the coupling of a pair of SM gluons to"
"a pair of UED level-1 KK gluons.");
}
void UEDG0G0G1G1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3, tcPDPtr part4) {
int ismg(0), ikkg(0);
- vector<tcPDPtr> particles(4);
- particles[0] = part1; particles[1] = part2;
- particles[2] = part3; particles[3] = part4;
- for(vector<long>::size_type i = 0; i < 4; ++i) {
- if(particles[i]->id() == ParticleID::g) ++ismg;
- if(particles[i]->id() == 5100021) ++ikkg;
+ const array<tcPDPtr, 4> particles{{ part1, part2, part3, part4 }};
+ for(auto p : particles) {
+ if(p->id() == ParticleID::g) ++ismg;
+ if(p->id() == 5100021) ++ikkg;
}
assert(ismg == 2 && ikkg == 2);
if(q2 != theq2Last || theCoupLast == 0. ) {
theq2Last = q2;
theCoupLast = sqr(strongCoupling(q2));
}
norm(theCoupLast);
setType(1);
setOrder(0,1,2,3);
}
diff --git a/Models/UED/UEDG1G1G0Vertex.cc b/Models/UED/UEDG1G1G0Vertex.cc
--- a/Models/UED/UEDG1G1G0Vertex.cc
+++ b/Models/UED/UEDG1G1G0Vertex.cc
@@ -1,65 +1,66 @@
// -*- C++ -*-
//
// UEDG1G1G0Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDG1G1G0Vertex class.
//
#include "UEDG1G1G0Vertex.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDG1G1G0Vertex::UEDG1G1G0Vertex()
: theq2Last(ZERO), theCoupLast(0.) {
orderInGs(1);
orderInGem(0);
+ colourStructure(ColourStructure::SU3F);
}
void UEDG1G1G0Vertex::doinit() {
long kkg1 = 5100021;
addToList(kkg1, kkg1, 21);
VVVVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<UEDG1G1G0Vertex,Helicity::VVVVertex>
describeUEDG1G1G0Vertex("Herwig::UEDG1G1G0Vertex", "HwUED.so");
void UEDG1G1G0Vertex::Init() {
static ClassDocumentation<UEDG1G1G0Vertex> documentation
("The UEDG1G1G0Vertex class implements the coupling of the "
"gluon to two KK excitations of the gluon in the UED model.");
}
void UEDG1G1G0Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long id1(part1->id()), id2(part2->id()), id3(part3->id());
if( (id1 == ParticleID::g && id2 == 5100021 && id3 == 5100021) ||
(id2 == ParticleID::g && id1 == 5100021 && id3 == 5100021) ||
(id3 == ParticleID::g && id1 == 5100021 && id2 == 5100021) ) {
if(q2 != theq2Last || theCoupLast == 0.) {
theq2Last = q2;
theCoupLast = strongCoupling(q2);
}
norm(theCoupLast);
}
else throw HelicityLogicalError()
<< "UEDG1G1G0Vertex::setCoupling - "
<< "There is an unknown particle in this vertex "
<< id1 << " " << id2 << " " << id3 << Exception::runerror;
}
diff --git a/Models/UED/UEDP0H1H1Vertex.cc b/Models/UED/UEDP0H1H1Vertex.cc
--- a/Models/UED/UEDP0H1H1Vertex.cc
+++ b/Models/UED/UEDP0H1H1Vertex.cc
@@ -1,63 +1,64 @@
// -*- C++ -*-
//
// UEDP0H1H1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDP0H1H1Vertex class.
//
#include "UEDP0H1H1Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace Herwig;
using namespace ThePEG::Helicity;
UEDP0H1H1Vertex::UEDP0H1H1Vertex() : theq2Last(ZERO), theCoupLast(0.) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
void UEDP0H1H1Vertex::doinit() {
addToList(22, 5100037, -5100037);
VSSVertex::doinit();
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeNoPIOClass<UEDP0H1H1Vertex,VSSVertex>
describeHerwigUEDP0H1H1Vertex("Herwig::UEDP0H1H1Vertex", "HwUED.so");
void UEDP0H1H1Vertex::Init() {
static ClassDocumentation<UEDP0H1H1Vertex> documentation
("This is the coupling of the SM photon to the level-1 charged higgs.");
}
#ifndef NDEBUG
void UEDP0H1H1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr ) {
#else
void UEDP0H1H1Vertex::setCoupling(Energy2 q2, tcPDPtr , tcPDPtr part2,
tcPDPtr ) {
#endif
assert(part1->id()==ParticleID::gamma);
assert(abs(part2->id()) == 5100037);
if(q2 != theq2Last || theCoupLast == 0.) {
theq2Last = q2;
theCoupLast = electroMagneticCoupling(q2);
}
if(part2->id()>0)
norm(-theCoupLast);
else
norm( theCoupLast);
}
diff --git a/Models/UED/UEDW0A1H1Vertex.cc b/Models/UED/UEDW0A1H1Vertex.cc
--- a/Models/UED/UEDW0A1H1Vertex.cc
+++ b/Models/UED/UEDW0A1H1Vertex.cc
@@ -1,96 +1,97 @@
// -*- C++ -*-
//
// UEDW0A1H1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDW0A1H1Vertex class.
//
#include "UEDW0A1H1Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
void UEDW0A1H1Vertex::doinit() {
addToList( 24, 5100036, -5100037);
addToList(-24, 5100036, 5100037);
VSSVertex::doinit();
tUEDBasePtr UEDBase = dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!UEDBase) throw InitException()
<< "UEDW0A1H1Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!" << Exception::runerror;
theMw2 = sqr(getParticleData(24)->mass());
theMz2 = sqr(getParticleData(23)->mass());
theR2 = sqr(UEDBase->compactRadius());
}
UEDW0A1H1Vertex::UEDW0A1H1Vertex() : theMw2(), theMz2(), theR2(),
theq2Last(), theCoupLast(0.) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
void UEDW0A1H1Vertex::persistentOutput(PersistentOStream & os) const {
os << ounit(theMw2,GeV2) << ounit(theMz2,GeV2) << ounit(theR2,1/GeV2);
}
void UEDW0A1H1Vertex::persistentInput(PersistentIStream & is, int) {
is >> iunit(theMw2,GeV2) >> iunit(theMz2,GeV2) >> iunit(theR2,1/GeV2);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDW0A1H1Vertex,VSSVertex>
describeHerwigUEDW0A1H1Vertex("Herwig::UEDW0A1H1Vertex", "HwUED.so");
void UEDW0A1H1Vertex::Init() {
static ClassDocumentation<UEDW0A1H1Vertex> documentation
("The coupling of a SM W boson to a level-1 charged higgs and the "
"level-1 heavy neutral higgs");
}
void UEDW0A1H1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long chiggs(0);
if(abs(part1->id()) == ParticleID::Wplus)
chiggs = (abs(part2->id()) == 5100037) ? part2->id() : part3->id();
else if(abs(part2->id()) == ParticleID::Wplus)
chiggs = (abs(part1->id()) == 5100037) ? part1->id() : part3->id();
else if(abs(part3->id()) == ParticleID::Wplus)
chiggs = (abs(part1->id()) == 5100037) ? part1->id() : part2->id();
else {
throw HelicityLogicalError() << "UEDW0A1H1Vertex::setCoupling - "
<< "There is no SM W boson in this vertex"
<< Exception::warning;
return;
}
if(abs(chiggs) == 5100037) {
if(q2 != theq2Last || theCoupLast == 0.) {
theq2Last = q2;
theCoupLast = weakCoupling(q2);
double mwRs = theMw2*theR2;
double denom = sqrt( (1 + mwRs)*(1. + theMw2*theR2) );
theCoupLast *= ( 0.5 + mwRs )/denom;
}
if(chiggs > 0) theCoupLast *= -1.;
norm(theCoupLast);
}
else
throw HelicityLogicalError() << "UEDW0A1H1Vertex::setCoupling - "
<< "There is an unknown particle in this "
<< "vertex " << chiggs
<< Exception::runerror;
}
diff --git a/Models/UED/UEDW0W1W1Vertex.cc b/Models/UED/UEDW0W1W1Vertex.cc
--- a/Models/UED/UEDW0W1W1Vertex.cc
+++ b/Models/UED/UEDW0W1W1Vertex.cc
@@ -1,139 +1,140 @@
// -*- C++ -*-
//
// UEDW0W1W1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDW0W1W1Vertex class.
//
#include "UEDW0W1W1Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDW0W1W1Vertex::UEDW0W1W1Vertex() : theSinW(0.), theCosW(0.),
theSinThetaOne(0.), theCosThetaOne(0.),
theq2last(), theElast(0.), theCouplast(0.),
theSMlast(0), theKKlast(0) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
void UEDW0W1W1Vertex::doinit() {
addToList( 22, -5100024, 5100024);
addToList( 23, -5100024, 5100024);
addToList( 24, -5100024, 5100022);
addToList( 24, -5100024, 5100023);
addToList(-24, 5100024, 5100022);
addToList(-24, 5100024, 5100023);
VVVVertex::doinit();
tUEDBasePtr model = dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!model)
throw InitException() << "UEDW0W1W1Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
theSinW = sqrt(sin2ThetaW());
theCosW = sqrt( 1. - sqr(theSinW) );
theSinThetaOne = model->sinThetaOne();
theCosThetaOne = sqrt( 1. - sqr(theSinThetaOne));
}
void UEDW0W1W1Vertex::persistentOutput(PersistentOStream & os) const {
os << theSinW << theCosW << theSinThetaOne << theCosThetaOne;
}
void UEDW0W1W1Vertex::persistentInput(PersistentIStream & is, int) {
is >> theSinW >> theCosW >> theSinThetaOne >> theCosThetaOne;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDW0W1W1Vertex,VVVVertex>
describeHerwigUEDW0W1W1Vertex("Herwig::UEDW0W1W1Vertex", "HwUED.so");
void UEDW0W1W1Vertex::Init() {
static ClassDocumentation<UEDW0W1W1Vertex> documentation
("The coupling of an SM W boson to a level 1 KK W and KK Z and KK photon");
}
/// \todo look again
void UEDW0W1W1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long id1(abs(part1->id())), id2(abs(part2->id())), id3(abs(part3->id())),
smID(0), kkparticle(0);
double perm(1.);
if( id1 == 22 || id1 == 23) {
smID = id1;
kkparticle = id2;
if(part2->id()>0) perm=-1.;
}
else if(id2 == 22 || id2 == 23) {
smID = id2;
kkparticle = id1;
if(part1->id()<0) perm=-1.;
}
else if(id3 == 22 || id3 == 23) {
smID = id3;
kkparticle = id1;
if(part1->id()>0) perm=-1.;
}
else if(id1 == 24 ) {
if( part1->id() == 24 ) perm = -1.;
smID = id1;
kkparticle = (id2 == 5100024) ? id3 : id2;
if(id3 == 5100024) perm *=-1.;
}
else if( id2 == 24 ) {
if( part2->id() == 24 ) perm = -1.;
smID = id2;
kkparticle = (id1 == 5100024) ? id3 : id1;
if(id1 == 5100024) perm *=-1.;
}
else if( id3 == 24 ) {
if( part3->id() == 24 ) perm = -1.;
smID = id3;
kkparticle = (id1 == 5100024) ? id2 : id1;
if(id2 == 5100024) perm *=-1.;
}
else {
throw HelicityLogicalError()
<< "UEDW0W1W1Vertex::setCoupling() - There is no SM gauge boson in "
<< "this vertex. " << id1 << " " << id2 << " " << id3
<< Exception::warning;
norm(0.);
return;
}
if( q2 != theq2last || theElast == 0.) {
theq2last = q2;
theElast = electroMagneticCoupling(q2);
}
if( smID != theSMlast || kkparticle != theKKlast ) {
theSMlast = smID;
theKKlast = kkparticle;
if( smID == 22 )
theCouplast = 1.;
else if(smID == 23)
theCouplast = theCosW/theSinW;
else {
if( kkparticle == 5100023 )
theCouplast = theCosThetaOne/theSinW;
else
theCouplast = theSinThetaOne/theSinW;
}
}
norm(perm*theElast*theCouplast);
}
diff --git a/Models/UED/UEDZ0A1h1Vertex.cc b/Models/UED/UEDZ0A1h1Vertex.cc
--- a/Models/UED/UEDZ0A1h1Vertex.cc
+++ b/Models/UED/UEDZ0A1h1Vertex.cc
@@ -1,100 +1,101 @@
// -*- C++ -*-
//
// UEDZ0A1h1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDZ0A1h1Vertex class.
//
#include "UEDZ0A1h1Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDZ0A1h1Vertex::UEDZ0A1h1Vertex() : theSin2ThetaW(0.), theKappa(0.),
theq2Last(ZERO), theCoupLast(0.) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
void UEDZ0A1h1Vertex::doinit() {
addToList(23, 5100036, 5100025);
VSSVertex::doinit();
tUEDBasePtr UEDBase =
dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!UEDBase)
throw InitException() << "UEDZ0A1h1Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
double sw2 = sin2ThetaW();
theSin2ThetaW = 2.*sqrt(sw2*(1. - sw2));
Energy2 mz2 = sqr(getParticleData(23)->mass());
InvEnergy2 rad2 = sqr(UEDBase->compactRadius());
theKappa = 1./sqrt(1. + mz2*rad2);
}
void UEDZ0A1h1Vertex::persistentOutput(PersistentOStream & os) const {
os << theSin2ThetaW << theKappa;
}
void UEDZ0A1h1Vertex::persistentInput(PersistentIStream & is, int) {
is >> theSin2ThetaW >> theKappa;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDZ0A1h1Vertex,VSSVertex>
describeHerwigUEDZ0A1h1Vertex("Herwig::UEDZ0A1h1Vertex", "HwUED.so");
void UEDZ0A1h1Vertex::Init() {
static ClassDocumentation<UEDZ0A1h1Vertex> documentation
("The coupling of an SM Z boson to a level-1 CP-Odd pseudo-scalar "
"and level 1 higgs.");
}
void UEDZ0A1h1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long scaA(0), scaB(0);
if(part1->id() == ParticleID::Z0) {
scaA = part2->id();
scaB = part3->id();
}
else if(part2->id() == ParticleID::Z0) {
scaA = part1->id();
scaB = part3->id();
}
else if(part3->id() == ParticleID::Z0) {
scaA = part1->id();
scaB = part2->id();
}
else {
throw HelicityLogicalError() << "UEDZ0A1h1Vertex::setCoupling - "
<< "There is no SM Z boson in this vertex"
<< Exception::warning;
}
if( (scaA == 5100036 && scaB == 5100025) ||
(scaB == 5100036 && scaA == 5100025) ) {
if(q2 != theq2Last || theCoupLast == 0.) {
theq2Last = q2;
theCoupLast = theKappa*electroMagneticCoupling(q2)/theSin2ThetaW;
}
norm(theCoupLast);
}
else
throw HelicityLogicalError() << "UEDZ0A1h1Vertex::setCoupling - "
<< "There is an unknown particle in this "
<< "vertex. " << scaA << " " << scaB
<< Exception::warning;
}
diff --git a/Models/UED/UEDZ0H1H1Vertex.cc b/Models/UED/UEDZ0H1H1Vertex.cc
--- a/Models/UED/UEDZ0H1H1Vertex.cc
+++ b/Models/UED/UEDZ0H1H1Vertex.cc
@@ -1,95 +1,96 @@
// -*- C++ -*-
//
// UEDZ0H1H1Vertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the UEDZ0H1H1Vertex class.
//
#include "UEDZ0H1H1Vertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/PDT/EnumParticles.h"
using namespace ThePEG::Helicity;
using namespace Herwig;
UEDZ0H1H1Vertex::UEDZ0H1H1Vertex() : theCosThetaW(0.), theCosTheta2W(0.), theMw2(),
theR2(), theq2Last(ZERO), theCoupLast(0.) {
orderInGs(0);
orderInGem(1);
+ colourStructure(ColourStructure::SINGLET);
}
void UEDZ0H1H1Vertex::doinit() {
addToList(23, 5100037, -5100037);
VSSVertex::doinit();
tUEDBasePtr theUEDBase = dynamic_ptr_cast<tUEDBasePtr>(generator()->standardModel());
if(!theUEDBase)
throw InitException() << "UEDZ0H1H1Vertex::doinit() - The pointer to "
<< "the UEDBase object is null!"
<< Exception::runerror;
theCosThetaW = sqrt(1. - sin2ThetaW());
theCosTheta2W = 1. - 2.*sin2ThetaW();
theMw2 = sqr(getParticleData(24)->mass());
theR2 = sqr(theUEDBase->compactRadius());
}
void UEDZ0H1H1Vertex::persistentOutput(PersistentOStream & os) const {
os << theCosThetaW << theCosTheta2W
<< ounit(theMw2,GeV2) << ounit(theR2,1/GeV2);
}
void UEDZ0H1H1Vertex::persistentInput(PersistentIStream & is, int) {
is >> theCosThetaW >> theCosTheta2W
>> iunit(theMw2,GeV2) >> iunit(theR2,1/GeV2);
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<UEDZ0H1H1Vertex,VSSVertex>
describeHerwigUEDZ0H1H1Vertex("Herwig::UEDZ0H1H1Vertex", "HwUED.so");
void UEDZ0H1H1Vertex::Init() {
static ClassDocumentation<UEDZ0H1H1Vertex> documentation
("This is the coupling of the SM Z boson to the level-1 charged higgs.");
}
void UEDZ0H1H1Vertex::setCoupling(Energy2 q2, tcPDPtr part1, tcPDPtr part2,
tcPDPtr part3) {
long kkhiggs(0);
if(part1->id() == ParticleID::Z0)
kkhiggs = abs(part2->id());
else if(part2->id() == ParticleID::Z0)
kkhiggs = abs(part1->id());
else if(part3->id() == ParticleID::Z0)
kkhiggs = abs(part1->id());
else {
throw HelicityLogicalError() << "UEDZ0H1H1Vertex::setCoupling - There is no "
<< "SM photon in this vertex!."
<< Exception::warning;
return;
}
if(kkhiggs == 5100037) {
if(q2 != theq2Last || theCoupLast == 0.) {
theq2Last = q2;
theCoupLast =
Complex(0., 1.)*weakCoupling(q2);
theCoupLast *= ( (theCosTheta2W/2./theCosThetaW)
- sqr(theCosThetaW)*theMw2*theR2 )/(1. + theMw2*theR2);
}
norm(theCoupLast);
}
else
throw HelicityLogicalError() << "UEDZ0H1H1Vertex::setCoupling - There is no "
<< "level-1 higgs in this vertex! " << kkhiggs
<< Exception::warning;
}
diff --git a/Models/Zprime/ZprimeModelZPQQVertex.cc b/Models/Zprime/ZprimeModelZPQQVertex.cc
--- a/Models/Zprime/ZprimeModelZPQQVertex.cc
+++ b/Models/Zprime/ZprimeModelZPQQVertex.cc
@@ -1,186 +1,187 @@
// -*- C++ -*-
//
// ZprimeModelZPQQVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ZprimeModelZPQQVertex class.
//
#include "ZprimeModelZPQQVertex.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Config/Constants.h"
using namespace Herwig;
IBPtr ZprimeModelZPQQVertex::clone() const {
return new_ptr(*this);
}
IBPtr ZprimeModelZPQQVertex::fullclone() const {
return new_ptr(*this);
}
ZprimeModelZPQQVertex::ZprimeModelZPQQVertex() {
addToList(-2,6,32);
addToList(-6,2,32);
addToList(-6,6,32);
addToList(-5,5,32);
addToList(-4,4,32);
addToList(-3,3,32);
addToList(-2,2,32);
addToList(-1,1,32);
addToList(-11,11,32);
addToList(-13,13,32);
addToList(-15,15,32);
addToList(-12,12,32);
addToList(-14,14,32);
addToList(-16,16,32);
orderInGem(1);
orderInGs(0);
+ colourStructure(ColourStructure::SU3F);
}
void ZprimeModelZPQQVertex::doinit() {
_theModel = generator()->standardModel();
tcHwZprimePtr hwZprime=dynamic_ptr_cast<tcHwZprimePtr>(_theModel);
if(hwZprime) {
_cZPTU_R =hwZprime->_cZPTU_right();
_cZPTU_L =hwZprime->_cZPTU_left();
_cZPTT_R =hwZprime->_cZPTT_right();
_cZPTT_L =hwZprime->_cZPTT_left();
_cZPUU_R =hwZprime->_cZPUU_right();
_cZPUU_L =hwZprime->_cZPUU_left();
_cZPCC_R =hwZprime->_cZPCC_right();
_cZPCC_L =hwZprime->_cZPCC_left();
_cZPDD_R =hwZprime->_cZPDD_right();
_cZPDD_L =hwZprime->_cZPDD_left();
_cZPBB_R =hwZprime->_cZPBB_right();
_cZPBB_L =hwZprime->_cZPBB_left();
_cZPSS_R =hwZprime->_cZPSS_right();
_cZPSS_L =hwZprime->_cZPSS_left();
_cZPee_R =hwZprime->_cZPee_right();
_cZPee_L =hwZprime->_cZPee_left();
_cZPmm_R =hwZprime->_cZPmm_right();
_cZPmm_L =hwZprime->_cZPmm_left();
_cZPtt_R =hwZprime->_cZPtt_right();
_cZPtt_L =hwZprime->_cZPtt_left();
_cZPnuenue_R =hwZprime->_cZPnuenue_right();
_cZPnuenue_L =hwZprime->_cZPnuenue_left();
_cZPnuenue_R =hwZprime->_cZPnumnum_right();
_cZPnumnum_L =hwZprime->_cZPnumnum_left();
_cZPnutnut_R =hwZprime->_cZPnutnut_right();
_cZPnutnut_L =hwZprime->_cZPnutnut_left();
_cZP_o =hwZprime->_cZPoverallCoup();
}
FFVVertex::doinit();
}
void ZprimeModelZPQQVertex::persistentOutput(PersistentOStream & os) const {
os << _cZPTU_R << _cZPTU_L << _cZPTT_R << _cZPTT_L << _cZPUU_R << _cZPUU_L << _cZPCC_R << _cZPCC_L << _cZPDD_R << _cZPDD_L << _cZPSS_R << _cZPSS_L << _cZPBB_R << _cZPBB_L << _cZPee_R << _cZPee_L << _cZPmm_R << _cZPmm_L << _cZPtt_R << _cZPtt_L << _cZPnuenue_R << _cZPnuenue_L << _cZPnumnum_R << _cZPnumnum_L << _cZPnutnut_R << _cZPnutnut_L << _cZP_o;
}
void ZprimeModelZPQQVertex::persistentInput(PersistentIStream & is, int) {
is >> _cZPTU_R >> _cZPTU_L >> _cZPTT_R >> _cZPTT_L >> _cZPUU_R >> _cZPUU_L >> _cZPCC_R >> _cZPCC_L >> _cZPDD_R >> _cZPDD_L >> _cZPSS_R >> _cZPSS_L >> _cZPBB_R >> _cZPBB_L >> _cZPee_R >> _cZPee_L >> _cZPmm_R >> _cZPmm_L >> _cZPtt_R >> _cZPtt_L >> _cZPnuenue_R >> _cZPnuenue_L >> _cZPnumnum_R >> _cZPnumnum_L >> _cZPnutnut_R >> _cZPnutnut_L >> _cZP_o;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<ZprimeModelZPQQVertex,FFVVertex>
describeHerwigZprimeModelZPQQVertex("Herwig::ZprimeModelZPQQVertex", "Herwig.so");
void ZprimeModelZPQQVertex::Init() {
static ClassDocumentation<ZprimeModelZPQQVertex> documentation
("The ZprimeModelZPQQVertex class is the implementation"
" of the helicity amplitude calculation of the Zprime"
" Z prime Quark-antiQuark vertex.");
}
void ZprimeModelZPQQVertex::setCoupling(Energy2,tcPDPtr aa ,tcPDPtr bb, tcPDPtr cc) {
double _cR = 1.0, _cL = 1.0;
long ccc(cc->id()), aaa(aa->id()), bbb(bb->id());
if( abs(aaa) == 6 || abs(bbb) == 6 || abs(ccc) == 6 ) {
if( abs(aaa) !=2 && abs(bbb) !=2 && abs(ccc) != 2 ) {
_cL = _cZPTT_L; _cR = _cZPTT_R;
} else if( abs(aaa) ==2 || abs(bbb) ==2 || abs(ccc) == 2 ) {
_cL = _cZPTU_L; _cR = _cZPTU_R;
}
}
if( abs(aaa) == 5 || abs(bbb) == 5 || abs(ccc) == 5 ) {
_cL = _cZPBB_L; _cR = _cZPBB_R;
}
if( abs(aaa) == 4 || abs(bbb) == 4 || abs(ccc) == 4 ) {
_cL = _cZPCC_L; _cR = _cZPCC_R;
}
if( abs(aaa) == 3 || abs(bbb) == 3 || abs(ccc) == 3 ) {
_cL = _cZPSS_L; _cR = _cZPSS_R;
}
if( (abs(aaa) == 2 || abs(bbb) == 2 || abs(ccc) == 2) && (abs(aaa) !=6 && abs(bbb) !=6 && abs(ccc) != 6)) {
_cL = _cZPUU_L; _cR = _cZPUU_R;
}
if( abs(aaa) == 1 || abs(bbb) == 1 || abs(ccc) == 1 ) {
_cL = _cZPDD_L; _cR = _cZPDD_R;
}
if( abs(aaa) == 11 || abs(bbb) == 11 || abs(ccc) == 11 ) {
_cL = _cZPee_L; _cR = _cZPee_R;
}
if( abs(aaa) == 13 || abs(bbb) == 13 || abs(ccc) == 13 ) {
_cL = _cZPmm_L; _cR = _cZPmm_R;
}
if( abs(aaa) == 15 || abs(bbb) == 15 || abs(ccc) == 15 ) {
_cL = _cZPtt_L; _cR = _cZPtt_R;
}
if( abs(aaa) == 12 || abs(bbb) == 12 || abs(ccc) == 12 ) {
_cL = _cZPnuenue_L; _cR = _cZPnuenue_R;
}
if( abs(aaa) == 14 || abs(bbb) == 14 || abs(ccc) == 14 ) {
_cL = _cZPnumnum_L; _cR = _cZPnumnum_R;
}
if( abs(aaa) == 16 || abs(bbb) == 16 || abs(ccc) == 16 ) {
_cL = _cZPnutnut_L; _cR = _cZPnutnut_R;
}
right(_cR);
left(_cL);
norm(_cZP_o);
}
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -1,1667 +1,1689 @@
Herwig News -*- outline -*-
================================================================================
+* Herwig 7.1.3 release: 2018-04-05
+
+** Dipole Shower
+*** Changed default phase space limits
+*** g -> gg splitting function asymmetrized
+*** Initial retune supplied, given the visible changes
+ to LEP observables
+
+** Added new Baryonic colour reconnection model
+ (arXiv 1710:10906)
+
+** Added Schuler-Sjostrand Photon PDFs
+
+** Handling of massless taus from external sources
+
+** various minor fixes
+
+** use std::array<> where possible
+
+
+
* Herwig 7.1.2 release: 2017-11-01
** Reduction of the default pt cut for QED radiation off leptons.
** Inputfile changes due to new read mode in ThePEG.
ThePEG remains in current repo dir when reading input-file/snippet.
** Fix for shower scale variations in qtilde shower.
** All standard input files now use the tuned intrinsic pt.
** Remove obsolete input files for various tunes.
** Fix for Madgraph interface for NLO corrections with recent version.
** Run file size reduction for processes using madgraph/openloops.
** Fix in jacobian for massive dipole kinematics.
** General improvements for UFO model handling.
+
* Herwig 7.1.1 release: 2017-07-14
** Snippets are now all installed
** Fixed broken ufo2herwig output and LHC-MB.in
** UFO improvements
*** More robust SLHA file handling
*** option of creating diagonal mixing matrices, needed for ATLAS simplfied models
*** Improved warnings about resetting standard model particles
*** Fixed certain cases where the wrong lorentz structure was picked in VVS vertices
** Improved error message for unhandled beam particles
** Fix for Dipole Shower chain selection
** Fixed crash in double diffractive delta resonances
* Herwig 7.1.0 release: 2017-05-19
** Major new release
For a more detailed overview and further references please see the
release note arXiv:1705.06919
** NLO multijet merging with the dipole shower
** A new soft model
** An interface to EvtGen
** Improved calculation of mass effects in the dipole shower
** Top decays in the dipole shower, and NLO corrections to the decay
** An implementation of the KrkNLO method for simple processes
** Major restructuring and cleanup of default input files
** C++11 is now mandatory and heavily used in the code
** Many smaller bugfixes and improvements
* Herwig 7.0.4 release: 2016-10-24
** API
The high level API is now properly available as a library, providing an
alternative to the Herwig main program.
** Dipole shower
Added nloops() function to the AlphaS classes to return the number of loops
in the running coupling
** Matchbox
Improved error handling and clearer messages
** BSM models
Initialize W mass correctly from SLHA file. Improved reading in of decay
modes if they already exist.
** Sampling
Introduced option to reduce reference weight in AlmostUnweighted mode by
Kappa factor. Useful for processes where full unweighting is infeasible.
** Qtilde shower
Better control of scale in splitting functions using the
SplittingFunction:ScaleChoice interface.
** Tests
New NLO fixed-order input files for testing Matchbox in Tests/ExternNLO.
** Input files
Set diagonal CKM options consistently. Added TauTauHVertex and MuMuHVertex
to MatchboxDefaults.
* Herwig 7.0.3 release: 2016-07-21
** subprocess generation filters
A number of filters has been implemented to speed up process and diagram
generation for the case of Standard Model like processes; this is
particularly helpful for processes involving a large number of electroweak
combinatorics. See the documentation for more details.
** fix to directory hierarchy
A bug in the Herwig-scratch directory hierarchy when integrating with
different seeds has been fixed.
** fix for relocating MadGraph generated amplitudes
The directory and symbolic link structure for MadGraph-built amplitudes has
been changed to allow for relocation of a run directory to a different file
system hierarchy.
** z* variable added to LeptonsJetsAnalysis
The builtin LeptonsJetsAnalysis has been extented to include the normalized
relative rapidity z*
** detuning parameter for shower reweighting
An efficiency tweak when using the shower reweighting facilities has been
introduced for the veto algorithms in both the QTilde and the Dipole
shower. See the documentation for more details.
** BaryonThreeQuarkModelFormFactor
A scaling bug in the form factor series expansion was fixed.
* Herwig 7.0.2 release: 2016-04-29
** Event reweighting
New option of calculating the weights for the effect of varying the scale
used in both the default and dipole showers. The method is described in
arXiv:1605.08256
** mergegrids mode
A main mode for the Herwig executable has been added which merges the
integration grids from parallel runs.
** NLO Diphoton production
The NLO matrix elements in the POWHEG approach for diphoton production as
described in JHEP 1202 (2012) 130, arXiv:1106.3939 have been included as
MEPP2GammaGammaPowheg.
** BSM Hard process constructor
A missing Feynman diagram with a t-channel vector boson has been added to
the matrix element for vv2ss
** BSM Decay Modes calculation
The behaviour of the option to disable decay modes in BSM Models has been
changed so that the partial width for the ignored modes is now calculated
and included in the total width, but the branching ratio is set to
zero. This is more physical than the previous option where the mode was
t otally ignored and hence not included in the calculation of the width.
** Mass Generation
The behaviour of the GenericMassGenerator has been changed so that modes
which have been disabled are only included in the calculation of the total
width and not in the partial width used in the numerator of the weight used
to select the off-shell mass.
** Boost detection
Boost could not detect the compiler version for gcc-5.3 and gcc-6.1
* Herwig 7.0.1 release: 2016-01-17
** Version number written to log file
The Herwig version number is now included in addition to ThePEG's version.
** Tau lifetimes
A bug with lifetimes for hard process Taus is fixed. Thanks to ATLAS
for the report!
** Shower FSR retries
Rare events could take a long time due to an extremely large number
of FSR retries. These are now capped at a configurable number.
** Dipole shower
Reweighting for non-radiating events; fixes for shower profile
handling; option to downgrade large-Q expansion for alphaS
** Matchbox builtins
Added massive currents for q-qbar
** ShowerAlphaQCD
can now use user-defined thresholds
** Input snippets
W/Z/H on-shell now split into three files; 4-flavour scheme added
** UFO converter
The converter now has experimental support for writing out param
cards of its current settings.
** LEPJetAnalysis loading fixed
** Contrib
HJets++ has moved to a stand-alone project, FxFx has been added
* Herwig 7.0.0 (Herwig++ 3.0.0) release: 2015-12-04
** Major new release
A major new release of the Monte Carlo event generator Herwig++ (version
3.0) is now available. This release marks the end of distinguishing
Herwig++ and HERWIG development and therefore constitutes the first major
release of version 7 of the Herwig event generator family. The new version
features a number of significant improvements to the event simulation,
including: built-in NLO hard process calculation for all Standard Model
processes, with matching to both angular ordered and dipole shower modules
via variants of both subtractive (MC@NLO-type) and multiplicative
(Powheg-type) algorithms; QED radiation and spin correlations in the
angular ordered shower; a consistent treatment of perturbative
uncertainties within the hard process and parton showering, as well as a
vastly improved documentation. This version includes (for a more detailed
overview and further references please see the release note
arXiv:1512.01178):
** A long list of improvements and fixes for the Matchbox module
*** includes MC@NLO and Powheg matching to both showers with truncated showering
** A long list of improvements and fixes for both of the shower modules
*** includes improvements of numerics issues relevant to 100 TeV pp collisions
** NLO event simulation and Matchbox development
*** Interfaces to a number of external libraries
*** A new workflow for event generation
*** Electroweak corrections to VV production
** Parton shower development
*** QED radiation in the angular ordered shower
*** Spin correlations in the angular ordered shower
*** New scale choices in gluon branchings
** Improvements to event generation workflow
*** Re-organized and streamlined input files for the new NLO development
*** A unified treatment of shower and matching uncertainties
*** New integrator modules featuring parallel integration
** New default tunes for both shower modules
** New contrib modules
*** Electroweak Higgs plus jets production
*** FxFx merging support
*** Higgs boson pair production
* Herwig++-2.7.1 release: 2014-07-07
** New shower switches to select schemes for momentum reconstruction
*** QTildeReconstructor:FinalStateReconOption
has the following options:
*** Default
All momenta are rescaled in the rest frame.
*** MostOffShell
Put all particles on the new-mass shell and the most off-shell and
recoiling system are rescaled to ensure 4-momentum is conserved.
*** Recursive
Recursively put the most off-shell particle which hasn't yet been
rescaled on-shell by rescaling the particles and the recoiling
system.
*** RestMostOffShell
The most off-shell is put on shell by rescaling it and the
recoiling system, the recoiling system is then put on-shell in its
rest frame.
*** RestRecursive
As above, but recursively treat the currently most-off shell
(only makes a difference for more than 3 partons)
** Ticket #378: Hadronization of baryon number violating clusters involving diquarks
Fixed by only considering non-diquarks to be combined in the
ClusterFinder.
** UFO converter can now parse SLHA files for parameter settings
The UFO converter code can now use SLHA files for modifying
parameters. The first pass "ufo2herwig" produces the model to be
compiled. For each parameter card, run "slha2herwig" to get the
matching input file.
** Fix for systems using lib64
The repository is now initialized correctly on systems using lib64
as the library location.
** Efficiency optimization
Better allocation of internal vector variables for a noticeable
speed increase of 10-20% with LHC events.
* Herwig++-2.7.0 release: 2013-10-28
** UFO interface to Feynman rules generators
Herwig++ now includes "ufo2herwig", a tool that automatically
creates all required files to run a BSM model from a UFO
directory. The conversion has been extensively tested against
Feynrules models MSSM, NMSSM, RS, Technicolor,
and less extensively with most of the
other models in the Feynrules model database.
We expect that following this release there will be no further
hard-coded new physics models added to Herwig++ and that future
models will be included using the UFO interface.
** Shower uncertainties
A first set of scaling parameters to estimate shower uncertainties
is provided for both the angular ordered as well as the dipole
shower; they are Evolver:HardScaleFactor and ShowerAlphaQCD:
RenormalizationScaleFactor.
** Rewrite of Matchbox NLO matching
The NLO matching implementation has been rewritten and is now more
flexible and consistent. Profile scales are provided for the
hardest emission both for the dipole shower and matrix element
correction matching.
** BLHA2 Interface and new processes
Matchbox now features a generic BLHA2 interface to one-loop
amplitude codes and now also includes W and W+jet production as
well as Higss production in gluon fusion as builtin processes.
** Impoved dipole shower kinematics parametrization
The kinematics parametrization for emissions in the dipole shower
has been made more efficient.
** W and Z Powheg decays
Decays of W and Z bosons now use the Powheg decayers by default.
** Improved treatment of beam remnants
The handling of beam remnants has been improved in multiple
contexts, leading to a much lower error rate at p+/p- collisions.
An additional value "VeryHard" for ClusterFissioner:RemnantOption
can be used to disable any special treatment of beam remnant
clusters.
** New underlying event tune
Herwig++ now uses tune UE-EE-5-MRST by default. Other related tunes
can be obtained from the Herwig++ tunes page
** Improvements in BSM code
The UFO development identified many sign fixes in rarely used BSM
vertices; many improvements were made to general decayers, allowing
four-body decays in BSM for the first time; Powheg is enabled in
General two-body decayers; and the handling of colour
sextets has been improved.
** A new HiggsPair matrix element in Contrib.
** A new matrix element for single top production.
** The Higgs mass is now set to 125.9 GeV (from PDG 2013 update).
** C++-11 testing
To help with the coming transition to C++-11, we provide the new
--enable-stdcxx11 configure flag. Please try to test builds with
this flag enabled and let us know any problems, but do not use this
in production code yet. In future releases, this flag will be on by
default.
** Other changes
*** Many new Rivet analyses have been included in the Tests directory.
*** Cleaned Shower header structure; grouped shower parameters into one struct.
*** The boolean Powheg flag in HwMEBase changed to an enumeration.
* Herwig++-2.6.3 release: 2013-02-22
** Decay vertex positioning in HepMC output
Pseudo-vertices that Herwig++ inserts for technical reasons will
now not contribute to the Lorentz positions of downstream vertices.
Thanks to ATLAS for the bug report!
** Updated Rivet tests
Herwig's library of Rivet test runs has been brought up-to-date
with new analyses that were recently published by the Rivet
collaboration.
* Herwig++-2.6.2 release: 2013-01-30
** Fixes for PDF and scale choices in POWHEG events
Scale settings for MPI and the regular shower are now correct in
POWHEG events. This should fix reported anomalies in POWHEG jet rates.
NLO PDFs are now also set consistently in the example input files.
** Ticket #373: Branching ratio factors in cross-section
If any decay modes are selectively disabled, setting the following
post-handler will cause all reported cross-sections to include the
branching ratio factor(s) from the previous stages correctly:
create Herwig::BranchingRatioReweighter BRreweight
insert LHCGenerator:EventHandler:PostDecayHandlers 0 BRreweight
** Anomalous vertices now possible in MEfftoVH
** Interactive shell does not quit on error
** Better warning messages for events from inconsistent LHEF files
** Possible division by zero error fixed in BSM branching ratio calculations
** Decayer and ME changes to improve checkpointing
The checkpointing changes in ThePEG 1.8.2 are implemented here, too. Regular
dump files are consistent now.
* Herwig++-2.6.1 release: 2012-10-16
** Configure switches
The various switches to turn off compilation of BSM models have
been unified into a single '--disable-models'. A new flag
'--disable-dipole' can be used to turn off the compilation of the
Dipole and Matchbox codes.
** Ticket #348: Search path for repository 'read' command
The search path for the 'read' command is configurable on the
command line with the -i and -I switches. By default, the
installation location is now included in the search path, so that
'Herwig++ read LEP.in' will work in an empty directory. The current
working directory will always be searched first.
The rarely used "Herwig++ init" command has been made consistent
with 'read' and 'run' and should now be used without the '-i' flag.
** Width treatment in BSM
The width treatment in BSM decay chains has been greatly improved
and is now switched on by default in the .model files. To get the
old behaviour, use
set /Herwig/NewPhysics/NewModel:WhichOffshell Selected
** New BSM models
Little Higgs models with and without T-parity are now available.
** Resonance photon lifetime
A lifetime bug affecting decays of pi0 to e+e-X was fixed. The
virtual photon is not part of the event record anymore.
** Ticket #371: Hard diffraction FPE
Herwig++ 2.6.0 introduced a bug into the diffraction code which
would abort any runs. This is now fixed.
** O2AlphaS
Support for setting quark masses different from the particle data
objects as introduced in ThePEG 1.8.1 has been enabled.
** Matchbox
Several improvements and bug fixes are included for
Matchbox. Amplitudes relevant to pp -> Z+jet and crossed processes
at NLO are now available, and various scale choices have been added
in a more flexible way. All subtraction dipoles for massive quarks
are now included.
** Dipole shower
Parameters to perform scale variations in the shower have been
added to estimate uncertainties. A bug in showering off gg -> h has
been fixed.
** Minor fixes
*** Two broken colour structures in GeneralHardME
*** Susy Higgs mixing matrix
*** BaryonFactorizedDecayer out-of-bounds access
*** Mass values in SimpleLHCAnalysis
* Herwig++-2.6.0 release: 2012-05-21 (tagged at SVN r7407)
** New NLO framework
Matchbox, a flexible and very general framework for performing NLO
calculations at fixed order or matched to parton showers is
provided with this release.
** Dipole shower algorithm
A first implementation of the coherent dipole shower algorithm by
Plätzer and Gieseke (arXiv:0909.5593 and arXiv:1109.6256) is
available.
** Alternative samplers and the ExSample library
The ExSample library by Plätzer (arXiv:1108.6182) is shipped along
with Herwig++ in an extended version. The extended version provides
SamplerBase objects which can be used alternatively to the default
ACDCSampler.
** New BSM models
*** New colour sextet diquark model
A colour sextet diquark model has been included, as described in
Richardson and Winn (arXiv:1108.6154).
*** Models reproducing the CDF t-tbar asymmetry
Four models that can reproduce the reported t-tbar asymmetry have
been included.
*** Zprime
A simple standard model extension by one additional heavy neutral
vector boson.
** Interface to AlpGen, with MLM merging
The Contrib directory contains a new interface to the AlpGen matrix
element generator. AlpGen events must be preprocessed with the
provided AlpGenToLH.exe tool before they can be used. More
information can be found in the Herwig++ 2.6 release note.
** HiggsVBF Powheg
Higgs boson production by vector boson fusion is available at NLO
in the POWHEG scheme, as described in d'Errico, Richardson
(arXiv:1106.2983). The Powheg DIS processes were available in
Herwig++-2.5.2 already.
** Statistical colour reconnection
Alternative mechanisms to minimize the colour length Sum(m_clu)
before the hadronization stage, based on Metropolis and annealing
algorithms.
** Energy extrapolation of underlying-event tunes
To describe underlying-event data at different c.m. energies, the
energy-dependent parameter pT_min will now be adjusted
automatically, following a power-law. The new tune parameters are
the value at 7000 GeV "MPIHandler:pTmin0", and MPIHandler:Power.
** Ticket #239: Reporting of minimum-bias cross-section
When simulating minimum-bias events using the MEMinBias matrix
element, the correct unitarized cross section can now be reported
via the standard facilities; it is no longer necessary to extract
it from the .log file of the run. The corresponding functionality
is enabled by inserting a MPIXSecReweighter object as a
post-subprocess handler:
create Herwig::MPIXSecReweighter MPIXSecReweighter
insert LHCHandler:PostSubProcessHandlers 0 MPIXSecReweighter
** Dependency on 'boost'
Herwig++ now requires the boost headers to build; if not detected
in standard locations, specify with the --with-boost configure
option.
** Tests directory
The Tests directory now contains input cards for almost all Rivet
analyses. A full comparison run can be initiated with 'make tests'.
** Minor changes
*** Default LHC energy now 8 TeV
All LHC-based defaults have now been updated to use 8 TeV as the
center-of-mass energy.
*** Herwig::ExtraParticleID -> ThePEG::ParticleID
The namespace for additional particles has been unified into
ThePEG::ParticleID
*** MEee2VectorMeson
The e+e- -> vector meson matrix element has moved from Contrib into
HwMELepton.so
*** SUSY numerics fixes
Better handling of rare numerical instabilities.
*** YODA output for Rivet
The built-in histogramming handler can now output data in the YODA
format used by Rivet.
*** Consistency checks in SLHA file reader
Better warnings for inconsistent SusyLHA files
*** better colour flow checking for development
** Bug fixes
*** Extremely offshell W from top decay
Numerical improvements for very off-shell W bosons coming from top
decays.
*** Ticket #367: problems in using SUSY + LHE
Susy events from Les Houches event files are now handled better.
*** Infinite loop in remnant decayer
The remnant decayer will now abort after 100 tries.
*** Fix to HiggsVBF LO diagrams
The diagram structure of HiggsVBF LO matrix elements has been fixed.
*** LEP thrust fix
The calculation of the transverse momentum of a branching from the
evolution variable in final-state radiation can now be
changed. While formally a sub-leading choice this enables a better
description of the thrust distribution in e+e- collisions at
small values of the thrust. Currently the default behaviour, where
the cut-off masses are used in the calculation, remains the same
as previous versions.
* Herwig++-2.5.2 release: 2011-11-01 (tagged at SVN r6928)
** Optional new jet vetoing model
The jet vetoing model by Schofield and Seymour (arXiv:1103.4811) is
available via Evolver:ColourEvolutionMethod,
PartnerFinder:PartnerMethod and SplittingFunction:SplittingColourMethod.
The default behaviour is unchanged.
** MPI tune
Version 3 of the MPI tunes is now the default. Please note that the
pT parameter is energy-dependent and needs to be modified when an
LHC run is not at 7 TeV.
The latest tunes are always available at
http://projects.hepforge.org/herwig/trac/wiki/MB_UE_tunes
** MPI PDFs
MPI PDFs can now be controlled independently.
** Initialization time speedup
A new BSMModel base class was introduced between StandardModel and
the BSM model classes. Together with a restructured decay mode
initialization, this offers significantly faster startup times for
BSM runs. ThreeBodyDecays can now always be switched on without a
large speed penalty.
** Decay mode file
Decay mode files in the SLHA format can now be read separately in
any BSM model with 'set Model:DecayFileName filename'
** Powheg DIS
Charged- and neutral-current DIS processes implementing the POWHEG
method are now available.
** Diffraction models
Xi cut implemented in PomeronFlux
** Ticket #352: Colour reconnection fixed in DIS
** Ticket #353: Improved numerical stability in chargino decays
** Ticket #358: Infinite loop in top events with pT cut in shower
** Ticket #361: Problem with duplicate 2-body modes in BSM
** Tickets #362 / #363: Crashes with baryon number violating models
Particle decays in SUSY models with RPV now work correctly in the
colour 8 -> 3,3,3 case. Colour reshuffling now works for RPV
clusters.
** Improved Fastjet detection
The configure step uses fastjet-config to make sure all header file
paths are seen.
** Darwin 11 / OS X Lion
A configure bug was fixed which prevented 'make check' from
succeeding on OS X Lion.
** Vertex classes
The specification of QED / QCD orders has been moved to the vertex
constructors, to allow ThePEG consistency checks. WWHH vertices in
MSSM and NMSSM were fixed. Some Leptoquark and UED vertices fixed.
** Hadronization
Cleanup of obsolete code.
* Herwig++-2.5.1 release: 2011-06-24 (tagged at SVN r6609)
** Example input files at 7 TeV
All our example input files for LHC now have their beam energy set
to 7 TeV instead of 14 TeV.
** Colour reconnection on by default
The colour reconnection tunes are now the default setup. Version 2
of the tunes replaces the *-1 tunes, which had a problem with LEP
event shapes.
** Run name tags
Aded possibility to add a tag to the run name when running with the
'-t' option. One run file can thus be run with different seeds and
results stored in different output files.
** Floating point exceptions
The new command line option -D enables floating point error checking.
** General improvements to WeakCurrent decays
** Remnant decayer
Hardwired gluon mass was removed.
** WeakCurrentDecayConstructor
Instead of specifying separate Particle1...Particle5 vectors for
the decay modes, the new interface DecayModes can be filled with
decay tags in the standard syntax.
** BSM: improvements to handling of vertex and model initialisation
** Powheg Higgs
Option to use pT or mT as the scale in alphaS and for the
factorization scale in the PDFs
** Ticket #337: Tau polarization wrong in charged Higgs decay
** Ticket #339: Colour flows in GeneralThreeBody Decayers for 3bar -> 8 3bar 1
** Ticket #340: Crash for resonant zero-width particles
** Ticket #341: Varying scale for BSM processes
The scale used is now ResonantProcessConstructor:ScaleFactor or
TwoToTwoProcessConstructor:ScaleFactor multiplied by sHat.
** Ticket #346: Chargino decays
Chargino decayers now automatically switch between the mesonic
decays for mass differences less than 2 GeV and the normal partonic
decays above 2 GeV.
** Ticket #349: Stop by default on input file errors
The '--exitonerror' flag is now the default behaviour for the
Herwig++ binary. To switch back to the old behaviour,
'--noexitonerror' is required.
** Ticket #351: Four-body stop decays
** Tested with gcc-4.6
* Herwig++-2.5.0 release: 2011-02-08 (tagged at SVN r6274)
** Uses ThePEG-1.7.0
Herwig++ 2.5.0 requires ThePEG 1.7.0 to benefit from various
improvements, particularly: handling of diffractive processes;
respecting LD_LIBRARY_PATH when loading dynamic libraries,
including LHAPDF; improvements to repository commands for decay
modes. See ThePEG's NEWS file for more details.
** POWHEG improvements
*** New POWHEG processes
Simulation at NLO accuracy using the POWHEG method is now
available for hadronic diboson production (pp to WW,WZ,ZZ), Higgs
decays to heavy quarks, and e+e- to two jets or ttbar, including
full mass dependence.
*** Input file changes
The input files for setting up POWHEG process simulation have been
simplified. See the example files LHC-Powheg.in and TVT-Powheg.in
for the improved command list.
*** Structural changes
The POWHEG backend in the shower code has been restructured to
make future additions easier: PowhegEvolver has merged with
Evolver; both the matrix element corrections and real corrections
in the POWHEG scheme are implemented directly in the ME or Decayer
classes.
** New processes at leading order
*** Photon initiated processes
We have added a matrix element for dijet production in gamma
hadron collisions.
*** Bottom and charm in heavy quark ME
The option of bottom and charm quarks is now supported for heavy
quark production in MEHeavyQuark.
** Colour reconnection
The cluster hadronization model has been extended by an option to
reconnect coloured constituents between clusters with a given
probability. This new model is different from the colour
reconnection model used in FORTRAN HERWIG, and improves the
description of minimum bias and underlying event data.
** Diffractive Processes
Both single and double diffractive processes are now supported in
Herwig++. The Pomeron PDF is implemented using a fit to HERA data,
and a pion PDF can be used to model reggeon flux.
** BSM physics
*** New models
We have added new BSM models, particularly ADD-type extra
dimension models and the next-to-minimal supersymmetric standard
model (NMSSM). Effects of leptoquarks can as well be simulated.
*** Vertex additions
We have added flavour changing stop interactions (stop -
neutralino - charm) and gravitino interactions with particular
emphasis on numerical stability for very light gravitinos.
Tri-linear Higgs and Higgs-Higgs/Vector-Vector four-vertices are
available as well.
*** Input file changes
The SUSY model can now also extract the SLHA information from the
header of a Les Houches event file: replace the SLHA file name
in the example input files with the LH file name.
*** Structure
The backend structure of the HardProcessConstructor has changed,
to allow easier inclusion of new process constructors. Some 2->3
BSM scattering processes involving neutral higgs bosons are now
included. The spin handling has been improved in the background.
** Shower splitting code reorganized
The selection of spin structures has been decoupled from the choice
of colour structure. This gives more flexibility in implementing
new splittings. Selected splittings can be disabled in the input
files.
** B mixing
B mixing, and indirect CP violation in the B meson system are
included now.
** Looptools
The Looptools directory has been updated to reflect T.Hahn's
Looptools 2.6.
** Contrib changes
The ROOT interface has been removed as deprecated. The MCPWNLO code
has temporarily been removed from the Contrib directory as a major
review of this code is required. Additionally, there are various
fixes to all other codes shipped in Contrib.
** DIS improvements
The momentum reshuffling in DIS events has been improved.
** mu and nu beams
mu, nu_e and nu_mu and their antiparticles are now available as
beam particles. They are all supported in the DIS matrix
elements. mu+ mu- collisions are supported in the general
matrix element code for BSM models, but not yet in the hard-coded
matrix elements for lepton-lepton scattering.
** Structural changes
*** Inline code
Inline code has been merged into the header files, .icc files were
removed.
*** Silent build
By default, Herwig++ now builds with silent build rules. To get
the old behaviour, run 'make V=1'.
*** Debug level
The debug level on the command line will now always have priority.
*** Event counter
The event counter has been simplified.
*** Interpolator persistency
Interpolators can now be written persistently.
** Ticket #307: Momentum violation check in BasicConsistency
Added parameters AbsoluteMomentumTolerance and
RelativeMomentumTolerance
** Example POWHEG input files
The example input files for Powheg processes now set the NLO
alpha_S correctly, and are run as part of 'make check'.
** Truncated shower
A problem which lead to the truncated shower not being applied in
some cases has been fixed.
** Fixes to numerical problems
Minor problems with values close to zero were fixed in several
locations.
** Remove duplicated calculation of event shapes
An accidental duplication in the calculation of event shapes was
removed, they are now only calculated once per event. Several other
minor issues in the event shape calculations have also been fixed.
** MRST PDFs fixed
An initialization problem in the internal MRST PDFs was fixed.
** Vertex scale choice
The scale in the Vertex classes can now be zero where
possible.
** Treatment of -N flag
The Herwig++ main program now correctly treats the -N flag
as optional.
** Numerical stability improved
The numerical stability in the 'RunningMass' and
'QTildeReconstructor' classes has been improved. The
stability of the boosts in the SOPTHY code for the
simulation of QED radiation has been improved.
The accuracy of boosts in the z-direction has been improved to
fix problems with extremely high p_T partons.
** Bugfix in initial state splittings
A bug in the implementation of the PDF weight in initial-state
qbar -> qbar g splittings has been fixed.
** Bugfix in chargino neutralino vertices
A bug in the 'chi+- chi0 W-+' and charged
Higgs-sfermions vertices has been fixed.
** Remove uninitialized variables written to repository
A number of uninitialised variables which were written to the
repository have been initialised to zero to avoid problems on some
systems.
** Fix to QED radiation in hadronic collisions
The longitudinal boost of the centre-of-mass frame in hadronic
collisions is correctly accounted for now in the generation of QED
radiation.
** Fix to numerical problems in two-body decays
Numerical problems have been fixed, which appeared in the rare case
that the three-momenta of the decay products in two-body decays are
zero in the rest frame of the decay particle.
** A problem with forced splittings in the Remnant was fixed.
** ME correction for W+- decays applied properly
The matrix element correction for QCD radiation in W+- decays
which was not being applied is now correctly used.
** Top quark decays from SLHA file
The presence of top quark decay modes in SLHA files is now handled
correctly.
** Exceptional shower reconstruction kinematics
Additional protection against problems due to the shower
reconstruction leading to partons with x>1 has been added.
** Ordering of particles in BSM processes
Changes have been made to allow arbitrary ordering of the outgoing
particles in BSM processes.
** Bugfixes in tau decays
Two bugs involving tau decays have been fixed. The wrong masses
were used in the 'KPiCurrent' class for the scalar form factors
and a mistake in the selection of decay products lead to
tau- --> pi0 K- being generated instead of tau- --> eta K-.
** Avoid crashes in baryon number violating processes.
To avoid crashes, better protection has been introduced for the
case where diquarks cannot be formed from the quarks in a
baryon-number violating process. In addition, the parents of the
baryon-number violating clusters have been changed to avoid
problems with the conversion of the events to HepMC.
** QED radiation in W- decays
A bug in the 'QEDRadiationHandler' class which resulted
in no QED radiation being generated in W- decays has been fixed.
** A number of minor fixes to the SUSY models have been made.
** Partial width calculations in BSM models
A fix for the direction of the incoming particle in the calculation
of two-body partial widths in BSM models has been made.
** LoopTools improvements
The LoopTools cache is now cleared more frequently to
reduce the amount of memory used by the particle.
** Negative gluino masses are now correctly handled.
** A problem with mixing matrices which are not square has been fixed.
** Removed duplicate diagram
The 'MEee2gZ2ll' class has been fixed to only include the
photon exchange diagram once rather than twice as previously.
** Fix for duplicate particles in DecayConstructor
A problem has been fixed which occurred if the same particle was
included in the list of DecayConstructor:DecayParticles.
** Fixes for UED model vertices
A number of minor problems in the vertices for the UED model have
been fixed.
** Include missing symmetry factor
The missing identical-particle symmetry factor in
'MEPP2GammaGamma' has been included.
** Fix floating point problem in top decays
A floating point problem in the matrix element correction for top
decays has been fixed.
* Herwig++-2.4.2 release: 2009-12-11 (tagged at SVN r5022)
** Ticket #292: Tau decay numerical instability
The momentum assignment in tau decays contained numerical
instabilities which have been fixed by postponing the tau decay
until after the parton shower. A new interface setting
DecayHandler:Excluded is available to prevent decays in the shower
step. This is enabled by default for tau only.
** Ticket #290: Missing MSSM colour structure
The missing colour structure for gluino -> gluon neutralino was added.
** Ticket #294: Zero momentum in some decays
Some rare phase space points lead to zero momentum in two-body
decays. This has been fixed.
** Ticket #295: Stability of QED radiation for lepton collider processes
The numerical stability of QED radiation momenta was improved
further.
** Ticket #296: K0 oscillation vertex was wrong
The oscillation from K0 to K0_L/S now takes place at the production
vertex of K0.
** Ticket #289: Undefined variables in repository
On some system configurations, undefined variables were written to
the repository. These have been fixed.
** Fixed QED radiation for hadron processes
The longitudinal boost of the centre-of-mass frame in hadronic
collisions is correctly accounted for now.
** Numerical stability fixes
Small fixes in RunningMass and QTildeReconstructor.
** Powheg example input files
The example input files for Powheg processes now set the NLO
alpha_S correctly, and are run as part of 'make check'.
** OS X builds for Snow Leopard
Snow Leopard machines will now be recognized as a 64bit
architecture.
* Herwig++-2.4.1 release: 2009-11-19 (tagged at SVN r4932)
** Uses ThePEG-1.6.0
Herwig++ now requires ThePEG-1.6.0 to benefit from the improved
helicity code there. If you have self-written vertex classes, see
ThePEG's NEWS file for conversion instructions.
** Vertex improvements
ThePEG's new helicity code allowed major simplification of the vertex
implementations for all Standard Model and BSM physics models.
** New Transplanckian scattering model
An example configuration is in LHC-TRP.in
** BSM ModelGenerator as branching ratio calculator
The BSM ModelGenerator has a new switch to output the branching
ratios for a given SLHA file in SLHA format, which can then be used
elsewhere.
** BSM debugging: HardProcessConstructor
New interface 'Excluded' to exclude certain particles from
intermediate lines.
** Chargino-Neutralino-W vertex fixed
** Spin correlations
are now switched on by default for all perturbative decays.
** Ticket #276: Scale choice in BSM models' HardProcessConstructor
New interface 'ScaleChoice' to choose process scale between
- sHat (default for colour neutral intermediates) and
- transverse mass (default for all other processes).
** Ticket #287: Powheg process scale choice
The default choice is now the mass of the colour-singlet system.
** Ticket #278: QED radiation for BSM
Soft QED radiation is now enabled in BSM decays and all
perturbative decays by default.
** Ticket #279: Full 1-loop QED radiation for Z decays
Soft QED radiation in Z decays is now fully 1-loop by default.
** Ticket #280: Redirect all files to stdout
This is now implemented globally. The files previously ending in
-UE.out and -BSMinfo.out are now appended to the log file. They now
also obey the EventGenerator:UseStdout flag.
** Ticket #270: LaTeX output updated
After each run, a LaTeX file is produced that contains the full
list of citations. Please include the relevant ones in publications.
** Ticket #256: Mac OS X problems
An initialization problem that affected only some configurations has
been identified and fixed.
** Tests directory added
This contains many .in files, to exercise most matrix
elements.
** Minor fixes
*** Prevent rare x>1 partons in shower reconstruction.
*** SUSY-LHA parameter EXTPAR can be used to set tan beta
*** Improved Fastjet detection at configure time
* Herwig++-2.4.0 release: 2009-09-01 (tagged at SVN r4616)
** New matrix elements
We have added a built-in implementation of several new matrix elements:
PP --> WW / WZ / ZZ
PP --> W gamma / Z gamma
PP --> VBF Higgs
PP --> Higgs tt / Higgs bb
e+e- --> WW / ZZ
gamma gamma --> ff / WW
** Base code improvements
*** Ticket #257: Remnant handling
A problem with forced splittings in the Remnant was fixed.
*** Ticket #264: Soft matrix element correction
A problem with emissions form antiquarks was fixed.
** PDF sets
*** New default set
MRST LO** is the new default PDF set. LO* is also available built-in.
*** Shower PDFs can be set separately from the hard process
Use the 'ShowerHandler:PDF' interface.
** Parameter tunes
Shower, hadronization and underlying event parameters were retuned
against LEP and Tevatron data respectively.
** BSM module improvements
*** Ticket #259: read error for some UED models
Arbitrary ordering of outgoing lines in the process description is now
possible.
*** Ticket #266: branching ratio sums
The warning threshold for branching ratios not summing to 1 has
been relaxed. It is now a user interface parameter.
*** Ticket #267: Top decay modes
Top decay modes listed in SLHA files are now handled correctly.
** QED radiation
*** Ticket #241: Soft QED radiation is now enabled by default
*** Ticket #265: Radiation off W+ and W- is now handled correctly
** Interfaces
*** Ticket #243: Fastjet
Fastjet is now the only supported jet finder code. All example
analyses have been converted to use Fastjet.
*** KtJet and CLHEP interfaces have been removed.
*** New interfaces to AcerDet and PGS available in Contrib
*** MCPWnlo distributed in Contrib
*** HepMC and Rivet interfaces moved to ThePEG
** Ticket #239: Inelastic cross-section for MinBias
This information is now available in the ...-UE.out files.
** Technical changes
*** Ticket #186
Configure now looks for ThePEG in the --prefix location first.
*** Configure information
Important configuration information is listed at the end of the
'configure' run and in the file 'config.thepeg'. Please provide
this file in any bug reports.
*** New ZERO object
The ZERO object can be used to set any dimensionful quantity to
zero. This avoids explicit constructs like 0.0*GeV.
*** Exception specifiers removed
Client code changes are needed in doinit() etc., simply remove the
exception specifier after the function name.
*** Ticket #263: Tau polarizations can be forced in TauDecayer
* Herwig++-2.3.2 release: 2009-05-08 (tagged at SVN r4249)
** SUSY enhancements
*** Ticket #245: Select inclusive / exclusive production
Using the new 'HardProcessConstructor:Processes' switch options
'SingleParticleInclusive', 'TwoParticleInclusive' or 'Exclusive'
*** Improved three-body decay generation
Several problems were fixed, incl. tickets #249 #250 #251
Thanks to J.Tattersall and K.Rolbiecki for the stress-testing!
*** Looptools fix
Release 2.3.1 had broken the Looptools initialization.
*** Improved warning message texts
** Ticket #237:
Values of q2last can now be zero where possible.
** Ticket #240:
The Herwig++ main program now correctly treats the -N flag as optional.
** Ticket #246:
Extreme pT partons fixed by improving accuracy of z boosts.
** DIS
Improved parton shower momentum reshuffling.
** Minimum Bias events
The zero-momentum interacting particle used for
bookkeeping is now labelled as a pomeron.
** User Makefile
Makefile-UserModules does not enable -pedantic anymore. User's ROOT
code will not compile otherwise.
** Build system
Small fixes in the build system.
* Herwig++-2.3.1 release: 2009-03-31 (tagged at SVN r4140)
** Initial state showers
The PDF veto was wrongly applied to qbar->qbar g splittings.
** User interaction
The Makefile-UserModules now includes the Herwig version number.
The -N flag to 'Herwig++ run' is optional now, as was always intended.
** Contrib
The contrib directory is now included in the tarball. The omission
was accidental.
** Numerical accuracy
Minor problems with values close to zero were fixed in several
locations.
** LEP event shapes
An accidental duplication was removed, they are now only calculated
once per event.
** MRST PDF code
Initialization problem fixed.
** Mac OS X
The configure script was improved to detect libraries better.
** Libtool
Updated to version 2.2.6
* Herwig++-2.3.0 release: 2008-12-02 (tagged at SVN r3939)
** Major release, with many new features and bug fixes
** Extension to lepton-hadron collisions
** Inclusion of several processes accurate at next-to-leading order
in the POsitive Weight Hardest Emission Generator (POWHEG) scheme
** Inclusion of three-body decays and finite-width effects
in BSM processes
** New procedure for reconstructing kinematics of the parton shower
based on the colour structure of the hard scattering process
** New model for baryon decays including excited baryon multiplets
** Addition of a soft component to the multiple scattering model
of the underlying event and the option to choose more than one hard
scattering explicitly
** New matrix elements for DIS and e+e- processes
** New /Contrib directory added
containing external modules that will hopefully be of use to some
users but are not expected to be needed by most users and are not
supported at the same level as the main Herwig++ code
** Minor changes to improve the physics simulation:
*** IncomingPhotonEvolver added
to allow the simulation of partonic processes with incoming photons
in hadron collisions
*** KTRapidityCut added
to allow cuts on the p_T and rapidity, rather than just the p_T and
pseudorapidity used in SimpleKTCut. This is now used by default for
cuts on massive particles such as the $W^\pm$, $Z^0$ and Higgs
bosons and the top quark
*** Several changes to the decayers of B mesons
both to resolve problems with the modelling of partonic decays and
improve agreement with $\Upsilon(4s)$ data
*** Changes to allow values other than transverse mass of final-state particles as maximum transverse momentum for radiation in parton shower
either SCALUP for Les Houches events or the scale of the hard
process for internally generated hard processes
*** Changed defaults for intrinsic transverse momentum in hadron collisions
to 1.9GeV, 2.1GeV and 2.2GeV for the Tevatron and LHC at 10 TeV and
14 TeV, respectively
*** Pdfinfo object is now created in the HepMC interface
However in order to support all versions of HepMC containing this
feature the PDF set is not specified as not all versions contain
this information
*** New option of only decaying particles with lifetimes below user specified value
*** New options for the cut-off in the shower
and some obsolete parameters removed
*** Added option of switching off certain decay modes in BSM models
*** Added a Matcher for Higgs boson
to allow cuts to be placed on it
*** Diffractive particles deleted from default input files
they were not previously used
** Technical changes:
*** Some AnalysisHandler classes comparing to LEP data have been renamed
e.g. MultiplicityCount becomes LEPMultiplicityCount to avoid
confusion with those supplied in /Contrib for observables at the
Upsilon(4s) resonance
*** Reorganisation to remove the majority of the .icc files
by moving inlined functions to headers in an effort to improve
compile time
*** Restructured the decay libraries to reduce the amount of memory allocation
and de-allocation which improves run-time performance
*** The switch to turn off LoopTools has been removed
because LoopTools is now used by several core modules. As LoopTools
does not work on 64-bit platforms with g77 this build option is not
supported
*** Removed support for obsolete version of HepMC supplied with CLHEP
and improved the support for different units options with HepMC
*** EvtGen interface has been removed until it is more stable
*** Support for ROOT has been removed
it was not previously used
*** CKKW infrastructure has been removed from the release
until a concrete implementation is available
*** Default optimisation has been increased from -O2 to -O3
*** Handling of the fortran compiler has been improved
mainly due to improvements in the autotools
*** Use of FixedAllocator for Particle objects in ThePEG has been removed
as it had no performance benefits
** Bugs fixed:
*** Problems with the mother/daughter relations in the hard process
and diagram selection in W+- and Z0 production in association with a
hard jet
*** In general matrix element code for fermion-vector to fermion-scalar
where the outgoing fermion is coloured and the scalar neutral
*** In the selection of diagrams in some associated squark gaugino processes
*** h0->mu+mu- was being generated when h0->tau+tau-
*** Normalisation in the Histogram class for non unit-weight events
*** Protection against negative PDF values has been improved
these can occur when using NLO PDF sets
*** Lifetime for BSM particles is now automatically calculated
at the same time as the width
*** Hadrons containing a top quark now treated like hadrons containing BSM particles
in order to support this possibility
*** Several ambiguous uses of unsigned int
*** Several variables that may have been used undefined
*** Several memory leaks at initialisation
*** The configuration now aborts if no fortran compiler is found
as this is required to compile Looptools
*** Several minor floating point errors that did not affect results
* Herwig++-2.2.1 release: 2008-07-09 (tagged at SVN r3434)
** Ticket #181: BSM shower with a decay close to threshold
Now fixed.
** Ticket #191: Split SUSY crash
Improved error message.
** Ticket #192: using SCALUP as the pT veto in the shower
Now implemented.
** Ticket #194: production processes of ~chi_1(2)-
Fixed bug in the diagram creation.
** Removed unused particles
DiffractiveParticles.in was removed, they were never produced.
** Hadronization
Top quark clusters now possible, handled as 'exotic' clusters.
** Improved handling of decay modes
See ThePEG-1.3.0. 'defaultparticle' command is now obsolete.
** Multi-Parton interactions
Increased phase space sampling to have less than 1% uncertainty on
average multiplicity.
** New libtool version
gfortran is now used as default if it is available. Set FC=g77 to
override this.
** Fixed several memory leaks
** Memory allocation
Now using plain 'new' and 'delete'.
* Herwig++-2.2.0 release: 2008-04-18 (tagged at SVN r3195)
** Major release: now as stand-alone library
Herwig++ is now a stand-alone dlopen() plugin to ThePEG.
No compile-time linking to Herwig code is required. The Herwig++
binary is a simple executable steering ThePEG, which can
be replaced by other frontends (such as setupThePEG / runThePEG).
** New matrix elements
p p -> W + jet / Z + jet / W + higgs / Z + higgs
e+ e- -> Z + higgs
** Looptools
Updated to version 2.2.
** Ticket #141: segfault from using 'run' command
Fixed by using default allocators in Herwig++, and the
Repository::cleanup() method in ThePEG 1.2.0.
** Ticket #157: broken gsl library path on some 64bit systems
Paths with lib64 are correctly identified now.
** Ticket #159: p_t spectrum of ttbar pair
Fixed identical particle multiplier in Sudakov form factor.
** Ticket #161: glibc segfault
Rare segfault in MPI handler fixed.
** Ticket #165: rare infinite loop in four-body decay
All 4-body decays without dedicated decayers now use the Mambo algorithm.
A loop guard has been introduced to 3-body decays to avoid infinite retries.
** Ticket #166: rare infinite loop in top ME correction
These very rare events (O(1) in 10^7) close to mass threshold
now are discarded.
** Higgs width fixes
** SatPDF
Optionally, the PDF extrapolation behaviour outside a given range
can now be specified.
** gcc 4.3
Herwig++-2.2 compiles cleanly with the new gcc 4.3 series.
* Herwig++-2.1.4 release: 2008-03-03 (tagged at SVN r3024)
** Ticket #152: Vertex positions
All vertex positions of unphysical particles are set to zero until
a fix for the previous nonsensical values can be implemented.
* Herwig++-2.1.3 release: 2008-02-25 (tagged at SVN r2957)
** Ticket #129: Baryon decays
Fix for baryon decay modes.
** Ticket #131: HepMC
Check if IO_GenEvent exists
** Ticket #134: Hadronization
Smearing of hadron directions in cluster decay fixed.
** Ticket #137: HepMC
HepMC conversion allows specification of energy and length units to
be used.
** Ticket #139: Neutral kaons
Ratio K_L / K_S corrected.
** Ticket #140 / #141: Crash on shutdown
Event generation from the 'read' stage or an interface now shuts
down cleanly. Fixes a crash bug introduced in 2.1.1 which affected
external APIs to ThePEG / Herwig.
** Ticket #146: BSM models can be disabled
To save build time, some or all of the BSM models can be disabled
using the '--enable-models' configure switch.
** Reorganised .model files
The .model files now include the model-specific particles, too.
** Re-tune
Re-tuned hadronization parameters to LEP data.
** Other fixes in
QSPAC implementation in Shower; Multi-parton interaction tuning;
MRST initialization
* Herwig++-2.1.2 release: 2008-01-05 (tagged at SVN r2694)
** Ticket #127
Thanks to a patch submitted by Fred Stober, HepMCFile now can
output event files in all supported formats.
** Ticket #128
Fixed incorrect value of pi in histogram limits.
** Other fixes in
CKKW Qtilde clusterers, BSM width cut, SUSY mixing matrices.
* Herwig++-2.1.1 release: 2007-12-08 (tagged at SVN r2589)
** Bug #123
Fixed a bug with particle lifetimes which resulted in nan for some
vertex positions.
** Secondary scatters
Fixed bug which gave intrinsic pT to secondary scatters.
** gcc abs bug detection
configure now checks for and works around
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34130
** CKKW reweighting
Fixed wrong check for top quarks.
** MPIHandler
Fixed call order ambiguity.
* Herwig++-2.1.0 release: 2007-11-20 (tagged at SVN r2542)
** Major new release
Herwig++-2.1 includes significant improvements, including
multi-parton interactions, BSM physics and a new hadronic decay
model, tuned to LEP data.
For an overview of the changes, please see the release note
arXiv:0711.3137
* Herwig++-2.0.3 release: 2007-08-21 (tagged at SVN r2101)
** Bug #90
nan in top decay ME corrections fixed.
** unlisted
Colour flow fix in LightClusterDecayer
** unlisted
Updated version of MultiplicityCount analysis handler.
* Herwig++-2.0.2 release: 2007-07-06 (tagged at SVN r1716)
** Bug #80
Separation of HepMC from CLHEP is handled properly now.
** Bug #83
Workaround for OS X header problem
** unlisted
Veto on very hard emissions from Shower.
** unlisted
Detailed documentation in .in files
* Herwig++-2.0.1 release: 2006-12-05 (tagged at SVN r1195)
** Bug #54
ClusterFissioner vertex calculation fixed.
** Bug #57
Crash when showering W+jet events supplied by Les Houches interface.
** Bug #59
Fix for #57 applied to LHC events.
** Bug #60
Segfault when PDF is set to NoPDF.
** Bug #61
Missing weight factor for I=0 mesons
** Bug #62
Spinor vertex calculations broken when spinor rep is not default rep.
** Bug #63
Top decay never produces tau.
** Bug #69
TTbar and HiggsJet analysis handlers fixed.
** unlisted
Reorganization of Hadronization module gives 30% speedup.
Thanks to Vincenzo Innocente at CMS for his profiling work!
** unlisted
cleaner automake files in include/ and src/
** unlisted
Hw64 hadron selection algorithm 'abortnow' fixed.
** unlisted
Top/LeptonDalitzAnalysis removed (only worked with modified code).
** unlisted
removed f'_0 from particle list, decays were not handled
* Herwig++-2.0.0 release: 2006-09-28 (tagged at SVN r1066)
** Full simulation of hadron collisions
diff --git a/PDF/Makefile.am b/PDF/Makefile.am
--- a/PDF/Makefile.am
+++ b/PDF/Makefile.am
@@ -1,52 +1,58 @@
EXTRA_DIST = diffraction
pkglib_LTLIBRARIES = HwPomeronPDF.la
HwPomeronPDF_la_SOURCES = \
PomeronPDF.cc PomeronPDF.h
## add this to produce tests of the PDFs
## HwDIFFRACTIVEPDF_la_CPPFLAGS=$(AM_CPPFLAGS) -DDIFFRACTIVEPDF_TESTING
HwPomeronPDF_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 3:0:0
pkglib_LTLIBRARIES += HwReggeonPDF.la
HwReggeonPDF_la_SOURCES = \
ReggeonPDF.cc ReggeonPDF.h
## add this to produce tests of the PDFs
## HwDIFFRACTIVEPDF_la_CPPFLAGS=$(AM_CPPFLAGS) -DDIFFRACTIVEPDF_TESTING
HwReggeonPDF_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 3:0:0
pkglib_LTLIBRARIES += HwPomeronFlux.la
HwPomeronFlux_la_SOURCES = \
PomeronFlux.h PomeronFlux.cc
HwPomeronFlux_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 4:0:0
## bound into HwShower.la
noinst_LTLIBRARIES = libHwRemDecayer.la
libHwRemDecayer_la_SOURCES = \
HwRemDecayer.h HwRemDecayer.cc HwRemDecayer.fh
## bound into HwShower.la
noinst_LTLIBRARIES += libHwMPIPDF.la
libHwMPIPDF_la_SOURCES = \
MPIPDF.h MPIPDF.cc MPIPDF.fh \
MinBiasPDF.h MinBiasPDF.cc MinBiasPDF.fh
pkglib_LTLIBRARIES += HwSatPDF.la
HwSatPDF_la_SOURCES = \
SatPDF.h SatPDF.cc
HwSatPDF_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 6:0:0
pkglib_LTLIBRARIES += HwIncomingPhotonEvolver.la
HwIncomingPhotonEvolver_la_SOURCES = \
IncomingPhotonEvolver.h IncomingPhotonEvolver.cc
HwIncomingPhotonEvolver_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 6:0:0
+pkglib_LTLIBRARIES += HwSaSPhotonPDF.la
+HwSaSPhotonPDF_la_SOURCES = \
+SaSGamma.f SaSPhotonPDF.cc SaSPhotonPDF.h
+
+HwSaSPhotonPDF_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 1:0:0
+
install-data-local:
for i in `find $(srcdir)/diffraction -name '*.data'`; \
do \
$(install_sh_DATA) $$i $(DESTDIR)$(pkgdatadir)/PDF/$${i#$(srcdir)/}; \
done
uninstall-local:
rm -rf $(DESTDIR)$(pkgdatadir)/PDF
diff --git a/PDF/SaSGamma.f b/PDF/SaSGamma.f
new file mode 100644
--- /dev/null
+++ b/PDF/SaSGamma.f
@@ -0,0 +1,718 @@
+C-----------------------------------------------------------------------
+C...SaSgam version 2 - parton distributions of the photon
+C...by Gerhard A. Schuler and Torbjorn Sjostrand
+C...For further information see Z. Phys. C68 (1995) 607
+C...and CERN-TH/96-04 and LU TP 96-2.
+C...Program last changed on 18 January 1996.
+C
+C!!!Note that one further call parameter - IP2 - has been added
+C!!!to the SASGAM argument list compared with version 1.
+C
+C...The user should only need to call the SASGAM routine,
+C...which in turn calls the auxiliary routines SASVMD, SASANO,
+C...SASBEH and SASDIR. The package is self-contained.
+C
+C...One particular aspect of these parametrizations is that F2 for
+C...the photon is not obtained just as the charge-squared-weighted
+C...sum of quark distributions, but differ in the treatment of
+C...heavy flavours (in F2 the DIS relation W2 = Q2*(1-x)/x restricts
+C...the kinematics range of heavy-flavour production, but the same
+C...kinematics is not relevant e.g. for jet production) and, for the
+C...'MSbar' fits, in the addition of a Cgamma term related to the
+C...separation of direct processes. Schematically:
+C...PDF = VMD (rho, omega, phi) + anomalous (d, u, s, c, b).
+C...F2 = VMD (rho, omega, phi) + anomalous (d, u, s) +
+C... Bethe-Heitler (c, b) (+ Cgamma (d, u, s)).
+C...The J/psi and Upsilon states have not been included in the VMD sum,
+C...but low c and b masses in the other components should compensate
+C...for this in a duality sense.
+C
+C...The calling sequence is the following:
+C CALL SASGAM(ISET,X,Q2,P2,IP2,F2GM,XPDFGM)
+C...with the following declaration statement:
+C DIMENSION XPDFGM(-6:6)
+C...and, optionally, further information in:
+C COMMON/SASCOM/XPVMD(-6:6),XPANL(-6:6),XPANH(-6:6),XPBEH(-6:6),
+C &XPDIR(-6:6)
+C COMMON/SASVAL/VXPVMD(-6:6),VXPANL(-6:6),VXPANH(-6:6),VXPDGM(-6:6)
+C...Input: ISET = 1 : SaS set 1D ('DIS', Q0 = 0.6 GeV)
+C = 2 : SaS set 1M ('MSbar', Q0 = 0.6 GeV)
+C = 3 : SaS set 2D ('DIS', Q0 = 2 GeV)
+C = 4 : SaS set 2M ('MSbar', Q0 = 2 GeV)
+C X : x value.
+C Q2 : Q2 value.
+C P2 : P2 value; should be = 0. for an on-shell photon.
+C IP2 : scheme used to evaluate off-shell anomalous component.
+C = 0 : recommended default, see = 7.
+C = 1 : dipole dampening by integration; very time-consuming.
+C = 2 : P_0^2 = max( Q_0^2, P^2 )
+C = 3 : P'_0^2 = Q_0^2 + P^2.
+C = 4 : P_{eff} that preserves momentum sum.
+C = 5 : P_{int} that preserves momentum and average
+C evolution range.
+C = 6 : P_{eff}, matched to P_0 in P2 -> Q2 limit.
+C = 7 : P_{eff}, matched to P_0 in P2 -> Q2 limit.
+C...Output: F2GM : F2 value of the photon (including factors of alpha_em).
+C XPFDGM : x times parton distribution functions of the photon,
+C with elements 0 = g, 1 = d, 2 = u, 3 = s, 4 = c, 5 = b,
+C 6 = t (always empty!), - for antiquarks (result is same).
+C...The breakdown by component is stored in the commonblock SASCOM,
+C with elements as above.
+C XPVMD : rho, omega, phi VMD part only of output.
+C XPANL : d, u, s anomalous part only of output.
+C XPANH : c, b anomalous part only of output.
+C XPBEH : c, b Bethe-Heitler part only of output.
+C XPDIR : Cgamma (direct contribution) part only of output.
+C...The above arrays do not distinguish valence and sea contributions,
+C...although this information is available internally. The additional
+C...commonblock SASVAL provides the valence part only of the above
+C...distributions. Array names VXPVMD, VXPANL and VXPANH correspond
+C...to XPVMD, XPANL and XPANH, while XPBEH and XPDIR are valence only
+C...and therefore not given doubly. VXPDGM gives the sum of valence
+C...parts, and so matches XPDFGM. The difference, i.e. XPVMD-VXPVMD
+C...and so on, gives the sea part only.
+C
+ SUBROUTINE SASGAM(ISET,X,Q2,P2,IP2,F2GM,XPDFGM)
+C...Purpose: to construct the F2 and parton distributions of the photon
+C...by summing homogeneous (VMD) and inhomogeneous (anomalous) terms.
+C...For F2, c and b are included by the Bethe-Heitler formula;
+C...in the 'MSbar' scheme additionally a Cgamma term is added.
+ DIMENSION XPDFGM(-6:6)
+ COMMON/SASCOM/XPVMD(-6:6),XPANL(-6:6),XPANH(-6:6),XPBEH(-6:6),
+ &XPDIR(-6:6)
+ COMMON/SASVAL/VXPVMD(-6:6),VXPANL(-6:6),VXPANH(-6:6),VXPDGM(-6:6)
+ SAVE /SASCOM/,/SASVAL/
+C
+C...Temporary array.
+ DIMENSION XPGA(-6:6), VXPGA(-6:6)
+ SAVE PMC,PMB,AEM,AEM2PI,ALAM,FRACU,FRHO,FOMEGA,FPHI,PMRHO,PMPHI,
+ $ NSTEP
+C...Charm and bottom masses (low to compensate for J/psi etc.).
+ DATA PMC/1.3/, PMB/4.6/
+C...alpha_em and alpha_em/(2*pi).
+ DATA AEM/0.007297/, AEM2PI/0.0011614/
+C...Lambda value for 4 flavours.
+ DATA ALAM/0.20/
+C...Mixture u/(u+d), = 0.5 for incoherent and = 0.8 for coherent sum.
+ DATA FRACU/0.8/
+C...VMD couplings f_V**2/(4*pi).
+ DATA FRHO/2.20/, FOMEGA/23.6/, FPHI/18.4/
+C...Masses for rho (=omega) and phi.
+ DATA PMRHO/0.770/, PMPHI/1.020/
+C...Number of points in integration for IP2=1.
+ DATA NSTEP/100/
+C
+C...Reset output.
+ F2GM=0.
+ DO 100 KFL=-6,6
+ XPDFGM(KFL)=0.
+ XPVMD(KFL)=0.
+ XPANL(KFL)=0.
+ XPANH(KFL)=0.
+ XPBEH(KFL)=0.
+ XPDIR(KFL)=0.
+ VXPVMD(KFL)=0.
+ VXPANL(KFL)=0.
+ VXPANH(KFL)=0.
+ VXPDGM(KFL)=0.
+ 100 CONTINUE
+C
+C...Check that input sensible.
+ IF(ISET.LE.0.OR.ISET.GE.5) THEN
+ WRITE(*,*) ' FATAL ERROR: SaSgam called for unknown set'
+ WRITE(*,*) ' ISET = ',ISET
+ STOP
+ ENDIF
+ IF(X.LE.0..OR.X.GT.1.) THEN
+ WRITE(*,*) ' FATAL ERROR: SaSgam called for unphysical x'
+ WRITE(*,*) ' X = ',X
+ STOP
+ ENDIF
+C
+C...Set Q0 cut-off parameter as function of set used.
+ IF(ISET.LE.2) THEN
+ Q0=0.6
+ ELSE
+ Q0=2.
+ ENDIF
+ Q02=Q0**2
+C
+C...Scale choice for off-shell photon; common factors.
+ Q2A=Q2
+ FACNOR=1.
+ IF(IP2.EQ.1) THEN
+ P2MX=P2+Q02
+ Q2A=Q2+P2*Q02/MAX(Q02,Q2)
+ FACNOR=LOG(Q2/Q02)/NSTEP
+ ELSEIF(IP2.EQ.2) THEN
+ P2MX=MAX(P2,Q02)
+ ELSEIF(IP2.EQ.3) THEN
+ P2MX=P2+Q02
+ Q2A=Q2+P2*Q02/MAX(Q02,Q2)
+ ELSEIF(IP2.EQ.4) THEN
+ P2MX=Q2*(Q02+P2)/(Q2+P2)*EXP(P2*(Q2-Q02)/
+ & ((Q2+P2)*(Q02+P2)))
+ ELSEIF(IP2.EQ.5) THEN
+ P2MXA=Q2*(Q02+P2)/(Q2+P2)*EXP(P2*(Q2-Q02)/
+ & ((Q2+P2)*(Q02+P2)))
+ P2MX=Q0*SQRT(P2MXA)
+ FACNOR=LOG(Q2/P2MXA)/LOG(Q2/P2MX)
+ ELSEIF(IP2.EQ.6) THEN
+ P2MX=Q2*(Q02+P2)/(Q2+P2)*EXP(P2*(Q2-Q02)/
+ & ((Q2+P2)*(Q02+P2)))
+ P2MX=MAX(0.,1.-P2/Q2)*P2MX+MIN(1.,P2/Q2)*MAX(P2,Q02)
+ ELSE
+ P2MXA=Q2*(Q02+P2)/(Q2+P2)*EXP(P2*(Q2-Q02)/
+ & ((Q2+P2)*(Q02+P2)))
+ P2MX=Q0*SQRT(P2MXA)
+ P2MXB=P2MX
+ P2MX=MAX(0.,1.-P2/Q2)*P2MX+MIN(1.,P2/Q2)*MAX(P2,Q02)
+ P2MXB=MAX(0.,1.-P2/Q2)*P2MXB+MIN(1.,P2/Q2)*P2MXA
+ FACNOR=LOG(Q2/P2MXA)/LOG(Q2/P2MXB)
+ ENDIF
+C
+C...Call VMD parametrization for d quark and use to give rho, omega,
+C...phi. Note dipole dampening for off-shell photon.
+ CALL SASVMD(ISET,1,X,Q2A,P2MX,ALAM,XPGA,VXPGA)
+ XFVAL=VXPGA(1)
+ XPGA(1)=XPGA(2)
+ XPGA(-1)=XPGA(-2)
+ FACUD=AEM*(1./FRHO+1./FOMEGA)*(PMRHO**2/(PMRHO**2+P2))**2
+ FACS=AEM*(1./FPHI)*(PMPHI**2/(PMPHI**2+P2))**2
+ DO 110 KFL=-5,5
+ XPVMD(KFL)=(FACUD+FACS)*XPGA(KFL)
+ 110 CONTINUE
+ XPVMD(1)=XPVMD(1)+(1.-FRACU)*FACUD*XFVAL
+ XPVMD(2)=XPVMD(2)+FRACU*FACUD*XFVAL
+ XPVMD(3)=XPVMD(3)+FACS*XFVAL
+ XPVMD(-1)=XPVMD(-1)+(1.-FRACU)*FACUD*XFVAL
+ XPVMD(-2)=XPVMD(-2)+FRACU*FACUD*XFVAL
+ XPVMD(-3)=XPVMD(-3)+FACS*XFVAL
+ VXPVMD(1)=(1.-FRACU)*FACUD*XFVAL
+ VXPVMD(2)=FRACU*FACUD*XFVAL
+ VXPVMD(3)=FACS*XFVAL
+ VXPVMD(-1)=(1.-FRACU)*FACUD*XFVAL
+ VXPVMD(-2)=FRACU*FACUD*XFVAL
+ VXPVMD(-3)=FACS*XFVAL
+C
+ IF(IP2.NE.1) THEN
+C...Anomalous parametrizations for different strategies
+C...for off-shell photons; except full integration.
+C
+C...Call anomalous parametrization for d + u + s.
+ CALL SASANO(-3,X,Q2A,P2MX,ALAM,XPGA,VXPGA)
+ DO 120 KFL=-5,5
+ XPANL(KFL)=FACNOR*XPGA(KFL)
+ VXPANL(KFL)=FACNOR*VXPGA(KFL)
+ 120 CONTINUE
+C
+C...Call anomalous parametrization for c and b.
+ CALL SASANO(4,X,Q2A,P2MX,ALAM,XPGA,VXPGA)
+ DO 130 KFL=-5,5
+ XPANH(KFL)=FACNOR*XPGA(KFL)
+ VXPANH(KFL)=FACNOR*VXPGA(KFL)
+ 130 CONTINUE
+ CALL SASANO(5,X,Q2A,P2MX,ALAM,XPGA,VXPGA)
+ DO 140 KFL=-5,5
+ XPANH(KFL)=XPANH(KFL)+FACNOR*XPGA(KFL)
+ VXPANH(KFL)=VXPANH(KFL)+FACNOR*VXPGA(KFL)
+ 140 CONTINUE
+C
+ ELSE
+C...Special option: loop over flavours and integrate over k2.
+ DO 170 KF=1,5
+ DO 160 ISTEP=1,NSTEP
+ Q2STEP=Q02*(Q2/Q02)**((ISTEP-0.5)/NSTEP)
+ IF((KF.EQ.4.AND.Q2STEP.LT.PMC**2).OR.
+ & (KF.EQ.5.AND.Q2STEP.LT.PMB**2)) GOTO 160
+ CALL SASVMD(0,KF,X,Q2,Q2STEP,ALAM,XPGA,VXPGA)
+ FACQ=AEM2PI*(Q2STEP/(Q2STEP+P2))**2*FACNOR
+ IF(MOD(KF,2).EQ.0) FACQ=FACQ*(8./9.)
+ IF(MOD(KF,2).EQ.1) FACQ=FACQ*(2./9.)
+ DO 150 KFL=-5,5
+ IF(KF.LE.3) XPANL(KFL)=XPANL(KFL)+FACQ*XPGA(KFL)
+ IF(KF.GE.4) XPANH(KFL)=XPANH(KFL)+FACQ*XPGA(KFL)
+ IF(KF.LE.3) VXPANL(KFL)=VXPANL(KFL)+FACQ*VXPGA(KFL)
+ IF(KF.GE.4) VXPANH(KFL)=VXPANH(KFL)+FACQ*VXPGA(KFL)
+ 150 CONTINUE
+ 160 CONTINUE
+ 170 CONTINUE
+ ENDIF
+C
+C...Call Bethe-Heitler term expression for charm and bottom.
+ CALL SASBEH(4,X,Q2,P2,PMC**2,XPBH)
+ XPBEH(4)=XPBH
+ XPBEH(-4)=XPBH
+ CALL SASBEH(5,X,Q2,P2,PMB**2,XPBH)
+ XPBEH(5)=XPBH
+ XPBEH(-5)=XPBH
+C
+C...For MSbar subtraction call C^gamma term expression for d, u, s.
+ IF(ISET.EQ.2.OR.ISET.EQ.4) THEN
+ CALL SASDIR(X,Q2,P2,Q02,XPGA)
+ DO 180 KFL=-5,5
+ XPDIR(KFL)=XPGA(KFL)
+ 180 CONTINUE
+ ENDIF
+C
+C...Store result in output array.
+ DO 190 KFL=-5,5
+ CHSQ=1./9.
+ IF(IABS(KFL).EQ.2.OR.IABS(KFL).EQ.4) CHSQ=4./9.
+ XPF2=XPVMD(KFL)+XPANL(KFL)+XPBEH(KFL)+XPDIR(KFL)
+ IF(KFL.NE.0) F2GM=F2GM+CHSQ*XPF2
+ XPDFGM(KFL)=XPVMD(KFL)+XPANL(KFL)+XPANH(KFL)
+ VXPDGM(KFL)=VXPVMD(KFL)+VXPANL(KFL)+VXPANH(KFL)
+ 190 CONTINUE
+C
+ END
+C
+C*********************************************************************
+C
+ SUBROUTINE SASVMD(ISET,KF,X,Q2,P2,ALAM,XPGA,VXPGA)
+C...Purpose: to evaluate the VMD parton distributions of a photon,
+C...evolved homogeneously from an initial scale P2 to Q2.
+C...Does not include dipole suppression factor.
+C...ISET is parton distribution set, see above;
+C...additionally ISET=0 is used for the evolution of an anomalous photon
+C...which branched at a scale P2 and then evolved homogeneously to Q2.
+C...ALAM is the 4-flavour Lambda, which is automatically converted
+C...to 3- and 5-flavour equivalents as needed.
+ DIMENSION XPGA(-6:6), VXPGA(-6:6)
+ SAVE PMC,PMB
+ DATA PMC/1.3/, PMB/4.6/
+C
+C...Reset output.
+ DO 100 KFL=-6,6
+ XPGA(KFL)=0.
+ VXPGA(KFL)=0.
+ 100 CONTINUE
+ KFA=IABS(KF)
+C
+C...Calculate Lambda; protect against unphysical Q2 and P2 input.
+ ALAM3=ALAM*(PMC/ALAM)**(2./27.)
+ ALAM5=ALAM*(ALAM/PMB)**(2./23.)
+ P2EFF=MAX(P2,1.2*ALAM3**2)
+ IF(KFA.EQ.4) P2EFF=MAX(P2EFF,PMC**2)
+ IF(KFA.EQ.5) P2EFF=MAX(P2EFF,PMB**2)
+ Q2EFF=MAX(Q2,P2EFF)
+C
+C...Find number of flavours at lower and upper scale.
+ NFP=4
+ IF(P2EFF.LT.PMC**2) NFP=3
+ IF(P2EFF.GT.PMB**2) NFP=5
+ NFQ=4
+ IF(Q2EFF.LT.PMC**2) NFQ=3
+ IF(Q2EFF.GT.PMB**2) NFQ=5
+C
+C...Find s as sum of 3-, 4- and 5-flavour parts.
+ S=0.
+ IF(NFP.EQ.3) THEN
+ Q2DIV=PMC**2
+ IF(NFQ.EQ.3) Q2DIV=Q2EFF
+ S=S+(6./27.)*LOG(LOG(Q2DIV/ALAM3**2)/LOG(P2EFF/ALAM3**2))
+ ENDIF
+ IF(NFP.LE.4.AND.NFQ.GE.4) THEN
+ P2DIV=P2EFF
+ IF(NFP.EQ.3) P2DIV=PMC**2
+ Q2DIV=Q2EFF
+ IF(NFQ.EQ.5) Q2DIV=PMB**2
+ S=S+(6./25.)*LOG(LOG(Q2DIV/ALAM**2)/LOG(P2DIV/ALAM**2))
+ ENDIF
+ IF(NFQ.EQ.5) THEN
+ P2DIV=PMB**2
+ IF(NFP.EQ.5) P2DIV=P2EFF
+ S=S+(6./23.)*LOG(LOG(Q2EFF/ALAM5**2)/LOG(P2DIV/ALAM5**2))
+ ENDIF
+C
+C...Calculate frequent combinations of x and s.
+ X1=1.-X
+ XL=-LOG(X)
+ S2=S**2
+ S3=S**3
+ S4=S**4
+C
+C...Evaluate homogeneous anomalous parton distributions below or
+C...above threshold.
+ IF(ISET.EQ.0) THEN
+ IF(Q2.LE.P2.OR.(KFA.EQ.4.AND.Q2.LT.PMC**2).OR.
+ &(KFA.EQ.5.AND.Q2.LT.PMB**2)) THEN
+ XVAL = X * 1.5 * (X**2+X1**2)
+ XGLU = 0.
+ XSEA = 0.
+ ELSE
+ XVAL = (1.5/(1.-0.197*S+4.33*S2)*X**2 + (1.5+2.10*S)/
+ & (1.+3.29*S)*X1**2 + 5.23*S/(1.+1.17*S+19.9*S3)*X*X1) *
+ & X**(1./(1.+1.5*S)) * (1.-X**2)**(2.667*S)
+ XGLU = 4.*S/(1.+4.76*S+15.2*S2+29.3*S4) *
+ & X**(-2.03*S/(1.+2.44*S)) * (X1*XL)**(1.333*S) *
+ & ((4.*X**2+7.*X+4.)*X1/3. - 2.*X*(1.+X)*XL)
+ XSEA = S2/(1.+4.54*S+8.19*S2+8.05*S3) *
+ & X**(-1.54*S/(1.+1.29*S)) * X1**(2.667*S) *
+ & ((8.-73.*X+62.*X**2)*X1/9. + (3.-8.*X**2/3.)*X*XL +
+ & (2.*X-1.)*X*XL**2)
+ ENDIF
+C
+C...Evaluate set 1D parton distributions below or above threshold.
+ ELSEIF(ISET.EQ.1) THEN
+ IF(Q2.LE.P2.OR.(KFA.EQ.4.AND.Q2.LT.PMC**2).OR.
+ &(KFA.EQ.5.AND.Q2.LT.PMB**2)) THEN
+ XVAL = 1.294 * X**0.80 * X1**0.76
+ XGLU = 1.273 * X**0.40 * X1**1.76
+ XSEA = 0.100 * X1**3.76
+ ELSE
+ XVAL = 1.294/(1.+0.252*S+3.079*S2) * X**(0.80-0.13*S) *
+ & X1**(0.76+0.667*S) * XL**(2.*S)
+ XGLU = 7.90*S/(1.+5.50*S) * EXP(-5.16*S) *
+ & X**(-1.90*S/(1.+3.60*S)) * X1**1.30 * XL**(0.50+3.*S) +
+ & 1.273 * EXP(-10.*S) * X**0.40 * X1**(1.76+3.*S)
+ XSEA = (0.1-0.397*S2+1.121*S3)/(1.+5.61*S2+5.26*S3) *
+ & X**(-7.32*S2/(1.+10.3*S2)) *
+ & X1**((3.76+15.*S+12.*S2)/(1.+4.*S))
+ XSEA0 = 0.100 * X1**3.76
+ ENDIF
+C
+C...Evaluate set 1M parton distributions below or above threshold.
+ ELSEIF(ISET.EQ.2) THEN
+ IF(Q2.LE.P2.OR.(KFA.EQ.4.AND.Q2.LT.PMC**2).OR.
+ &(KFA.EQ.5.AND.Q2.LT.PMB**2)) THEN
+ XVAL = 0.8477 * X**0.51 * X1**1.37
+ XGLU = 3.42 * X**0.255 * X1**2.37
+ XSEA = 0.
+ ELSE
+ XVAL = 0.8477/(1.+1.37*S+2.18*S2+3.73*S3) * X**(0.51+0.21*S)
+ & * X1**1.37 * XL**(2.667*S)
+ XGLU = 24.*S/(1.+9.6*S+0.92*S2+14.34*S3) * EXP(-5.94*S) *
+ & X**((-0.013-1.80*S)/(1.+3.14*S)) * X1**(2.37+0.4*S) *
+ & XL**(0.32+3.6*S) + 3.42 * EXP(-12.*S) * X**0.255 *
+ & X1**(2.37+3.*S)
+ XSEA = 0.842*S/(1.+21.3*S-33.2*S2+229.*S3) *
+ & X**((0.13-2.90*S)/(1.+5.44*S)) * X1**(3.45+0.5*S) *
+ & XL**(2.8*S)
+ XSEA0 = 0.
+ ENDIF
+C
+C...Evaluate set 2D parton distributions below or above threshold.
+ ELSEIF(ISET.EQ.3) THEN
+ IF(Q2.LE.P2.OR.(KFA.EQ.4.AND.Q2.LT.PMC**2).OR.
+ &(KFA.EQ.5.AND.Q2.LT.PMB**2)) THEN
+ XVAL = X**0.46 * X1**0.64 + 0.76 * X
+ XGLU = 1.925 * X1**2
+ XSEA = 0.242 * X1**4
+ ELSE
+ XVAL = (1.+0.186*S)/(1.-0.209*S+1.495*S2) * X**(0.46+0.25*S)
+ & * X1**((0.64+0.14*S+5.*S2)/(1.+S)) * XL**(1.9*S) +
+ & (0.76+0.4*S) * X * X1**(2.667*S)
+ XGLU = (1.925+5.55*S+147.*S2)/(1.-3.59*S+3.32*S2) *
+ & EXP(-18.67*S) * X**((-5.81*S-5.34*S2)/(1.+29.*S-4.26*S2))
+ & * X1**((2.-5.9*S)/(1.+1.7*S)) * XL**(9.3*S/(1.+1.7*S))
+ XSEA = (0.242-0.252*S+1.19*S2)/(1.-0.607*S+21.95*S2) *
+ & X**(-12.1*S2/(1.+2.62*S+16.7*S2)) * X1**4 * XL**S
+ XSEA0 = 0.242 * X1**4
+ ENDIF
+C
+C...Evaluate set 2M parton distributions below or above threshold.
+ ELSEIF(ISET.EQ.4) THEN
+ IF(Q2.LE.P2.OR.(KFA.EQ.4.AND.Q2.LT.PMC**2).OR.
+ &(KFA.EQ.5.AND.Q2.LT.PMB**2)) THEN
+ XVAL = 1.168 * X**0.50 * X1**2.60 + 0.965 * X
+ XGLU = 1.808 * X1**2
+ XSEA = 0.209 * X1**4
+ ELSE
+ XVAL = (1.168+1.771*S+29.35*S2) * EXP(-5.776*S) *
+ & X**((0.5+0.208*S)/(1.-0.794*S+1.516*S2)) *
+ & X1**((2.6+7.6*S)/(1.+5.*S)) * XL**(5.15*S/(1.+2.*S)) +
+ & (0.965+22.35*S)/(1.+18.4*S) * X * X1**(2.667*S)
+ XGLU = (1.808+29.9*S)/(1.+26.4*S) * EXP(-5.28*S) *
+ & X**((-5.35*S-10.11*S2)/(1.+31.71*S)) *
+ & X1**((2.-7.3*S+4.*S2)/(1.+2.5*S)) *
+ & XL**(10.9*S/(1.+2.5*S))
+ XSEA = (0.209+0.644*S2)/(1.+0.319*S+17.6*S2) *
+ & X**((-0.373*S-7.71*S2)/(1.+0.815*S+11.0*S2)) *
+ & X1**(4.+S) * XL**(0.45*S)
+ XSEA0 = 0.209 * X1**4
+ ENDIF
+ ENDIF
+C
+C...Threshold factors for c and b sea.
+ SLL=LOG(LOG(Q2EFF/ALAM**2)/LOG(P2EFF/ALAM**2))
+ XCHM=0.
+ IF(Q2.GT.PMC**2.AND.Q2.GT.1.001*P2EFF) THEN
+ SCH=MAX(0.,LOG(LOG(PMC**2/ALAM**2)/LOG(P2EFF/ALAM**2)))
+ IF(ISET.EQ.0) THEN
+ XCHM=XSEA*(1.-(SCH/SLL)**2)
+ ELSE
+ XCHM=MAX(0.,XSEA-XSEA0*X1**(2.667*S))*(1.-SCH/SLL)
+ ENDIF
+ ENDIF
+ XBOT=0.
+ IF(Q2.GT.PMB**2.AND.Q2.GT.1.001*P2EFF) THEN
+ SBT=MAX(0.,LOG(LOG(PMB**2/ALAM**2)/LOG(P2EFF/ALAM**2)))
+ IF(ISET.EQ.0) THEN
+ XBOT=XSEA*(1.-(SBT/SLL)**2)
+ ELSE
+ XBOT=MAX(0.,XSEA-XSEA0*X1**(2.667*S))*(1.-SBT/SLL)
+ ENDIF
+ ENDIF
+C
+C...Fill parton distributions.
+ XPGA(0)=XGLU
+ XPGA(1)=XSEA
+ XPGA(2)=XSEA
+ XPGA(3)=XSEA
+ XPGA(4)=XCHM
+ XPGA(5)=XBOT
+ XPGA(KFA)=XPGA(KFA)+XVAL
+ DO 110 KFL=1,5
+ XPGA(-KFL)=XPGA(KFL)
+ 110 CONTINUE
+ VXPGA(KFA)=XVAL
+ VXPGA(-KFA)=XVAL
+C
+ END
+C
+C*********************************************************************
+C
+ SUBROUTINE SASANO(KF,X,Q2,P2,ALAM,XPGA,VXPGA)
+C...Purpose: to evaluate the parton distributions of the anomalous
+C...photon, inhomogeneously evolved from a scale P2 (where it vanishes)
+C...to Q2.
+C...KF=0 gives the sum over (up to) 5 flavours,
+C...KF<0 limits to flavours up to abs(KF),
+C...KF>0 is for flavour KF only.
+C...ALAM is the 4-flavour Lambda, which is automatically converted
+C...to 3- and 5-flavour equivalents as needed.
+ DIMENSION XPGA(-6:6), VXPGA(-6:6), ALAMSQ(3:5)
+ SAVE PMC,PMB,AEM2PI
+ DATA PMC/1.3/, PMB/4.6/, AEM2PI/0.0011614/
+C
+C...Reset output.
+ DO 100 KFL=-6,6
+ XPGA(KFL)=0.
+ VXPGA(KFL)=0.
+ 100 CONTINUE
+ IF(Q2.LE.P2) RETURN
+ KFA=IABS(KF)
+C
+C...Calculate Lambda; protect against unphysical Q2 and P2 input.
+ ALAMSQ(3)=(ALAM*(PMC/ALAM)**(2./27.))**2
+ ALAMSQ(4)=ALAM**2
+ ALAMSQ(5)=(ALAM*(ALAM/PMB)**(2./23.))**2
+ P2EFF=MAX(P2,1.2*ALAMSQ(3))
+ IF(KF.EQ.4) P2EFF=MAX(P2EFF,PMC**2)
+ IF(KF.EQ.5) P2EFF=MAX(P2EFF,PMB**2)
+ Q2EFF=MAX(Q2,P2EFF)
+ XL=-LOG(X)
+C
+C...Find number of flavours at lower and upper scale.
+ NFP=4
+ IF(P2EFF.LT.PMC**2) NFP=3
+ IF(P2EFF.GT.PMB**2) NFP=5
+ NFQ=4
+ IF(Q2EFF.LT.PMC**2) NFQ=3
+ IF(Q2EFF.GT.PMB**2) NFQ=5
+C
+C...Define range of flavour loop.
+ IF(KF.EQ.0) THEN
+ KFLMN=1
+ KFLMX=5
+ ELSEIF(KF.LT.0) THEN
+ KFLMN=1
+ KFLMX=KFA
+ ELSE
+ KFLMN=KFA
+ KFLMX=KFA
+ ENDIF
+C
+C...Loop over flavours the photon can branch into.
+ DO 110 KFL=KFLMN,KFLMX
+C
+C...Light flavours: calculate t range and (approximate) s range.
+ IF(KFL.LE.3.AND.(KFL.EQ.1.OR.KFL.EQ.KF)) THEN
+ TDIFF=LOG(Q2EFF/P2EFF)
+ S=(6./(33.-2.*NFQ))*LOG(LOG(Q2EFF/ALAMSQ(NFQ))/
+ & LOG(P2EFF/ALAMSQ(NFQ)))
+ IF(NFQ.GT.NFP) THEN
+ Q2DIV=PMB**2
+ IF(NFQ.EQ.4) Q2DIV=PMC**2
+ SNFQ=(6./(33.-2.*NFQ))*LOG(LOG(Q2DIV/ALAMSQ(NFQ))/
+ & LOG(P2EFF/ALAMSQ(NFQ)))
+ SNFP=(6./(33.-2.*(NFQ-1)))*LOG(LOG(Q2DIV/ALAMSQ(NFQ-1))/
+ & LOG(P2EFF/ALAMSQ(NFQ-1)))
+ S=S+(LOG(Q2DIV/P2EFF)/LOG(Q2EFF/P2EFF))*(SNFP-SNFQ)
+ ENDIF
+ IF(NFQ.EQ.5.AND.NFP.EQ.3) THEN
+ Q2DIV=PMC**2
+ SNF4=(6./(33.-2.*4))*LOG(LOG(Q2DIV/ALAMSQ(4))/
+ & LOG(P2EFF/ALAMSQ(4)))
+ SNF3=(6./(33.-2.*3))*LOG(LOG(Q2DIV/ALAMSQ(3))/
+ & LOG(P2EFF/ALAMSQ(3)))
+ S=S+(LOG(Q2DIV/P2EFF)/LOG(Q2EFF/P2EFF))*(SNF3-SNF4)
+ ENDIF
+C
+C...u and s quark do not need a separate treatment when d has been done.
+ ELSEIF(KFL.EQ.2.OR.KFL.EQ.3) THEN
+C
+C...Charm: as above, but only include range above c threshold.
+ ELSEIF(KFL.EQ.4) THEN
+ IF(Q2.LE.PMC**2) GOTO 110
+ P2EFF=MAX(P2EFF,PMC**2)
+ Q2EFF=MAX(Q2EFF,P2EFF)
+ TDIFF=LOG(Q2EFF/P2EFF)
+ S=(6./(33.-2.*NFQ))*LOG(LOG(Q2EFF/ALAMSQ(NFQ))/
+ & LOG(P2EFF/ALAMSQ(NFQ)))
+ IF(NFQ.EQ.5.AND.NFP.EQ.4) THEN
+ Q2DIV=PMB**2
+ SNFQ=(6./(33.-2.*NFQ))*LOG(LOG(Q2DIV/ALAMSQ(NFQ))/
+ & LOG(P2EFF/ALAMSQ(NFQ)))
+ SNFP=(6./(33.-2.*(NFQ-1)))*LOG(LOG(Q2DIV/ALAMSQ(NFQ-1))/
+ & LOG(P2EFF/ALAMSQ(NFQ-1)))
+ S=S+(LOG(Q2DIV/P2EFF)/LOG(Q2EFF/P2EFF))*(SNFP-SNFQ)
+ ENDIF
+C
+C...Bottom: as above, but only include range above b threshold.
+ ELSEIF(KFL.EQ.5) THEN
+ IF(Q2.LE.PMB**2) GOTO 110
+ P2EFF=MAX(P2EFF,PMB**2)
+ Q2EFF=MAX(Q2,P2EFF)
+ TDIFF=LOG(Q2EFF/P2EFF)
+ S=(6./(33.-2.*NFQ))*LOG(LOG(Q2EFF/ALAMSQ(NFQ))/
+ & LOG(P2EFF/ALAMSQ(NFQ)))
+ ENDIF
+C
+C...Evaluate flavour-dependent prefactor (charge^2 etc.).
+ CHSQ=1./9.
+ IF(KFL.EQ.2.OR.KFL.EQ.4) CHSQ=4./9.
+ FAC=AEM2PI*2.*CHSQ*TDIFF
+C
+C...Evaluate parton distributions (normalized to unit momentum sum).
+ IF(KFL.EQ.1.OR.KFL.EQ.4.OR.KFL.EQ.5.OR.KFL.EQ.KF) THEN
+ XVAL= ((1.5+2.49*S+26.9*S**2)/(1.+32.3*S**2)*X**2 +
+ & (1.5-0.49*S+7.83*S**2)/(1.+7.68*S**2)*(1.-X)**2 +
+ & 1.5*S/(1.-3.2*S+7.*S**2)*X*(1.-X)) *
+ & X**(1./(1.+0.58*S)) * (1.-X**2)**(2.5*S/(1.+10.*S))
+ XGLU= 2.*S/(1.+4.*S+7.*S**2) *
+ & X**(-1.67*S/(1.+2.*S)) * (1.-X**2)**(1.2*S) *
+ & ((4.*X**2+7.*X+4.)*(1.-X)/3. - 2.*X*(1.+X)*XL)
+ XSEA= 0.333*S**2/(1.+4.90*S+4.69*S**2+21.4*S**3) *
+ & X**(-1.18*S/(1.+1.22*S)) * (1.-X)**(1.2*S) *
+ & ((8.-73.*X+62.*X**2)*(1.-X)/9. + (3.-8.*X**2/3.)*X*XL +
+ & (2.*X-1.)*X*XL**2)
+C
+C...Threshold factors for c and b sea.
+ SLL=LOG(LOG(Q2EFF/ALAM**2)/LOG(P2EFF/ALAM**2))
+ XCHM=0.
+ IF(Q2.GT.PMC**2.AND.Q2.GT.1.001*P2EFF) THEN
+ SCH=MAX(0.,LOG(LOG(PMC**2/ALAM**2)/LOG(P2EFF/ALAM**2)))
+ XCHM=XSEA*(1.-(SCH/SLL)**3)
+ ENDIF
+ XBOT=0.
+ IF(Q2.GT.PMB**2.AND.Q2.GT.1.001*P2EFF) THEN
+ SBT=MAX(0.,LOG(LOG(PMB**2/ALAM**2)/LOG(P2EFF/ALAM**2)))
+ XBOT=XSEA*(1.-(SBT/SLL)**3)
+ ENDIF
+ ENDIF
+C
+C...Add contribution of each valence flavour.
+ XPGA(0)=XPGA(0)+FAC*XGLU
+ XPGA(1)=XPGA(1)+FAC*XSEA
+ XPGA(2)=XPGA(2)+FAC*XSEA
+ XPGA(3)=XPGA(3)+FAC*XSEA
+ XPGA(4)=XPGA(4)+FAC*XCHM
+ XPGA(5)=XPGA(5)+FAC*XBOT
+ XPGA(KFL)=XPGA(KFL)+FAC*XVAL
+ VXPGA(KFL)=VXPGA(KFL)+FAC*XVAL
+ 110 CONTINUE
+ DO 120 KFL=1,5
+ XPGA(-KFL)=XPGA(KFL)
+ VXPGA(-KFL)=VXPGA(KFL)
+ 120 CONTINUE
+C
+ END
+C
+C*********************************************************************
+C
+ SUBROUTINE SASBEH(KF,X,Q2,P2,PM2,XPBH)
+C...Purpose: to evaluate the Bethe-Heitler cross section for
+C...heavy flavour production.
+ SAVE AEM2PI
+ DATA AEM2PI/0.0011614/
+C
+C...Reset output.
+ XPBH=0.
+ SIGBH=0.
+C
+C...Check kinematics limits.
+ IF(X.GE.Q2/(4.*PM2+Q2+P2)) RETURN
+ W2=Q2*(1.-X)/X-P2
+ BETA2=1.-4.*PM2/W2
+ IF(BETA2.LT.1E-10) RETURN
+ BETA=SQRT(BETA2)
+ RMQ=4.*PM2/Q2
+C
+C...Simple case: P2 = 0.
+ IF(P2.LT.1E-4) THEN
+ IF(BETA.LT.0.99) THEN
+ XBL=LOG((1.+BETA)/(1.-BETA))
+ ELSE
+ XBL=LOG((1.+BETA)**2*W2/(4.*PM2))
+ ENDIF
+ SIGBH=BETA*(8.*X*(1.-X)-1.-RMQ*X*(1.-X))+
+ & XBL*(X**2+(1.-X)**2+RMQ*X*(1.-3.*X)-0.5*RMQ**2*X**2)
+C
+C...Complicated case: P2 > 0, based on approximation of
+C...C.T. Hill and G.G. Ross, Nucl. Phys. B148 (1979) 373
+ ELSE
+ RPQ=1.-4.*X**2*P2/Q2
+ IF(RPQ.GT.1E-10) THEN
+ RPBE=SQRT(RPQ*BETA2)
+ IF(RPBE.LT.0.99) THEN
+ XBL=LOG((1.+RPBE)/(1.-RPBE))
+ XBI=2.*RPBE/(1.-RPBE**2)
+ ELSE
+ RPBESN=4.*PM2/W2+(4.*X**2*P2/Q2)*BETA2
+ XBL=LOG((1.+RPBE)**2/RPBESN)
+ XBI=2.*RPBE/RPBESN
+ ENDIF
+ SIGBH=BETA*(6.*X*(1.-X)-1.)+
+ & XBL*(X**2+(1.-X)**2+RMQ*X*(1.-3.*X)-0.5*RMQ**2*X**2)+
+ & XBI*(2.*X/Q2)*(PM2*X*(2.-RMQ)-P2*X)
+ ENDIF
+ ENDIF
+C
+C...Multiply by charge-squared etc. to get parton distribution.
+ CHSQ=1./9.
+ IF(IABS(KF).EQ.2.OR.IABS(KF).EQ.4) CHSQ=4./9.
+ XPBH=3.*CHSQ*AEM2PI*X*SIGBH
+C
+ END
+C
+C*********************************************************************
+C
+ SUBROUTINE SASDIR(X,Q2,P2,Q02,XPGA)
+C...Purpose: to evaluate the direct contribution, i.e. the C^gamma term,
+C...as needed in MSbar parametrizations.
+ DIMENSION XPGA(-6:6)
+ SAVE AEM2PI
+ DATA AEM2PI/0.0011614/
+C
+C...Reset output.
+ DO 100 KFL=-6,6
+ XPGA(KFL)=0.
+ 100 CONTINUE
+C
+C...Evaluate common x-dependent expression.
+ XTMP = (X**2+(1.-X)**2) * (-LOG(X)) - 1.
+ CGAM = 3.*AEM2PI*X * (XTMP*(1.+P2/(P2+Q02)) + 6.*X*(1.-X))
+C
+C...d, u, s part by simple charge factor.
+ XPGA(1)=(1./9.)*CGAM
+ XPGA(2)=(4./9.)*CGAM
+ XPGA(3)=(1./9.)*CGAM
+C
+C...Also fill for antiquarks.
+ DO 110 KF=1,5
+ XPGA(-KF)=XPGA(KF)
+ 110 CONTINUE
+C
+ END
diff --git a/PDF/SaSPhotonPDF.cc.in b/PDF/SaSPhotonPDF.cc.in
new file mode 100644
--- /dev/null
+++ b/PDF/SaSPhotonPDF.cc.in
@@ -0,0 +1,180 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the SaSPhotonPDF class.
+//
+
+#include "SaSPhotonPDF.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/Interface/Switch.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+#include "ThePEG/PDT/ParticleData.h"
+#include "ThePEG/PDT/EnumParticles.h"
+
+using namespace Herwig;
+
+/* Define to a macro mangling the given C identifier (in lower and upper
+ case), which must not contain underscores, for linking with Fortran. */
+#undef FC_FUNC
+
+extern "C" {
+
+ #define SASGAM_F77 FC_FUNC(sasgam,SASGAM)
+ void SASGAM_F77(int *,float *,float *,float *,int *,float *,float *);
+
+}
+
+bool SaSPhotonPDF::canHandleParticle(tcPDPtr particle) const {
+ // only the photon can be handled
+ return ( particle->id() == ParticleID::gamma );
+}
+
+cPDVector SaSPhotonPDF::partons(tcPDPtr particle) const {
+ // All standard partons can be extracted.
+ cPDVector ret;
+ if ( canHandleParticle(particle) ) {
+ ret.push_back(getParticleData(ParticleID::g));
+ for ( int i = 1; i <= 5; ++i ) {
+ ret.push_back(getParticleData(i));
+ ret.push_back(getParticleData(-i));
+ }
+ }
+ return ret;
+}
+
+double SaSPhotonPDF::xfl(tcPDPtr, tcPDPtr parton, Energy2 partonScale,
+ double l, Energy2 particleScale) const {
+ float x = exp(-l);
+ float q2 = partonScale/GeV2;
+ float p2 = particleScale/GeV2;
+ float f2gm=0.;
+ float xpdf[13];
+ int iloc = parton->id()!=ParticleID::g ? 6+parton->id() : 6;
+ assert(x>=0. && x<=1.);
+ SASGAM_F77(&iset_,&x,&q2,&p2,&ip_,&f2gm,xpdf);
+ // cerr << "testing " << partonScale/GeV2 << " " << particleScale/GeV2 << " " << x << "\n";
+ // for(unsigned int ix=0;ix<13;++ix)
+ // cerr << ix << " " << xpdf[ix] << "\n";
+ // cerr << "testing " << parton->PDGName() << " " << iloc << "\n";
+ return xpdf[iloc];
+}
+
+double SaSPhotonPDF::xfvl(tcPDPtr particle, tcPDPtr parton, Energy2 partonScale,
+ double l, Energy2 particleScale) const {
+ if(parton->id()==ParticleID::g)
+ return 0.;
+ else
+ return xfl(particle,parton,partonScale,l,particleScale);
+}
+
+IBPtr SaSPhotonPDF::clone() const {
+ return new_ptr(*this);
+}
+
+IBPtr SaSPhotonPDF::fullclone() const {
+ return new_ptr(*this);
+}
+
+void SaSPhotonPDF::persistentOutput(PersistentOStream & os) const {
+ os << iset_ << ip_;
+}
+
+void SaSPhotonPDF::persistentInput(PersistentIStream & is, int) {
+ is >> iset_ >> ip_;
+}
+
+
+// The following static variable is needed for the type
+// description system in ThePEG.
+DescribeClass<SaSPhotonPDF,PDFBase>
+describeHerwigSaSPhotonPDF("Herwig::SaSPhotonPDF", "HwSaSPhotonPDF.so");
+
+void SaSPhotonPDF::Init() {
+
+ static ClassDocumentation<SaSPhotonPDF> documentation
+ ("The SaSPhotonPDF class interfaces to the photon PDFs of Schuler and Sjostrand",
+ "The photon PDF of \\cite{Schuler:1995fk} was used.",
+ "\bibitem{Schuler:1995fk}\n"
+ "G.~A.~Schuler and T.~Sjostrand,\n"
+ "%``Low and high mass components of the photon distribution functions,''\n"
+ "Z.\\ Phys.\\ C {\bf 68} (1995) 607\n"
+ "doi:10.1007/BF01565260\n"
+ "[hep-ph/9503384].\n"
+ "%%CITATION = doi:10.1007/BF01565260;\n");
+
+ static Switch<SaSPhotonPDF,int> interfaceIset
+ ("Iset",
+ "The choice of PDF set",
+ &SaSPhotonPDF::iset_, 2, false, false);
+ static SwitchOption interfaceIset1D
+ (interfaceIset,
+ "1D",
+ "SaS set 1D ('DIS', Q0 = 0.6 GeV)",
+ 1);
+ static SwitchOption interfaceIset1M
+ (interfaceIset,
+ "1M",
+ "SaS set 1M ('MSbar', Q0 = 0.6 GeV)",
+ 2);
+ static SwitchOption interfaceIset2D
+ (interfaceIset,
+ "2D",
+ "SaS set 2D ('DIS', Q0 = 2 GeV)",
+ 3);
+ static SwitchOption interfaceIset2M
+ (interfaceIset,
+ "2M",
+ "SaS set 2M ('MSbar', Q0 = 2 GeV)",
+ 4);
+
+ static Switch<SaSPhotonPDF,int> interfaceIP2
+ ("IP2",
+ "scheme used to evaluate off-shell anomalous component.",
+ &SaSPhotonPDF::ip_, 0, false, false);
+ static SwitchOption interfaceIP20
+ (interfaceIP2,
+ "0",
+ "recommended default, see = 7.",
+ 0);
+ static SwitchOption interfaceIP21
+ (interfaceIP2,
+ "1",
+ "dipole dampening by integration; very time-consuming.",
+ 1);
+ static SwitchOption interfaceIP22
+ (interfaceIP2,
+ "2",
+ "P_0^2 = max( Q_0^2, P^2 )",
+ 2);
+ static SwitchOption interfaceIP23
+ (interfaceIP2,
+ "3",
+ "P'_0^2 = Q_0^2 + P^2.",
+ 3);
+ static SwitchOption interfaceIP24
+ (interfaceIP2,
+ "4",
+ "P_{eff} that preserves momentum sum.",
+ 4);
+ static SwitchOption interfaceIP25
+ (interfaceIP2,
+ "5",
+ "P_{int} that preserves momentum and average evolution range.",
+ 5);
+ static SwitchOption interfaceIP26
+ (interfaceIP2,
+ "6",
+ "P_{eff}, matched to P_0 in P2 -> Q2 limit.",
+ 6);
+ static SwitchOption interfaceIP27
+ (interfaceIP2,
+ "7",
+ "P_{eff}, matched to P_0 in P2 -> Q2 limit.",
+ 7);
+
+}
diff --git a/PDF/SaSPhotonPDF.h b/PDF/SaSPhotonPDF.h
new file mode 100644
--- /dev/null
+++ b/PDF/SaSPhotonPDF.h
@@ -0,0 +1,134 @@
+// -*- C++ -*-
+#ifndef Herwig_SaSPhotonPDF_H
+#define Herwig_SaSPhotonPDF_H
+//
+// This is the declaration of the SaSPhotonPDF class.
+//
+
+#include "ThePEG/PDF/PDFBase.h"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * The SaSPhotonPDF class provides an interface to the
+ *
+ * @see \ref SaSPhotonPDFInterfaces "The interfaces"
+ * defined for SaSPhotonPDF.
+ */
+class SaSPhotonPDF: public PDFBase {
+
+public:
+
+ /**
+ * The default constructor.
+ */
+ SaSPhotonPDF() : iset_(2), ip_(0) {}
+
+public:
+
+ /** @name Virtual functions to be overridden by sub-classes. */
+ //@{
+ /**
+ * Return true if this PDF can handle the extraction of partons from
+ * the given \a particle.
+ */
+ virtual bool canHandleParticle(tcPDPtr particle) const;
+
+ /**
+ * Return the partons which this PDF may extract from the given
+ * \a particle.
+ */
+ virtual cPDVector partons(tcPDPtr particle) const;
+
+ /**
+ * The density. Return the pdf for the given \a parton inside the
+ * given \a particle for the virtuality \a partonScale and
+ * logarithmic momentum fraction \a l \f$(l=\log(1/x)\$f. The \a
+ * particle is assumed to have a virtuality \a particleScale.
+ */
+ virtual double xfl(tcPDPtr particle, tcPDPtr parton, Energy2 partonScale,
+ double l, Energy2 particleScale = 0.0*GeV2) const;
+
+ /**
+ * The valence density. Return the pdf for the given cvalence \a
+ * parton inside the given \a particle for the virtuality \a
+ * partonScale and logarithmic momentum fraction \a l
+ * \f$(l=\log(1/x)\$f. The \a particle is assumed to have a
+ * virtuality \a particleScale. If not overidden by a sub class this
+ * will return zero.
+ */
+ virtual double xfvl(tcPDPtr particle, tcPDPtr parton, Energy2 partonScale,
+ double l, Energy2 particleScale = 0.0*GeV2) const;
+ //@}
+
+
+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.
+ */
+ SaSPhotonPDF & operator=(const SaSPhotonPDF &);
+
+private:
+
+ /**
+ * PDF Set
+ */
+ mutable int iset_;
+
+ /**
+ * Scheme used to evaluate off-shell anomalous component.
+ */
+ mutable int ip_;
+
+};
+
+}
+
+#endif /* Herwig_SaSPhotonPDF_H */
diff --git a/PDT/StandardMatchers.cc b/PDT/StandardMatchers.cc
--- a/PDT/StandardMatchers.cc
+++ b/PDT/StandardMatchers.cc
@@ -1,30 +1,31 @@
// -*- C++ -*-
//
// StandardMatchers.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// Ensures the StandardMatchers get created
//
#include "ThePEG/PDT/Matcher.h"
#include "ThePEG/PDT/StandardMatchers.h"
#include "StandardMatchers.h"
using namespace Herwig;
using namespace ThePEG;
namespace {
static MatchPhoton m00;
static MatchBottom m01;
static MatchTop m02;
static MatchHadron m03;
static MatchWBoson m04;
static MatchZBoson m05;
static MatchHiggsBoson m06;
static MatchChargedLepton m07;
+ static MatchLightParticle m08;
}
diff --git a/PDT/StandardMatchers.h b/PDT/StandardMatchers.h
--- a/PDT/StandardMatchers.h
+++ b/PDT/StandardMatchers.h
@@ -1,210 +1,231 @@
// -*- C++ -*-
//
// StandardMatchers.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_StandardMatchers_H
#define Herwig_StandardMatchers_H
// This is the declaration of the AnyMatcher,
#include "ThePEG/PDT/Matcher.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "ThePEG/PDF/BeamParticleData.h"
#include "ThePEG/PDT/EnumParticles.h"
namespace Herwig {
using namespace ThePEG;
/**
*
* This file declare a set of standard matcher classes in addition to those
* defined in ThePEG. The classes can be used by themselves (with
* their static functions) or together with the Matcher class to
* define Interfaced objects of the MatcherBase type to be used in the
* Repository. Suitable typedefs are declared for the latter.
*
* @see Matcher
* @see MatcherBase
*/
/**
* A Matcher class which matches photons
*/
struct PhotonMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef PhotonMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return pd.id()==ParticleID::gamma;
}
/** A simplified but unique class name. */
static string className() { return "Photon"; }
};
/**
* Gives a MatcherBase class based on PhotonMatcher.
*/
typedef Matcher<PhotonMatcher> MatchPhoton;
/**
* A Matcher class which matches top quarks
*/
struct TopMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef TopMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return abs(pd.id())==ParticleID::t;
}
/** A simplified but unique class name. */
static string className() { return "Top"; }
};
/**
* Gives a MatcherBase class based on TopMatcher.
*/
typedef Matcher<TopMatcher> MatchTop;
/**
* A Matcher class which matches bottom quarks
*/
struct BottomMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef BottomMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return abs(pd.id())==ParticleID::b;
}
/** A simplified but unique class name. */
static string className() { return "Bottom"; }
};
/**
* Gives a MatcherBase class based on BottomMatcher.
*/
typedef Matcher<BottomMatcher> MatchBottom;
/**
* A Matcher class which matches any hadron.
*/
struct HadronMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef HadronMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
if (pd.id() != ParticleID::gamma) return Check(pd.id());
else {
Ptr<BeamParticleData>::const_pointer beam =
dynamic_ptr_cast< Ptr<BeamParticleData>::const_pointer>(&pd);
return beam && beam->pdf();
}
}
/** The main static function to check if a given particle with type
\a id matches. */
static bool Check(long id) {
bool hadron = (id/10)%10 && (id/100)%10;
if(hadron) return true;
// special for gamma when acting like a hadron
if (id != ParticleID::gamma) return false;
tcPDPtr gamma = CurrentGenerator::current().getParticleData(ParticleID::gamma);
Ptr<BeamParticleData>::const_pointer beam =
dynamic_ptr_cast< Ptr<BeamParticleData>::const_pointer>(gamma);
return beam && beam->pdf();
}
/** A simplified but unique class name. */
static string className() { return "Hadron"; }
};
/** Gives a MatcherBase class based on HadronMatcher. */
typedef Matcher<HadronMatcher> MatchHadron;
/**
* A Matcher class which matches W bosons
*/
struct WBosonMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef WBosonMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return abs(pd.id())==ParticleID::Wplus;
}
/** A simplified but unique class name. */
static string className() { return "WBoson"; }
};
/**
* Gives a MatcherBase class based on WBosonMatcher.
*/
typedef Matcher<WBosonMatcher> MatchWBoson;
/**
* A Matcher class which matches Z bosons
*/
struct ZBosonMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef ZBosonMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return abs(pd.id())==ParticleID::Z0;
}
/** A simplified but unique class name. */
static string className() { return "ZBoson"; }
};
/**
* Gives a MatcherBase class based on ZBosonMatcher.
*/
typedef Matcher<ZBosonMatcher> MatchZBoson;
/**
* A Matcher class which matches Higgs bosons
*/
struct HiggsBosonMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef HiggsBosonMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return abs(pd.id())==ParticleID::h0;
}
/** A simplified but unique class name. */
static string className() { return "HiggsBoson"; }
};
/**
* Gives a MatcherBase class based on HiggsBosonMatcher.
*/
typedef Matcher<HiggsBosonMatcher> MatchHiggsBoson;
/**
* A Matcher class which matches any charged lepton.
*/
struct ChargedLeptonMatcher: public MatcherType {
/** Typedef the class matching the complex conjugate particles. */
typedef ChargedLeptonMatcher CC;
/** The main static function to check if a given particle type \a pd
matches. */
static bool Check(const ParticleData & pd) {
return Check(pd.id());
}
static bool Check(long id) {
return abs(id) > 10 && abs(id) <= 20 && abs(id)%2!=0;
}
/** A simplified but unique class name. */
static string className() { return "ChargedLepton"; }
};
/** Gives a MatcherBase class based on ChargedLeptonMatcher. */
typedef Matcher<ChargedLeptonMatcher> MatchChargedLepton;
+
+/**
+ * A Matcher class which matches any light (<1GeV) particles other than the photon
+ */
+struct LightParticleMatcher: public MatcherType {
+ /** Typedef the class matching the complex conjugate particles. */
+ typedef LightParticleMatcher CC;
+ /** The main static function to check if a given particle type \a pd
+ matches. */
+ static bool Check(const ParticleData & pd) {
+ return pd.id()!=22 && abs(pd.id()) > 6 && abs(pd.id())!=11 &&
+ abs(pd.id())!=13 && abs(pd.id())!=15 && abs(pd.mass())<=GeV;
+ }
+ /** A simplified but unique class name. */
+ static string className() { return "LightParticle"; }
+};
+
+/**
+ * Gives a MatcherBase class based on LightParticleatcher.
+ */
+typedef Matcher<LightParticleMatcher> MatchLightParticle;
+
}
-
#endif /* Herwig_StandardMatchers_H */
diff --git a/README b/README
--- a/README
+++ b/README
@@ -1,14 +1,14 @@
========
Herwig 7
========
-This is the release of Herwig 7.1.2, a multi purpose event
+This is the release of Herwig 7.1.3, a multi purpose event
generator for high energy physics.
The Herwig++ distribution contains an adapted version of LoopTools 2.6
<http://www.feynarts.de/looptools/>.
BUILD AND INSTALL
=================
Please refer to https://herwig.hepforge.org/tutorials/ for detailed
instructions.
diff --git a/Shower/Dipole/AlphaS/alpha_s.cc b/Shower/Dipole/AlphaS/alpha_s.cc
--- a/Shower/Dipole/AlphaS/alpha_s.cc
+++ b/Shower/Dipole/AlphaS/alpha_s.cc
@@ -1,236 +1,236 @@
// -*- C++ -*-
// couplings/alpha_s.cc is part of matchbox
// (C) 2008 Simon Platzer -- sp@particle.uni-karlsruhe.de
#include "alpha_s.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Command.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/Repository.h"
#include "ThePEG/PDT/ParticleData.h"
using namespace matchbox;
alpha_s::alpha_s()
: AlphaSBase(), min_active_flavours_(3), max_active_flavours_(6),
matched_(false), scale_factor_(1.), quark_masses_squared_(),
lambda_squared_(), alpha_s_in_(.1176), scale_in_(91.1876*GeV),
lambda_range_(1.*MeV2,1.e6*MeV2), fixed_(false) {
}
alpha_s::~alpha_s() {}
void alpha_s::persistentOutput(PersistentOStream & os) const {
os << min_active_flavours_ << max_active_flavours_ << matched_ << scale_factor_;
for (size_t f = 0; f < 7; ++f)
os << ounit(quark_masses_squared_[f],MeV2)
<< ounit(lambda_squared_[f],MeV2);
for (size_t f = 0; f < 6; ++f)
os << ounit(nfvector[f],MeV2);
os << alpha_s_in_ << ounit(scale_in_,GeV)
<< ounit(lambda_range_.first,MeV2) << ounit(lambda_range_.second,MeV2)
<< fixed_;
}
void alpha_s::persistentInput(PersistentIStream & is, int) {
is >> min_active_flavours_ >> max_active_flavours_ >> matched_ >> scale_factor_;
for (size_t f = 0; f < 7; ++f)
is >> iunit(quark_masses_squared_[f],MeV2)
>> iunit(lambda_squared_[f],MeV2);
for (size_t f = 0; f < 6; ++f)
is >> iunit(nfvector[f],MeV2);
is >> alpha_s_in_ >> iunit(scale_in_,GeV)
>> iunit(lambda_range_.first,MeV2) >> iunit(lambda_range_.second,MeV2)
>> fixed_;
}
AbstractClassDescription<alpha_s> alpha_s::initalpha_s;
// Definition of the static class description member.
void alpha_s::Init() {
static ClassDocumentation<alpha_s> documentation
("Base class for strong coupoling as used in matchbox");
static Parameter<alpha_s,unsigned int> interfacemin_active_flavours
("min_active_flavours",
"Minimum number of active flavours",
&alpha_s::min_active_flavours_, 3, 0, 6,
true, false, Interface::limited);
static Parameter<alpha_s,unsigned int> interfacemax_active_flavours
("max_active_flavours",
"Maximum number of active flavours",
&alpha_s::max_active_flavours_, 6, 0, 6,
true, false, Interface::limited);
static Parameter<alpha_s,double> interfaceinput_alpha_s
("input_alpha_s",
"alpha_s value at input scale",
&alpha_s::alpha_s_in_, .1176, 0.0, 1.0,
true, false, Interface::limited);
static Parameter<alpha_s,Energy> interfaceinput_scale
("input_scale",
"Input scale for alpha_s value",
&alpha_s::scale_in_, GeV, 91.1876*GeV, 0.*GeV, 0.*GeV,
true, false, Interface::lowerlim);
static Command<alpha_s> interfacecheck
("check",
"check",
&alpha_s::check, false);
static Parameter<alpha_s,double> interfacescale_factor
("scale_factor",
"scale factor for argument",
&alpha_s::scale_factor_, 1., 0.0, 100.0,
true, false, Interface::limited);
static Switch<alpha_s,bool> interfacefixed
("fixed",
"",
&alpha_s::fixed_, false, false, false);
static SwitchOption interfacefixedYes
(interfacefixed,
"Yes",
"",
true);
static SwitchOption interfacefixedNo
(interfacefixed,
"No",
"",
false);
}
string alpha_s::check (string args) {
istringstream argin(args);
double Q_low, Q_high;
long n_steps;
argin >> Q_low >> Q_high >> n_steps;
string fname;
argin >> fname;
- generator()->log() << "checking alpha_s in range [" << Q_low << "," << Q_high << "] GeV in "
- << n_steps << " steps.\nResults are written to " << fname << "\n";
+ Repository::clog() << "checking alpha_s in range [" << Q_low << "," << Q_high << "] GeV in "
+ << n_steps << " steps.\nResults are written to " << fname << "\n";
double step_width = (Q_high-Q_low)/n_steps;
match_thresholds();
- generator()->log() << "threshold matching results:\n"
- << "(m_Q^2 -> Lambda^2) / GeV^2 for dynamic flavours in range ["
- << min_active_flavours_ << "," << max_active_flavours_ << "]\n";
+ Repository::clog() << "threshold matching results:\n"
+ << "(m_Q^2 -> Lambda^2) / GeV^2 for dynamic flavours in range ["
+ << min_active_flavours_ << "," << max_active_flavours_ << "]\n";
for (size_t f = 0; f < 7; ++f) {
- generator()->log() << (quark_masses_squared_[f]/GeV2) << " "
- << (lambda_squared_[f]/GeV2) << "\n";
+ Repository::clog() << (quark_masses_squared_[f]/GeV2) << " "
+ << (lambda_squared_[f]/GeV2) << "\n";
}
ofstream out (fname.c_str());
for (long k = 0; k <= n_steps; ++k) {
Energy Q = Q_low*GeV + k*step_width*GeV;
out << (Q/GeV) << " " << (operator () (Q*Q)) << "\n";
}
return "alpha_s check finished";
}
void alpha_s::match_thresholds () {
if (matched_)
return;
// get the quark masses
quark_masses_squared_[0] = 0.*MeV2;
for (long f = 1; f < 7; ++f) {
if ( quarkMasses().empty() )
quark_masses_squared_[static_cast<size_t>(f)]
= sqr(getParticleData(f)->mass());
else
quark_masses_squared_[static_cast<size_t>(f)]
= sqr(quarkMasses()[static_cast<size_t>(f-1)]);
}
if ( quark_masses_squared_[1] > quark_masses_squared_[2] )
swap(quark_masses_squared_[1],quark_masses_squared_[2]);
unsigned int active_at_input = active_flavours(sqr(scale_in_));
// solve for input lambda
solve_input_lambda<alpha_s> input_equation (this,active_at_input,alpha_s_in_,sqr(scale_in_));
gsl::bisection_root_solver<solve_input_lambda<alpha_s>,100> input_solver(input_equation);
lambda_squared_[active_at_input] =
MeV2 *
input_solver.solve({lambda_range_.first/MeV2,lambda_range_.second/MeV2});
// get lambdas down to min active flavours
unsigned int below = active_at_input;
while (below > min_active_flavours_) {
solve_lambda_below<alpha_s> match_equation (this,below,
lambda_squared_[below],
quark_masses_squared_[below]);
gsl::bisection_root_solver<solve_lambda_below<alpha_s>,100> match_solver(match_equation);
lambda_squared_[below-1] =
MeV2 *
match_solver.solve({lambda_range_.first/MeV2,lambda_range_.second/MeV2});
--below;
}
// get lambdas up to max active flavours
unsigned int above = active_at_input;
while (above < max_active_flavours_) {
solve_lambda_above<alpha_s> match_equation (this,above,
lambda_squared_[above],
quark_masses_squared_[above+1]);
gsl::bisection_root_solver<solve_lambda_above<alpha_s>,100> match_solver(match_equation);
lambda_squared_[above+1] =
MeV2 *match_solver.solve({lambda_range_.first/MeV2,lambda_range_.second/MeV2});
++above;
}
if (min_active_flavours_ > 0) {
for (size_t f = 0; f < min_active_flavours_; ++f) {
lambda_squared_[f] = lambda_squared_[min_active_flavours_];
}
}
if (max_active_flavours_ < 6) {
for (size_t f = max_active_flavours_+1; f < 7; ++f) {
lambda_squared_[f] = lambda_squared_[max_active_flavours_];
}
}
matched_ = true;
return;
}
diff --git a/Shower/Dipole/Base/Dipole.cc b/Shower/Dipole/Base/Dipole.cc
--- a/Shower/Dipole/Base/Dipole.cc
+++ b/Shower/Dipole/Base/Dipole.cc
@@ -1,407 +1,438 @@
// -*- C++ -*-
//
// Dipole.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the Dipole class.
//
#include "Dipole.h"
#include "Herwig/Shower/Dipole/Utility/DipolePartonSplitter.h"
using namespace Herwig;
Dipole::Dipole()
: theParticles(), thePDFs(),
theFractions(1.0,1.0), theIndices(),
- theScales(0.0*GeV,0.0*GeV),
- theDecaying(false,false) {}
+ theDecaying(false,false),
+ theOffShell(false,false),
+ theScales(0.0*GeV,0.0*GeV) {}
Dipole::Dipole(const pair<PPtr,PPtr>& newParticles,
const pair<PDF,PDF>& newPDFs,
pair<double,double> newFractions,
pair<Energy,Energy> newScales)
: theParticles(newParticles),
thePDFs(newPDFs),
theFractions(newFractions), theIndices(),
- theScales(newScales),
- theDecaying(false,false) {
+ theDecaying(false,false),
+ theOffShell(false,false),
+ theScales(newScales) {
theIndices.first = DipoleIndex(theParticles.first->dataPtr(),
theParticles.second->dataPtr(),
newPDFs.first,newPDFs.second,
- theDecaying.first,theDecaying.second);
+ theDecaying.first,theDecaying.second,
+ theOffShell.first,theOffShell.second);
theIndices.second = theIndices.first;
theIndices.second.swap();
}
Dipole::Dipole(const pair<PPtr,PPtr>& newParticles,
const pair<PDF,PDF>& newPDFs,
pair<double,double> newFractions,
pair<bool,bool> decaying,
+ pair<bool,bool> offShell,
pair<Energy,Energy> newScales)
: theParticles(newParticles),
thePDFs(newPDFs),
theFractions(newFractions), theIndices(),
- theScales(newScales),
- theDecaying(decaying) {
+ theDecaying(decaying),
+ theOffShell(offShell),
+ theScales(newScales) {
theIndices.first = DipoleIndex(theParticles.first->dataPtr(),
theParticles.second->dataPtr(),
newPDFs.first,newPDFs.second,
- theDecaying.first,theDecaying.second);
+ theDecaying.first,theDecaying.second,
+ theOffShell.first,theOffShell.second);
theIndices.second = theIndices.first;
theIndices.second.swap();
}
void Dipole::update() {
theIndices.first = DipoleIndex(theParticles.first->dataPtr(),
theParticles.second->dataPtr(),
thePDFs.first,thePDFs.second,
- theDecaying.first,theDecaying.second);
+ theDecaying.first,theDecaying.second,
+ theOffShell.first,theOffShell.second);
theIndices.second = theIndices.first;
theIndices.second.swap();
assert(DipolePartonSplitter::colourConnected(theParticles.first,
theParticles.second));
}
pair<Dipole,Dipole> Dipole::split(DipoleSplittingInfo& dsplit,
bool colourSpectator) const {
// check contracts
assert(dsplit.splittingKinematics());
assert(dsplit.emitterData() && dsplit.emissionData() && dsplit.spectatorData());
if ( !colourSpectator ) {
assert(index(dsplit.configuration()) == dsplit.index());
assert(emitterX(dsplit.configuration()) == dsplit.emitterX());
assert(spectatorX(dsplit.configuration()) == dsplit.spectatorX());
} else {
assert(emitterX(dsplit.configuration()) == dsplit.emitterX());
assert(emitterPDF(dsplit.configuration()) == dsplit.index().emitterPDF());
assert((dsplit.configuration().first ?
theParticles.first->dataPtr() :
theParticles.second->dataPtr())
== dsplit.index().emitterData());
}
// generate full kinematics
dsplit.splittingKinematics()->generateKinematics(
emitter(dsplit.configuration())->momentum(),
spectator(dsplit.configuration())->momentum(),
dsplit);
// Treat the case of decay splittings as backward evolution.
// i.e. Put the new emitter and new emission or new spectator
// and new emission respectively into the new dipoles.
bool emitter_decay = dsplit.index().incomingDecayEmitter();
+ if ( emitter_decay )
+ assert(false);
bool spectator_decay = dsplit.index().incomingDecaySpectator();
-
+
tPPtr oldSpectator = spectator(dsplit.configuration());
PPtr newSpectator;
// get a new spectator
if ( !colourSpectator ) {
newSpectator =
dsplit.spectatorData()->produceParticle(
dsplit.splittingKinematics()->lastSpectatorMomentum());
DipolePartonSplitter::change(oldSpectator,
newSpectator,
spectatorPDF(dsplit.configuration()).pdf(), spectator_decay);
dsplit.spectator(oldSpectator);
dsplit.splitSpectator(newSpectator);
} else {
newSpectator = oldSpectator;
}
// perform the splitting
tPPtr oldEmitter = emitter(dsplit.configuration());
PPtr newEmitter =
dsplit.emitterData()->produceParticle(
dsplit.splittingKinematics()->lastEmitterMomentum());
PPtr newEmission =
dsplit.emissionData()->produceParticle(
dsplit.splittingKinematics()->lastEmissionMomentum());
newEmitter->scale(sqr(dsplit.lastPt()));
newEmission->scale(sqr(dsplit.lastPt()));
newSpectator->scale(oldSpectator->scale());
DipolePartonSplitter::split(oldEmitter,newEmitter,newEmission,
oldSpectator,emitterPDF(dsplit.configuration()).pdf(), emitter_decay);
dsplit.emitter(oldEmitter);
dsplit.splitEmitter(newEmitter);
dsplit.emission(newEmission);
double emitter_x = emitterX(dsplit.configuration()) / dsplit.lastEmitterZ();
double spectator_x = spectatorX(dsplit.configuration()) / dsplit.lastSpectatorZ();
PDF emitter_pdf = emitterPDF(dsplit.configuration());
PDF spectator_pdf = spectatorPDF(dsplit.configuration());
+ // Communicate off-shell parton flags
+ // Note that as gluons aren't off-shell, the only possibility
+ // in qcd splittings is gluon emissions off an off-shell emitter
+ // -> off-shell emitter => off-shell new emitter
+ bool emitter_off_shell = dsplit.index().offShellEmitter();
+ bool spectator_off_shell = dsplit.index().offShellSpectator();
+
// now check how we need to arrange the children
// assignment is 0 = emitter, 1 = emission, 2 = spectator
int left = 0;
int middle = 1;
int right = 2;
if (dsplit.configuration().first) {
// spectator is unique
right = 2;
// middle is the one connecting to the spectator
if (DipolePartonSplitter::colourConnected(newSpectator,newEmission)) {
middle = 1;
left = 0;
} else {
assert(DipolePartonSplitter::colourConnected(newSpectator,newEmitter));
middle = 0;
left = 1;
}
} else {
// spectator is unique
left = 2;
// middle is the one connecting to the spectator
if (DipolePartonSplitter::colourConnected(newSpectator,newEmission)) {
middle = 1;
right = 0;
} else {
assert(DipolePartonSplitter::colourConnected(newSpectator,newEmitter));
middle = 0;
right = 1;
}
}
pair<PPtr,PPtr> left_particles;
pair<PPtr,PPtr> right_particles;
pair<PDF,PDF> left_pdfs;
pair<PDF,PDF> right_pdfs;
pair<double,double> left_fractions;
pair<double,double> right_fractions;
// Pairs containing indicators for decayed particles
pair<bool,bool> left_decays = {false,false};
pair<bool,bool> right_decays = {false,false};
+ // Pairs containing indicators for off-shell particles
+ pair<bool, bool> left_off_shells = {false,false};
+ pair<bool, bool> right_off_shells = {false,false};
+
switch (left) {
case 0:
if (emitter_decay) {
assert(false);
left_decays.first = emitter_decay;
}
left_particles.first = newEmitter;
left_pdfs.first = emitter_pdf;
left_fractions.first = emitter_x;
+ left_off_shells.first = emitter_off_shell;
break;
case 1:
left_particles.first = newEmission;
left_pdfs.first = PDF();
left_fractions.first = 1.;
left_decays.first = false;
+ left_off_shells.first = false;
break;
case 2:
left_particles.first = newSpectator;
left_pdfs.first = spectator_pdf;
left_fractions.first = spectator_x;
left_decays.first = spectator_decay;
+ left_off_shells.first = spectator_off_shell;
break;
-
}
switch (middle) {
case 0:
if (emitter_decay) {
assert(false);
left_decays.second = emitter_decay;
}
left_particles.second = newEmitter;
left_pdfs.second = emitter_pdf;
left_fractions.second = emitter_x;
+ left_off_shells.second = emitter_off_shell;
break;
case 1:
left_particles.second = newEmission;
left_pdfs.second = PDF();
left_fractions.second = 1.;
left_decays.second = false;
+ left_off_shells.second = false;
break;
case 2:
left_decays.second = spectator_decay;
left_particles.second = newSpectator;
left_pdfs.second = spectator_pdf;
left_fractions.second = spectator_x;
+ left_off_shells.second = spectator_off_shell;
break;
}
right_particles.first = left_particles.second;
right_pdfs.first = left_pdfs.second;
right_fractions.first = left_fractions.second;
right_decays.first = left_decays.second;
+ right_off_shells.first = left_off_shells.second;
switch (right) {
case 0:
if (emitter_decay) {
assert(false);
right_decays.second = emitter_decay;
}
right_particles.second = newEmitter;
right_pdfs.second = emitter_pdf;
right_fractions.second = emitter_x;
+ right_off_shells.second = emitter_off_shell;
break;
case 1:
right_particles.second = newEmission;
right_pdfs.second = PDF();
right_fractions.second = 1.;
right_decays.second = false;
+ right_off_shells.second = false;
break;
case 2:
right_particles.second = newSpectator;
right_pdfs.second = spectator_pdf;
right_fractions.second = spectator_x;
right_decays.second = spectator_decay;
+ right_off_shells.second = spectator_off_shell;
break;
}
Energy scale = dsplit.lastPt();
- return { Dipole(left_particles,left_pdfs,left_fractions,left_decays,{scale,scale}),
- Dipole(right_particles,right_pdfs,right_fractions,right_decays,{scale,scale})};
+ return { Dipole(left_particles, left_pdfs, left_fractions,
+ left_decays, left_off_shells, {scale,scale}),
+ Dipole(right_particles, right_pdfs, right_fractions,
+ right_decays, right_off_shells, {scale,scale})};
}
void Dipole::tmpsplit(DipoleSplittingInfo& dsplit,
bool colourSpectator) const {
// generate full kinematics
dsplit.splittingKinematics()->generateKinematics(emitter(dsplit.configuration())->momentum(),
spectator(dsplit.configuration())->momentum(),
dsplit);
tPPtr oldSpectator = spectator(dsplit.configuration());
PPtr newSpectator;
// get a new spectator
if ( !colourSpectator ) {
newSpectator =
dsplit.spectatorData()->produceParticle(dsplit.splittingKinematics()->lastSpectatorMomentum());
dsplit.spectator(oldSpectator);
dsplit.splitSpectator(newSpectator);
} else {
newSpectator = oldSpectator;
}
// perform the splitting
tPPtr oldEmitter = emitter(dsplit.configuration());
PPtr newEmitter =
dsplit.emitterData()->produceParticle(dsplit.splittingKinematics()->lastEmitterMomentum());
PPtr newEmission =
dsplit.emissionData()->produceParticle(dsplit.splittingKinematics()->lastEmissionMomentum());
dsplit.emitter(oldEmitter);
dsplit.splitEmitter(newEmitter);
dsplit.emission(newEmission);
}
void Dipole::recoil (DipoleSplittingInfo& dsplit) {
// check contracts
assert(dsplit.splittingKinematics());
assert(dsplit.spectatorData());
assert(spectatorX(dsplit.spectatorConfiguration())
== dsplit.spectatorX());
assert(spectatorPDF(dsplit.spectatorConfiguration())
== dsplit.index().spectatorPDF());
assert((dsplit.spectatorConfiguration().first ?
theParticles.first->dataPtr() :
theParticles.second->dataPtr())
== dsplit.index().spectatorData());
tPPtr oldSpectator = spectator(dsplit.spectatorConfiguration());
PPtr newSpectator =
dsplit.spectatorData()->produceParticle(
dsplit.splittingKinematics()->lastSpectatorMomentum());
DipolePartonSplitter::change(oldSpectator,newSpectator,
spectatorPDF(dsplit.spectatorConfiguration()).pdf());
newSpectator->scale(sqr(dsplit.lastPt()));
dsplit.spectator(oldSpectator);
dsplit.splitSpectator(newSpectator);
if ( dsplit.spectatorConfiguration().first ) {
theParticles.second = newSpectator;
theFractions.second /= dsplit.lastSpectatorZ();
} else {
theParticles.first = newSpectator;
theFractions.first /= dsplit.lastSpectatorZ();
}
}
void Dipole::print(ostream& os) const {
os << "--- ";
// Check for decays first
if ( theDecaying.first || theDecaying.second) {
assert(!(theDecaying.first && theDecaying.second));
if ( theDecaying.first && !theDecaying.second )
os << "Decay IF";
else if ( theDecaying.second && !theDecaying.first )
os << "Decay FI";
}
else if ( !thePDFs.first.pdf() && !thePDFs.second.pdf() )
os << "FF";
else if ( thePDFs.first.pdf() && !thePDFs.second.pdf() )
os << "IF";
else if ( !thePDFs.first.pdf() && thePDFs.second.pdf() )
os << "FI";
else
os << "II";
os << " Dipole ------------------------------------------------------------------\n";
if ( !theParticles.first || !theParticles.second ) {
os << " *** This Dipole has not been setup properly. ***\n";
} else {
os << " particles\n"
<< *theParticles.first
<< *theParticles.second;
os << " scales/GeV = ("
<< (theScales.first/GeV) << ","
<< (theScales.second/GeV) << ") fractions = ("
<< theFractions.first << "," << theFractions.second << ")\n";
}
os << "--------------------------------------------------------------------------------\n";
os << flush;
}
diff --git a/Shower/Dipole/Base/Dipole.h b/Shower/Dipole/Base/Dipole.h
--- a/Shower/Dipole/Base/Dipole.h
+++ b/Shower/Dipole/Base/Dipole.h
@@ -1,321 +1,337 @@
// -*- C++ -*-
//
// Dipole.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_Dipole_H
#define HERWIG_Dipole_H
//
// This is the declaration of the Dipole class.
//
#include "Herwig/Shower/Dipole/Kinematics/DipoleSplittingKinematics.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer, Stephen Webster, Johannes Bellm
*
* \brief The Dipole class is used by the dipole shower to
* represent a dipole of two coloured partons.
*
*/
class Dipole {
public:
/**
* The default constructor
*/
Dipole();
/**
* The standard constructor
*/
Dipole(const pair<PPtr,PPtr>& newParticles,
const pair<PDF,PDF>& newPDFs,
pair<double,double> newFractions,
pair<Energy,Energy> newScales);
/**
* The standard constructor
*/
Dipole(const pair<PPtr,PPtr>& newParticles,
const pair<PDF,PDF>& newPDFs,
pair<double,double> newFractions,
const pair<bool,bool> decaying = pair<bool,bool>(false,false),
+ const pair<bool,bool> offShell = pair<bool,bool>(false,false),
pair<Energy,Energy> newScales = pair<Energy,Energy>(ZERO,ZERO));
public:
/**
* Get the left particle.
*/
tPPtr leftParticle() const { return theParticles.first; }
/**
* Get the right particle.
*/
tPPtr rightParticle() const { return theParticles.second; }
/**
* Get the left PDF.
*/
const PDF& leftPDF() const { return thePDFs.first; }
/**
* Get the right PDF.
*/
const PDF& rightPDF() const { return thePDFs.second; }
/**
* Get the left fraction.
*/
double leftFraction() const { return theFractions.first; }
/**
* Get the right fraction.
*/
double rightFraction() const { return theFractions.second; }
/**
* Get the bool indicating
* incoming decay for the left
* particle, for debugging only.
*/
bool leftDecaying() { return theDecaying.first; }
/**
* Get the bool indicating
* incoming decay for the right
* particle, for debugging only.
*/
bool rightDecaying() { return theDecaying.second; }
-
/**
* Set the left particle.
*/
void leftParticle(PPtr p) { theParticles.first = p; }
/**
* Set the right particle.
*/
void rightParticle(PPtr p) { theParticles.second = p; }
/**
* Set the left PDF
*/
void leftPDF(const PDF& p) { thePDFs.first = p; }
/**
* Set the right PDF
*/
void rightPDF(const PDF& p) { thePDFs.second = p; }
/**
* Set the momentum fraction for the left particle.
*/
void leftFraction(double x) { theFractions.first = x; }
/**
* Set the momentum fraction for the right particle.
*/
void rightFraction(double x) { theFractions.second = x; }
/**
* Get the scale for the left particle.
*/
Energy leftScale() const { return theScales.first; }
/**
* Set the scale for the left particle.
*/
void leftScale(Energy s) { theScales.first = s; }
/**
* Get the scale for the right particle.
*/
Energy rightScale() const { return theScales.second; }
/**
* Set the scale for the right particle.
*/
void rightScale(Energy s) { theScales.second = s; }
/**
* Set the decayed particle indicator
* for the left particle
*/
void leftDecaying(bool decaying) { theDecaying.first = decaying; }
/**
* Set the decayed particle indicator
* for the right particle
*/
void rightDecaying(bool decaying) { theDecaying.second = decaying; }
/**
* Update information, if modified.
*/
void update();
public:
/**
* Return the dipole index for the selected
* emitter-spectator assignment.
*/
const DipoleIndex& index(pair<bool,bool> conf) const {
return conf.first ? theIndices.first : theIndices.second;
}
/**
+ * Set the first index
+ */
+ void setFirstIndex(DipoleIndex s){theIndices.first=s;}
+
+ /**
+ * Set the first index
+ */
+ void setSecondIndex(DipoleIndex s){theIndices.second=s;}
+
+ /**
* Return the emitter particle for the
* selected configuration.
*/
tPPtr emitter(pair<bool,bool> conf) const {
return conf.first ? theParticles.first : theParticles.second;
}
/**
* Return the spectator particle for the
* selected configuration.
*/
tPPtr spectator(pair<bool,bool> conf) const {
return conf.first ? theParticles.second : theParticles.first;
}
/**
* Return the scale associated to the emitter
* for the selected configuration.
*/
Energy emitterScale(pair<bool,bool> conf) const {
return conf.first ? theScales.first : theScales.second;
}
/**
* Set the scale associated to the emitter
* for the selected configuration.
*/
void emitterScale(pair<bool,bool> conf, Energy scale) {
(conf.first ? theScales.first : theScales.second) = scale;
}
/**
* Return the momentum fraction of the emitter
* for the selected configuration.
*/
double emitterX(pair<bool,bool> conf) const {
return conf.first ? theFractions.first : theFractions.second;
}
/**
* Return the PDF of the emitter
* for the selected configuration.
*/
const PDF& emitterPDF(pair<bool,bool> conf) const {
return conf.first ? thePDFs.first : thePDFs.second;
}
/**
* Return the momentum fraction of the spectator
* for the selected configuration.
*/
double spectatorX(pair<bool,bool> conf) const {
return conf.first ? theFractions.second : theFractions.first;
}
/**
* Return the PDF of the spectator
* for the selected configuration.
*/
const PDF& spectatorPDF(pair<bool,bool> conf) const {
return conf.first ? thePDFs.second : thePDFs.first;
}
public:
/**
* Split this dipole according to the given splitting.
* If colourSpectator is true, do not change the spectator.
*/
pair<Dipole,Dipole> split (DipoleSplittingInfo& dsplit,
bool colourSpectator) const;
/**
* As split, but without touching the event record.
* Needed to produce a phase space point as it would
* be after calling split.
*/
void tmpsplit (DipoleSplittingInfo& dsplit,
bool colourSpectator) const;
/**
* Produce a new spectator according to the
* given splitting.
*/
void recoil (DipoleSplittingInfo& dsplit);
public:
/**
* Put information to ostream
*/
void print(ostream&) const;
private:
/**
* The particles forming the dipole
*/
pair<PPtr,PPtr> theParticles;
/**
* The PDF objects.
*/
pair<PDF,PDF> thePDFs;
/**
* The momentum fractions associated
* to the incoming particles
*/
pair<double,double> theFractions;
/**
* The dipole indices, if the first or second particle
* is considered as emitter.
*/
pair<DipoleIndex,DipoleIndex> theIndices;
/**
+ * Indicates if either the first or the second parton
+ * is incoming to a decay.
+ */
+ pair<bool,bool> theDecaying;
+
+ /**
+ * Indicates if either the first or second parton
+ * can be off-shell (required for sampling).
+ **/
+ pair<bool,bool> theOffShell;
+
+ /**
* The scale associated to the first and second
* particle, respectively.
*/
pair<Energy,Energy> theScales;
- /**
- * Indicates if either the first or the second parton
- * is incoming to a decay.
- */
- pair<bool,bool> theDecaying;
-
};
inline ostream& operator << (ostream& os, const Dipole& di) {
di.print(os);
return os;
}
}
#endif /* HERWIG_Dipole_H */
diff --git a/Shower/Dipole/Base/DipoleChain.cc b/Shower/Dipole/Base/DipoleChain.cc
--- a/Shower/Dipole/Base/DipoleChain.cc
+++ b/Shower/Dipole/Base/DipoleChain.cc
@@ -1,334 +1,342 @@
// -*- C++ -*-
//
// DipoleChain.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DipoleChain class.
//
#include "DipoleChain.h"
#include "Herwig/Shower/Dipole/Utility/DipolePartonSplitter.h"
+#include "Herwig/Shower/Dipole/Colorea/Colorea.h"
#include <iterator>
using namespace Herwig;
DipoleChain::DipoleChain()
: ggSingleDipole(false) {}
bool DipoleChain::circular () const {
return
(theDipoles.front().leftParticle() ==
theDipoles.back().rightParticle());
}
bool DipoleChain::hasLeftNeighbour (list<Dipole>::const_iterator dc) const {
if ( dc == dipoles().begin() )
return circular();
return true;
}
Dipole& DipoleChain::leftNeighbour (list<Dipole>::iterator dc) {
assert(hasLeftNeighbour(dc));
if ( dc == dipoles().begin() )
return dipoles().back();
return *(--dc);
}
const Dipole& DipoleChain::leftNeighbour (list<Dipole>::const_iterator dc) const {
assert(hasLeftNeighbour(dc));
if ( dc == dipoles().begin() )
return dipoles().back();
return *(--dc);
}
list<Dipole>::iterator DipoleChain::leftNeighbourIterator(list<Dipole>::iterator dc) {
assert(hasLeftNeighbour(dc));
if ( dc == dipoles().begin() )
return --dipoles().end();
return --dc;
}
bool DipoleChain::hasRightNeighbour (list<Dipole>::const_iterator dc) const {
if (dc == --dipoles().end())
return circular();
return true;
}
Dipole& DipoleChain::rightNeighbour (list<Dipole>::iterator dc) {
assert(hasRightNeighbour(dc));
if ( dc == --dipoles().end() )
return dipoles().front();
return *(++dc);
}
const Dipole& DipoleChain::rightNeighbour (list<Dipole>::const_iterator dc) const {
assert(hasRightNeighbour(dc));
if ( dc == --dipoles().end() )
return dipoles().front();
return *(++dc);
}
list<Dipole>::iterator DipoleChain::rightNeighbourIterator(list<Dipole>::iterator dc) {
assert(hasRightNeighbour(dc));
if ( dc == --dipoles().end() )
return dipoles().begin();
return ++dc;
}
void DipoleChain::check() {
if ( theDipoles.begin() == std::prev(theDipoles.end()) ) {
if ( theDipoles.front().leftParticle()->hasColour() &&
theDipoles.front().leftParticle()->hasAntiColour() ) {
assert(theDipoles.front().rightParticle()->hasColour() &&
theDipoles.front().rightParticle()->hasAntiColour());
ggSingleDipole = true;
}
}
}
+
+void DipoleChain::rearrange(int dipmax,int diplong){
+ static auto colorea = Colorea();
+ colorea.setChain(this);
+ colorea.rearrange( dipmax, diplong);
+}
+
list<Dipole>::iterator DipoleChain::insertSplitting(list<Dipole>::iterator emittingDipole,
pair<Dipole,Dipole> children,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators) {
assert(DipolePartonSplitter::colourConnected(children.first.leftParticle(),children.first.rightParticle()) ||
DipolePartonSplitter::colourConnected(children.second.leftParticle(),children.second.rightParticle()));
bool was_circular = circular();
if (hasLeftNeighbour(emittingDipole)) {
list<Dipole>::iterator theLeftNeighbour =
leftNeighbourIterator(emittingDipole);
theLeftNeighbour->rightParticle(children.first.leftParticle());
if ( children.first.leftParticle()->scale() < sqr(theLeftNeighbour->rightScale()) )
theLeftNeighbour->rightScale(sqrt(children.first.leftParticle()->scale()));
theLeftNeighbour->rightPDF(children.first.leftPDF());
theLeftNeighbour->rightFraction(children.first.leftFraction());
theLeftNeighbour->rightDecaying(children.first.leftDecaying());
theLeftNeighbour->update();
}
if (hasRightNeighbour(emittingDipole)) {
list<Dipole>::iterator theRightNeighbour =
rightNeighbourIterator(emittingDipole);
theRightNeighbour->leftParticle(children.second.rightParticle());
if ( children.second.rightParticle()->scale() < sqr(theRightNeighbour->leftScale()) )
theRightNeighbour->leftScale(sqrt(children.second.rightParticle()->scale()));
theRightNeighbour->leftPDF(children.second.rightPDF());
theRightNeighbour->leftFraction(children.second.rightFraction());
theRightNeighbour->leftDecaying(children.second.rightDecaying());
theRightNeighbour->update();
}
if (DipolePartonSplitter::colourConnected(children.first.leftParticle(),children.first.rightParticle()) &&
DipolePartonSplitter::colourConnected(children.second.leftParticle(),children.second.rightParticle())) {
// nothing special to do, just replace the emitting dipole
// by the right one and insert the left one before it
*emittingDipole = children.second;
childIterators.second = emittingDipole;
childIterators.first = dipoles().insert(emittingDipole,children.first);
if ( ggSingleDipole ) {
ggSingleDipole = false;
Dipole miss;
miss.leftParticle(dipoles().back().rightParticle());
miss.rightParticle(dipoles().front().leftParticle());
miss.leftScale(dipoles().back().rightScale());
miss.rightScale(dipoles().front().leftScale());
miss.leftPDF(dipoles().back().rightPDF());
miss.rightPDF(dipoles().front().leftPDF());
miss.leftFraction(dipoles().back().rightFraction());
miss.rightFraction(dipoles().front().leftFraction());
miss.leftDecaying(dipoles().back().rightDecaying());
miss.rightDecaying(dipoles().front().leftDecaying());
miss.update();
dipoles().push_back(miss);
}
return dipoles().end();
}
if (!DipolePartonSplitter::colourConnected(children.first.leftParticle(),children.first.rightParticle())) {
if ( !was_circular && !ggSingleDipole ) {
*emittingDipole = children.second;
childIterators.second = emittingDipole;
assert(emittingDipole != dipoles().begin());
childIterators.first = std::prev(emittingDipole);
return emittingDipole;
}
*emittingDipole = children.second;
if ( ggSingleDipole ) {
ggSingleDipole = false;
Dipole miss;
miss.leftParticle(children.second.rightParticle());
miss.rightParticle(children.first.leftParticle());
miss.leftScale(children.second.rightScale());
miss.rightScale(children.first.leftScale());
miss.leftPDF(children.second.rightPDF());
miss.rightPDF(children.first.leftPDF());
miss.leftFraction(children.second.rightFraction());
miss.rightFraction(children.first.leftFraction());
miss.leftDecaying(dipoles().back().rightDecaying());
miss.rightDecaying(dipoles().front().leftDecaying());
miss.update();
dipoles().push_back(miss);
childIterators.first = dipoles().begin();
childIterators.second = std::prev(dipoles().end());
return dipoles().end();
}
childIterators.second = emittingDipole;
if ( emittingDipole == dipoles().begin() )
childIterators.first = --dipoles().end();
else
childIterators.first = std::prev(emittingDipole);
if ( emittingDipole == dipoles().begin() )
return dipoles().end();
dipoles().splice(dipoles().begin(),dipoles(),emittingDipole,dipoles().end());
// explicitly fix iterators in case the splice implementation
// at hand does invalidate iterators (the SGI docu says, it doesn't,
// but it seems that this behaviour is not part of the standard)
childIterators.second = dipoles().begin();
childIterators.first = --dipoles().end();
return dipoles().end();
}
if (!DipolePartonSplitter::colourConnected(children.second.leftParticle(),children.second.rightParticle())) {
if ( !was_circular && !ggSingleDipole ) {
*emittingDipole = children.first;
childIterators.first = emittingDipole;
assert(emittingDipole != --dipoles().end());
childIterators.second = std::next(emittingDipole);
return std::next(emittingDipole);
}
*emittingDipole = children.first;
if ( ggSingleDipole ) {
ggSingleDipole = false;
Dipole miss;
miss.leftParticle(children.second.rightParticle());
miss.rightParticle(children.first.leftParticle());
miss.leftScale(children.second.rightScale());
miss.rightScale(children.first.leftScale());
miss.leftPDF(children.second.rightPDF());
miss.rightPDF(children.first.leftPDF());
miss.leftFraction(children.second.rightFraction());
miss.rightFraction(children.first.leftFraction());
miss.leftDecaying(dipoles().back().rightDecaying());
miss.rightDecaying(dipoles().front().leftDecaying());
miss.update();
dipoles().push_front(miss);
childIterators.first = dipoles().begin();
childIterators.second = std::prev(dipoles().end());
return dipoles().end();
}
childIterators.first = emittingDipole;
if ( emittingDipole == --dipoles().end() )
childIterators.second = dipoles().begin();
else
childIterators.second = std::next(emittingDipole);
if ( emittingDipole == --dipoles().end() )
return dipoles().end();
dipoles().splice(dipoles().begin(),dipoles(),std::next(emittingDipole),dipoles().end());
// explicitly fix iterators in case the splice implementation
// at hand does invalidate iterators (the SGI docu says, it doesn't,
// but it seems that this behaviour is not part of the standard)
childIterators.first = dipoles().begin();
childIterators.second = --dipoles().end();
return dipoles().end();
}
return dipoles().end();
}
void DipoleChain::updateDipole(list<Dipole>::iterator dip) {
dip->update();
if (hasLeftNeighbour(dip)) {
list<Dipole>::iterator theLeftNeighbour =
leftNeighbourIterator(dip);
theLeftNeighbour->rightParticle(dip->leftParticle());
theLeftNeighbour->rightPDF(dip->leftPDF());
theLeftNeighbour->rightFraction(dip->leftFraction());
theLeftNeighbour->rightDecaying(dip->leftDecaying());
theLeftNeighbour->update();
}
if (hasRightNeighbour(dip)) {
list<Dipole>::iterator theRightNeighbour =
rightNeighbourIterator(dip);
theRightNeighbour->leftParticle(dip->rightParticle());
theRightNeighbour->leftPDF(dip->rightPDF());
theRightNeighbour->leftFraction(dip->rightFraction());
theRightNeighbour->leftDecaying(dip->rightDecaying());
theRightNeighbour->update();
}
}
void DipoleChain::print(ostream& os) const {
os << "--- DipoleChain ----------------------------------------------------------------\n";
if ( theDipoles.empty() ) {
os << " *** This DipoleChain is empty. ***\n";
} else {
os << " " << (!circular() ? "non-" : "") << "circular with "
<< theDipoles.size() << " dipoles\n";
for (list<Dipole>::const_iterator dit = theDipoles.begin();
dit != theDipoles.end(); ++dit) {
os << (*dit);
}
}
os << "--------------------------------------------------------------------------------\n";
os << flush;
}
diff --git a/Shower/Dipole/Base/DipoleChain.fh b/Shower/Dipole/Base/DipoleChain.fh
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Base/DipoleChain.fh
@@ -0,0 +1,21 @@
+// -*- C++ -*-
+// This is the forward declaration of the DipoleChain class
+
+#ifndef HERWIG_DipoleChain_FH
+#define HERWIG_DipoleChain_FH
+
+#include "ThePEG/Config/ThePEG.h"
+#include "ThePEG/Config/Pointers.h"
+
+
+namespace Herwig {
+
+class DipoleChain;
+using namespace ThePEG;
+
+ ThePEG_DECLARE_POINTERS(DipoleChain , DipoleChainPtr );
+
+
+}
+
+#endif // HERWIG_DipoleChain_FH
diff --git a/Shower/Dipole/Base/DipoleChain.h b/Shower/Dipole/Base/DipoleChain.h
--- a/Shower/Dipole/Base/DipoleChain.h
+++ b/Shower/Dipole/Base/DipoleChain.h
@@ -1,153 +1,158 @@
// -*- C++ -*-
//
// DipoleChain.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_DipoleChain_H
#define HERWIG_DipoleChain_H
//
// This is the declaration of the DipoleChain class.
//
#include "Dipole.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer
*
* \brief The DipoleChain class is used by the dipole shower to
* represent a chain of dipoles.
*
*/
class DipoleChain {
public:
/**
* Default constructor
*/
DipoleChain();
/**
* Return true, if this chain is circular.
*/
bool circular () const;
/*
* Return true, if the dipole referred to
* has a left neighbour
*/
bool hasLeftNeighbour(list<Dipole>::const_iterator dc) const;
/*
* Return a reference to the left neighbour,
* if existing
*/
Dipole& leftNeighbour(list<Dipole>::iterator dc);
/*
* Return a const reference to the left neighbour,
* if existing
*/
const Dipole& leftNeighbour(list<Dipole>::const_iterator dc) const;
/**
* Return an iterator to the left neighbour
*/
list<Dipole>::iterator leftNeighbourIterator(list<Dipole>::iterator dc);
/*
* Return true, if the dipole referred to
* has a right neighbour
*/
bool hasRightNeighbour (list<Dipole>::const_iterator dc) const;
/*
* Return a reference to the right neighbour,
* if existing
*/
Dipole& rightNeighbour (list<Dipole>::iterator dc);
/*
* Return a const reference to the right neighbour,
* if existing
*/
const Dipole& rightNeighbour (list<Dipole>::const_iterator dc) const;
/**
* Return an iterator to the right neighbour
*/
list<Dipole>::iterator rightNeighbourIterator(list<Dipole>::iterator dc);
public:
/**
* Access the dipole list
*/
list<Dipole>& dipoles() { return theDipoles; }
/**
* Return the dipole list
*/
const list<Dipole>& dipoles() const { return theDipoles; }
/**
* Check for gg single dipole
*/
void check();
+ /**
+ * Rearrange the dipole chain (arXiv:1801.06113).
+ */
+ void rearrange(int dipmax,int diplong);
+
public:
/*
* Insert the given splitting; if this contains a chain-breakup emission and
* the chain is circular, reshuffle the chain to make it non-circular; if it is
* already non-circular return the iterator starting the new chain. If no
* splitting is needed return the end iterator of the dipole list.
* Set the iterators pointing to the children dipoles.
*/
list<Dipole>::iterator insertSplitting(list<Dipole>::iterator emittingDipole,
pair<Dipole,Dipole> children,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators);
/**
* Indicate a change in the given dipole.
*/
void updateDipole(list<Dipole>::iterator dip);
public:
/**
* Put information to ostream
*/
void print(ostream&) const;
private:
/**
* The dipoles contained in this chain
*/
list<Dipole> theDipoles;
/**
* Switch on special treatment for
* gg single dipole
*/
bool ggSingleDipole;
};
inline ostream& operator << (ostream& os, const DipoleChain& di) {
di.print(os);
return os;
}
}
#endif /* HERWIG_DipoleChain_H */
diff --git a/Shower/Dipole/Base/DipoleChainOrdering.cc b/Shower/Dipole/Base/DipoleChainOrdering.cc
--- a/Shower/Dipole/Base/DipoleChainOrdering.cc
+++ b/Shower/Dipole/Base/DipoleChainOrdering.cc
@@ -1,157 +1,146 @@
// -*- C++ -*-
//
// DipoleChainOrdering.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DipoleChainOrdering class.
//
#include "DipoleChainOrdering.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
DipoleChainOrdering::DipoleChainOrdering()
: DipoleEvolutionOrdering(), virtualityOrdering(false) {}
DipoleChainOrdering::~DipoleChainOrdering() {}
IBPtr DipoleChainOrdering::clone() const {
return new_ptr(*this);
}
IBPtr DipoleChainOrdering::fullclone() const {
return new_ptr(*this);
}
Energy DipoleChainOrdering::hardScale(tPPtr emitter, tPPtr spectator,
double emitterX, double spectatorX,
const DipoleSplittingKernel& split,
const DipoleIndex& index) const {
Energy scale =
split.splittingKinematics()->dipoleScale(emitter->momentum(),
spectator->momentum());
-
- if ( !index.incomingDecaySpectator() && !index.incomingDecayEmitter() ) {
return
virtualityOrdering ?
- split.splittingKinematics()->QMax(scale,emitterX,spectatorX,index,split) :
- split.splittingKinematics()->ptMax(scale,emitterX,spectatorX,index,split);
- }
+ split.splittingKinematics()->QMax(scale,emitterX,spectatorX,
+ index,split,emitter,spectator) :
+ split.splittingKinematics()->ptMax(scale,emitterX,spectatorX,
+ index,split,emitter,spectator);
+}
- else {
- DipoleSplittingInfo temp;
- temp.index(index);
- temp.recoilMass(split.splittingKinematics()->recoilMassKin(emitter->momentum(),
- spectator->momentum()));
- return
- virtualityOrdering ?
- split.splittingKinematics()->QMax(scale,emitterX,spectatorX,temp,split):
- split.splittingKinematics()->ptMax(scale,emitterX,spectatorX,temp,split);
- }
-}
void DipoleChainOrdering::setEvolutionScale(Energy scale,
const DipoleSplittingInfo&,
DipoleChain& chain,
pair<list<Dipole>::iterator,list<Dipole>::iterator>) const {
for ( list<Dipole>::iterator dip = chain.dipoles().begin();
dip != chain.dipoles().end(); ++dip ) {
if ( dip->emitterScale({true,false}) > scale )
dip->emitterScale({true,false},scale);
if ( dip->emitterScale({false,true}) > scale )
dip->emitterScale({false,true},scale);
}
}
void DipoleChainOrdering::setEvolutionScale(Energy scale,
const DipoleSplittingInfo&,
DipoleChain& chain,
list<Dipole>::iterator) const {
for ( list<Dipole>::iterator dip = chain.dipoles().begin();
dip != chain.dipoles().end(); ++dip ) {
if ( dip->emitterScale({true,false}) > scale )
dip->emitterScale({true,false},scale);
if ( dip->emitterScale({false,true}) > scale )
dip->emitterScale({false,true},scale);
}
}
Energy DipoleChainOrdering::evolutionScale(const DipoleSplittingInfo& split,
const DipoleSplittingKernel& spkernel) const {
return
virtualityOrdering ?
spkernel.splittingKinematics()->QFromPt(split.lastPt(),split) :
split.lastPt();
}
Energy DipoleChainOrdering::maxPt(Energy scale,
const DipoleSplittingInfo& split,
const DipoleSplittingKernel& spkernel) const {
return
virtualityOrdering ?
spkernel.splittingKinematics()->ptMax(scale,split.emitterX(),split.spectatorX(),split,spkernel) :
scale;
}
// If needed, insert default implementations of virtual function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void DipoleChainOrdering::persistentOutput(PersistentOStream & os) const {
os << virtualityOrdering;
}
void DipoleChainOrdering::persistentInput(PersistentIStream & is, int) {
is >> virtualityOrdering;
}
ClassDescription<DipoleChainOrdering> DipoleChainOrdering::initDipoleChainOrdering;
// Definition of the static class description member.
void DipoleChainOrdering::Init() {
static ClassDocumentation<DipoleChainOrdering> documentation
("DipoleChainOrdering performs ordering on "
"complete colour singlet dipole chains.");
static Switch<DipoleChainOrdering,bool> interfaceVirtualityOrdering
("Ordering",
"[experimental] Switch between virtuality and pt ordering.",
&DipoleChainOrdering::virtualityOrdering, false, false, false);
static SwitchOption interfaceVirtualityOrderingPt
(interfaceVirtualityOrdering,
"Pt",
"Perform pt ordering",
false);
static SwitchOption interfaceVirtualityOrderingVirtuality
(interfaceVirtualityOrdering,
"Virtuality",
"Perform virtuality ordering",
true);
interfaceVirtualityOrdering.rank(-1);
}
diff --git a/Shower/Dipole/Base/DipoleEventRecord.cc b/Shower/Dipole/Base/DipoleEventRecord.cc
--- a/Shower/Dipole/Base/DipoleEventRecord.cc
+++ b/Shower/Dipole/Base/DipoleEventRecord.cc
@@ -1,1537 +1,1608 @@
// -*- C++ -*-
//
// DipoleEventRecord.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DipoleEventRecord class.
//
#include "DipoleEventRecord.h"
+#include "Herwig/Shower/Dipole/DipoleShowerHandler.h"
#include "Herwig/Shower/Dipole/Utility/DipolePartonSplitter.h"
#include "Herwig/Shower/ShowerHandler.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Decay/HwDecayerBase.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/PDF/PartonExtractor.h"
#include "Herwig/Shower/RealEmissionProcess.h"
#include <boost/utility.hpp>
#include <algorithm>
#include <iterator>
using namespace Herwig;
PList DipoleEventRecord::colourOrdered(PPair & in,
PList & out) {
PList colour_ordered;
size_t done_size = out.size();
if (in.first->coloured())
++done_size;
if (in.second && in.second->coloured())
++done_size;
while (colour_ordered.size() != done_size) {
PPtr current;
// start with singlets, as long as we have some
if (find(colour_ordered.begin(),colour_ordered.end(),in.first) ==
colour_ordered.end() && in.first->coloured()) {
if (!in.first->hasColour() || !in.first->hasAntiColour())
current = in.first;
}
if (!current) {
for (PList::iterator p = out.begin();
p != out.end(); ++p) {
if (find(colour_ordered.begin(),colour_ordered.end(),*p) ==
colour_ordered.end() && (**p).coloured()) {
if (!(**p).hasColour() || !(**p).hasAntiColour()) {
current = *p;
break;
}
}
}
}
if (!current) {
if (in.second && find(colour_ordered.begin(),colour_ordered.end(),in.second) ==
colour_ordered.end() && in.second->coloured()) {
if (!in.second->hasColour() || !in.second->hasAntiColour())
current = in.second;
}
}
// then go on with anything else
if (!current) {
if (find(colour_ordered.begin(),colour_ordered.end(),in.first) ==
colour_ordered.end() && in.first->coloured()) {
current = in.first;
}
}
if (!current) {
for (PList::iterator p = out.begin();
p != out.end(); ++p) {
if (find(colour_ordered.begin(),colour_ordered.end(),*p) ==
colour_ordered.end() && (**p).coloured()) {
current = *p;
break;
}
}
}
if (!current) {
if (in.second && find(colour_ordered.begin(),colour_ordered.end(),in.second) ==
colour_ordered.end() && in.second->coloured()) {
current = in.second;
}
}
assert(current);
PPtr next;
Ptr<ColourLine>::ptr walk_the_line;
while (true) {
if (!walk_the_line) {
if (current->hasColour()) {
walk_the_line = current->colourLine();
}
else if (current->hasAntiColour()) {
walk_the_line = current->antiColourLine();
}
}
if (!next)
for (tPVector::const_iterator p = walk_the_line->coloured().begin();
p != walk_the_line->coloured().end(); ++p) {
if (*p == current)
continue;
if (find(out.begin(),out.end(),*p) != out.end() ||
*p == in.first ||
(in.second && *p == in.second)) {
next = *p;
if (next->hasColour() && next->hasAntiColour()) {
walk_the_line = walk_the_line == next->colourLine() ? next->antiColourLine() : next->colourLine();
}
break;
}
}
if (!next)
for (tPVector::const_iterator p = walk_the_line->antiColoured().begin();
p != walk_the_line->antiColoured().end(); ++p) {
if (*p == current)
continue;
if (find(out.begin(),out.end(),*p) != out.end() ||
*p == in.first ||
(in.second && *p == in.second)) {
next = *p;
if (next->hasColour() && next->hasAntiColour()) {
walk_the_line = walk_the_line == next->colourLine() ? next->antiColourLine() : next->colourLine();
}
break;
}
}
assert(next);
colour_ordered.push_back(current);
current = next;
// done if next is not a gluon or next is already in colour_ordered
if ((current->hasColour() && !current->hasAntiColour()) ||
(!current->hasColour() && current->hasAntiColour())) {
colour_ordered.push_back(current);
break;
}
if (next->hasColour() && next->hasAntiColour()) {
if (find(colour_ordered.begin(),colour_ordered.end(),next) != colour_ordered.end())
break;
}
next = PPtr();
}
}
return colour_ordered;
}
void DipoleEventRecord::popChain() {
assert(!theChains.empty());
theDoneChains.push_back(DipoleChain());
theDoneChains.back().dipoles().splice(theDoneChains.back().dipoles().begin(),theChains.front().dipoles());
theChains.pop_front();
}
void DipoleEventRecord::popChain(list<DipoleChain>::iterator ch) {
assert(!theChains.empty());
theDoneChains.push_back(DipoleChain());
theDoneChains.back().dipoles().splice(theDoneChains.back().dipoles().begin(),ch->dipoles());
theChains.erase(ch);
}
void DipoleEventRecord::popChains(const list<list<DipoleChain>::iterator>& chs) {
assert(!theChains.empty());
for ( list<list<DipoleChain>::iterator>::const_iterator ch =
chs.begin(); ch != chs.end(); ++ch ) {
theDoneChains.push_back(DipoleChain());
theDoneChains.back().dipoles().splice(theDoneChains.back().dipoles().begin(),(*ch)->dipoles());
}
for ( list<list<DipoleChain>::iterator>::const_iterator ch =
chs.begin(); ch != chs.end(); ++ch )
theChains.erase(*ch);
}
DipoleIndex
DipoleEventRecord::mergeIndex(list<Dipole>::iterator firstDipole, const pair<bool,bool>& whichFirst,
list<Dipole>::iterator secondDipole, const pair<bool,bool>& whichSecond) const {
tcPDPtr emitterData =
whichFirst.first ? firstDipole->leftParticle()->dataPtr() : firstDipole->rightParticle()->dataPtr();
tcPDPtr spectatorData =
whichSecond.first ? secondDipole->leftParticle()->dataPtr() : secondDipole->rightParticle()->dataPtr();
const PDF& emitterPDF =
whichFirst.first ? firstDipole->leftPDF() : firstDipole->rightPDF();
const PDF& spectatorPDF =
whichSecond.first ? secondDipole->leftPDF() : secondDipole->rightPDF();
return DipoleIndex(emitterData,spectatorData,emitterPDF,spectatorPDF);
}
SubleadingSplittingInfo
DipoleEventRecord::mergeSplittingInfo(list<DipoleChain>::iterator firstChain, list<Dipole>::iterator firstDipole,
const pair<bool,bool>& whichFirst,
list<DipoleChain>::iterator secondChain, list<Dipole>::iterator secondDipole,
const pair<bool,bool>& whichSecond) const {
SubleadingSplittingInfo res;
res.index(mergeIndex(firstDipole,whichFirst,secondDipole,whichSecond));
res.emitter(whichFirst.first ? firstDipole->leftParticle() : firstDipole->rightParticle());
res.spectator(whichSecond.first ? secondDipole->leftParticle() : secondDipole->rightParticle());
res.emitterX(whichFirst.first ? firstDipole->leftFraction() : firstDipole->rightFraction());
res.spectatorX(whichSecond.first ? secondDipole->leftFraction() : secondDipole->rightFraction());
res.configuration(whichFirst);
res.spectatorConfiguration(whichSecond);
res.emitterChain(firstChain);
res.emitterDipole(firstDipole);
res.spectatorChain(secondChain);
res.spectatorDipole(secondDipole);
return res;
}
void DipoleEventRecord::getSubleadingSplittings(list<SubleadingSplittingInfo>& res) {
static pair<bool,bool> left(true,false);
static pair<bool,bool> right(false,true);
res.clear();
for ( list<DipoleChain>::iterator cit = theChains.begin();
cit != theChains.end(); ++cit ) {
for ( list<Dipole>::iterator dit = cit->dipoles().begin();
dit != cit->dipoles().end(); ++dit ) {
for ( list<Dipole>::iterator djt = dit;
djt != cit->dipoles().end(); ++djt ) {
res.push_back(mergeSplittingInfo(cit,dit,left,cit,djt,left));
res.push_back(mergeSplittingInfo(cit,dit,right,cit,djt,right));
if ( dit != djt ) {
res.push_back(mergeSplittingInfo(cit,dit,left,cit,djt,right));
res.push_back(mergeSplittingInfo(cit,dit,right,cit,djt,left));
}
}
}
list<DipoleChain>::iterator cjt = cit; ++cjt;
for ( ; cjt != theChains.end(); ++cjt ) {
for ( list<Dipole>::iterator dit = cit->dipoles().begin();
dit != cit->dipoles().end(); ++dit ) {
for ( list<Dipole>::iterator djt = cjt->dipoles().begin();
djt != cjt->dipoles().end(); ++djt ) {
res.push_back(mergeSplittingInfo(cit,dit,left,cjt,djt,left));
res.push_back(mergeSplittingInfo(cit,dit,right,cjt,djt,right));
res.push_back(mergeSplittingInfo(cit,dit,left,cjt,djt,right));
res.push_back(mergeSplittingInfo(cit,dit,right,cjt,djt,left));
}
}
}
}
}
void DipoleEventRecord::splitSubleading(SubleadingSplittingInfo& dsplit,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators,
DipoleChain*& firstChain, DipoleChain*& secondChain) {
if ( dsplit.emitterDipole() == dsplit.spectatorDipole() ) {
assert(dsplit.emitterChain() == dsplit.spectatorChain());
split(dsplit.emitterDipole(),dsplit.emitterChain(),dsplit,
childIterators,firstChain,secondChain,false);
} else {
// first need to recoil, then split
recoil(dsplit.spectatorDipole(),dsplit.spectatorChain(),dsplit);
split(dsplit.emitterDipole(),dsplit.emitterChain(),dsplit,
childIterators,firstChain,secondChain,true);
}
}
-void DipoleEventRecord::findChains(const PList& ordered, const bool decay) {
-
+void DipoleEventRecord::findChains(const PList& ordered,
+ const set<long>& offShellPartons,
+ const bool decay) {
+
// All uses of findChains should guarantee
// a non-empty list of particles
assert( !ordered.empty() );
theChains.clear();
theDoneChains.clear();
DipoleChain current_chain;
// this whole thing needs to have a more elegant implementation at some point
bool startIsTriplet =
(ordered.front()->hasColour() && !ordered.front()->hasAntiColour()) ||
(!ordered.front()->hasColour() && ordered.front()->hasAntiColour());
bool endIsTriplet =
(ordered.back()->hasColour() && !ordered.back()->hasAntiColour()) ||
(!ordered.back()->hasColour() && ordered.back()->hasAntiColour());
-
+
+
if (!( ordered.size() == 2 && startIsTriplet && endIsTriplet)) {
PList::const_iterator theStart = ordered.begin();
bool onceMore = false;
for (PList::const_iterator p = ordered.begin();
p != ordered.end(); ++p) {
PList::const_iterator next_it =
p != --ordered.end() ? std::next(p) : ordered.begin();
if (!DipolePartonSplitter::colourConnected(*p,*next_it)) {
// it may have happened that we need to close the chain due to another
// chain starting right now; see the above global comment for this fix
bool startIsOctet =
(**theStart).hasColour() && (**theStart).hasAntiColour();
bool endIsOctet =
(**p).hasColour() && (**p).hasAntiColour();
if ( DipolePartonSplitter::colourConnected(*p,*theStart) &&
startIsOctet && endIsOctet ) {
swap(next_it,theStart);
onceMore = true;
} else {
theStart = next_it;
current_chain.check();
// Randomize the chains agains biasing of directions.
if(UseRandom::rndbool()) theChains.push_back(current_chain);
else theChains.insert(theChains.begin(),current_chain);
current_chain.dipoles().clear();
continue;
}
}
pair<bool,bool> initial_state (false,false);
initial_state.first = (*p == incoming().first || *p == incoming().second);
initial_state.second = (*next_it == incoming().first || *next_it == incoming().second);
pair<int,int> which_in (-1,-1);
if (initial_state.first)
which_in.first = *p == incoming().first ? 0 : 1;
if (initial_state.second)
which_in.second = *next_it == incoming().first ? 0 : 1;
pair<double,double> xs (1.,1.);
if (initial_state.first)
xs.first = *p == incoming().first ? fractions().first : fractions().second;
if (initial_state.second)
xs.second = *next_it == incoming().first ? fractions().first : fractions().second;
pair<PDF,PDF> pdf;
if ( which_in.first == 0 )
pdf.first = pdfs().first;
else if ( which_in.first == 1 )
pdf.first = pdfs().second;
if ( which_in.second == 0 )
pdf.second = pdfs().first;
else if ( which_in.second == 1 )
pdf.second = pdfs().second;
// In the case of a decay process register which
// parton is incoming to the decay
pair<bool,bool> decayed_parton (false,false);
if (decay) {
decayed_parton.first = (*p == currentDecay()->incoming()[0].first);
decayed_parton.second = (*next_it == currentDecay()->incoming()[0].first);
}
+
+ // Identify if either parton can have an off-shell mass
+ // The first test for partons with zero nominal mass should
+ // avoid issues of e.g. non-zero mass gluons
+ pair<bool,bool> off_shell (false,false);
+
+ // Note we could do away with the offShellPartons set but,
+ // to be safe in the case of an off-shell parton with a mass
+ // *very* close to its on-shell mass, we would need to include tests on the
+ // offShell indicators in the DipoleIndex == and < operators AND
+ // in canHandle and canHandleEquivalent in each massive kernel.
+ // Testing these in every splitting will probably be more expensive
+ // than doing the following checks for each hard process and decay process
+
+ // Only do off-shell check if the nominal mass is non-zero
+ if ( (*p)->nominalMass() != ZERO ) {
+ if ( offShellPartons.find(abs((*p)->id())) != offShellPartons.end() )
+ off_shell.first = true;
+ else
+ assert( abs((*p)->mass() - (*p)->nominalMass()) < (*p)->nominalMass()*1.e-5
+ && "There is an off-shell coloured particle in the hard process or a decay"
+ "which needs to be added to DipoleShowerHandler:OffShellInShower." );
+ }
+
+ if ( (*next_it)->nominalMass() != ZERO ) {
+ if ( offShellPartons.find(abs((*next_it)->id())) != offShellPartons.end() )
+ off_shell.second = true;
+ else
+ assert( abs((*next_it)->mass() - (*next_it)->nominalMass())
+ < (*next_it)->nominalMass()*1.e-5
+ && "There is an off-shell coloured particle in the hard process or a decay"
+ "which needs to be added to DipoleShowerHandler:OffShellInShower." );
+ }
+
- current_chain.dipoles().push_back(Dipole({*p,*next_it},pdf,xs,decayed_parton));
-
+ current_chain.dipoles().push_back(Dipole({*p,*next_it},pdf,xs,
+ decayed_parton, off_shell));
+
if ( onceMore ) {
next_it = theStart;
current_chain.check();
// Randomize the chains agains biasing of directions.
if(UseRandom::rndbool()) theChains.push_back(current_chain);
else theChains.insert(theChains.begin(),current_chain);
current_chain.dipoles().clear();
onceMore = false;
}
-
+
}
} else {
-
+
// treat 2 -> singlet, singlet -> 2 and 1 + singlet -> 1 + singlet special
// to prevent duplicate dipole
assert(DipolePartonSplitter::colourConnected(ordered.front(),ordered.back()));
pair<bool,bool> initial_state (false,false);
initial_state.first = (ordered.front() == incoming().first || ordered.front() == incoming().second);
initial_state.second = (ordered.back() == incoming().first || ordered.back() == incoming().second);
pair<int,int> which_in (-1,-1);
if (initial_state.first)
which_in.first = ordered.front() == incoming().first ? 0 : 1;
if (initial_state.second)
which_in.second = ordered.back() == incoming().first ? 0 : 1;
pair<double,double> xs (1.,1.);
if (initial_state.first)
xs.first = ordered.front() == incoming().first ? fractions().first : fractions().second;
if (initial_state.second)
xs.second = ordered.back() == incoming().first ? fractions().first : fractions().second;
pair<PDF,PDF> pdf;
if ( which_in.first == 0 )
pdf.first = pdfs().first;
else if ( which_in.first == 1 )
pdf.first = pdfs().second;
if ( which_in.second == 0 )
pdf.second = pdfs().first;
else if ( which_in.second == 1 )
pdf.second = pdfs().second;
// In the case of a decay process register which
// parton is incoming to the decay
pair<bool,bool> decayed_parton (false,false);
if (decay) {
decayed_parton.first = (ordered.front() == currentDecay()->incoming()[0].first);
decayed_parton.second = (ordered.back() == currentDecay()->incoming()[0].first);
}
+
- current_chain.dipoles().push_back(Dipole({ordered.front(),ordered.back()},pdf,xs,decayed_parton));
+ // Identify if either parton can have an off-shell mass
+ // The first test for partons with zero nominal mass should
+ // avoid issues of e.g. non-zero mass gluons
+ pair<bool,bool> off_shell (false,false);
+
+ // Only do off-shell check if the nominal mass is non-zero
+ if ( ordered.front()->nominalMass() != ZERO ) {
+ if ( offShellPartons.find(abs(ordered.front()->id())) != offShellPartons.end() )
+ off_shell.first = true;
+ else
+ assert( abs(ordered.front()->mass() - ordered.front()->nominalMass())
+ < ordered.front()->nominalMass()*1.e-5
+ && "There is an off-shell coloured particle in the hard process or a decay"
+ "which needs to be added to DipoleShowerHandler:OffShellInShower." );
+ }
+
+ if ( ordered.back()->nominalMass() != ZERO ) {
+ if ( offShellPartons.find(abs(ordered.back()->id())) != offShellPartons.end() )
+ off_shell.second = true;
+ else
+ assert( abs(ordered.back()->mass() - ordered.back()->nominalMass())
+ < ordered.back()->nominalMass()*1.e-5
+ && "There is an off-shell coloured particle in the hard process or a decay"
+ "which needs to be added to DipoleShowerHandler:OffShellInShower." );
+ }
+
+ current_chain.dipoles().push_back(Dipole({ordered.front(),ordered.back()},
+ pdf,xs, decayed_parton, off_shell));
}
if (!current_chain.dipoles().empty()) {
current_chain.check();
// Randomize the chains agains biasing of directions.
if(UseRandom::rndbool()) theChains.push_back(current_chain);
else theChains.insert(theChains.begin(),current_chain);
}
}
const map<PPtr,PPtr>&
DipoleEventRecord::prepare(tSubProPtr subpro,
tStdXCombPtr xc,
StepPtr step,
const pair<PDF,PDF>& pdf,tPPair beam,
- bool firstInteraction, bool dipoles) {
+ bool firstInteraction,
+ const set<long>& offShellPartons,
+ bool dipoles) {
// set the subprocess
subProcess(subpro);
// clear the event record
outgoing().clear();
theHard.clear();
theOriginals.clear();
theDecays.clear();
theCurrentDecay = PerturbativeProcessPtr();
// extract incoming particles
PPair in = subpro->incoming();
// get the incoming momentum fractions
// don't take these from the XComb as it may be null
pair<double,double> xs;
ThePEG::Direction<0> dir(true);
xs.first = in.first->momentum().dirPlus()/beam.first->momentum().dirPlus();
dir.reverse();
xs.second = in.second->momentum().dirPlus()/beam.second->momentum().dirPlus();
xcombPtr(xc);
pdfs() = pdf;
fractions() = xs;
// use ShowerHandler to split up the hard process
PerturbativeProcessPtr hard;
DecayProcessMap decay;
// Special handling for the first interaction:
// If a post subprocess handler (e.g. QED radiation)
// is applied, there may be particles in the step object not
// present in the subprocess object (other than any remnants).
// These need to be included in any transformations due to
// II splittings in ::update.
if ( firstInteraction ) {
// Initialise a PVector for the outgoing
tPVector hardProcOutgoing;
// Include all outgoing particles that are not remnants
for ( auto & part : step->particles() )
if ( part->id() != 82 ) {
hardProcOutgoing.push_back(part);
}
ShowerHandler::currentHandler()->splitHardProcess(hardProcOutgoing,
hard, decay);
}
// For secondary collisions we must use the
// subProcess object and not the step as the
// step stores all outgoing from the entire collision
else
ShowerHandler::currentHandler()->splitHardProcess(tPVector(subpro->outgoing().begin(),
subpro->outgoing().end()),
hard,decay);
// vectors for originals and copies of the particles
vector<PPtr> original;
vector<PPtr> copies;
// fill originals
for(unsigned int ix=0;ix<2;++ix)
original.push_back(hard->incoming()[ix].first);
for(unsigned int ix=0;ix<hard->outgoing().size();++ix)
original.push_back(hard->outgoing()[ix].first);
for(DecayProcessMap::const_iterator it=decay.begin();it!=decay.end();++it) {
fillFromDecays(it->second, original);
}
// and make copies
for ( vector<PPtr>::const_iterator p = original.begin();
p != original.end(); ++p ) {
PPtr copy = new_ptr(Particle(**p));
copies.push_back(copy);
theOriginals[*p] = copy;
}
// isolate the colour of the copies from the originals
colourIsolate(original,copies);
// set the incoming particles
incoming().first = copies[0];
ParticleVector children = incoming().first->children();
for ( ParticleVector::const_iterator c = children.begin();
c != children.end(); ++c )
incoming().first->abandonChild(*c);
incoming().second = copies[1];
children = incoming().second->children();
for ( ParticleVector::const_iterator c = children.begin();
c != children.end(); ++c )
incoming().second->abandonChild(*c);
// set the outgoing particles for the hard process
for(unsigned int ix=0;ix<hard->outgoing().size();++ix) {
if(hard->outgoing()[ix].first->coloured())
outgoing().push_back(theOriginals[hard->outgoing()[ix].first]);
else
theHard.push_back(theOriginals[hard->outgoing()[ix].first]);
}
if ( dipoles ) {
PList cordered = colourOrdered(incoming(),outgoing());
if ( !cordered.empty() )
- findChains(cordered,false);
+ findChains(cordered, offShellPartons, false);
}
// sort out the decays
for(auto const & dec : decay) {
// If the decay particle is in original it needs
// to be added to the decays and the decay needs to be
// changed to the copied particles.
if ( theOriginals.find(dec.second->incoming()[0].first) != theOriginals.end() ) {
theDecays[theOriginals[dec.second->incoming()[0].first]] = dec.second;
PerturbativeProcessPtr decayProc = theDecays[theOriginals[dec.second->incoming()[0].first]];
separateDecay(decayProc);
}
else {
assert( find( copies.begin(), copies.end(), dec.second->incoming()[0].first ) != copies.end() );
theDecays[dec.second->incoming()[0].first] = dec.second;
}
}
PList::const_iterator XFirst, XLast;
if ( !theHard.empty() ) {
XFirst = theHard.begin();
XLast = theHard.end();
} else {
XFirst = outgoing().begin();
XLast = outgoing().end();
}
thePX = (**XFirst).momentum();
++XFirst;
for ( ; XFirst != XLast; ++XFirst )
thePX += (**XFirst).momentum();
identifyEventType();
return theOriginals;
}
void DipoleEventRecord::slimprepare(tSubProPtr subpro,
tStdXCombPtr xc,
- const pair<PDF,PDF>& pdf,tPPair beam,
+ const pair<PDF,PDF>& pdf,tPPair beam,
+ const set<long>& offShellPartons,
bool dipoles) {
// set the subprocess
subProcess(subpro);
// clear the event record
outgoing().clear();
theHard.clear();
theOriginals.clear();
theDecays.clear();
theCurrentDecay = PerturbativeProcessPtr();
// extract incoming particles
PPair in = subpro->incoming();
// get the beam
// get the incoming momentum fractions
// don't take these from the XComb as it may be null
pair<double,double> xs;
ThePEG::Direction<0> dir(true);
xs.first = in.first->momentum().dirPlus()/beam.first->momentum().dirPlus();
dir.reverse();
xs.second = in.second->momentum().dirPlus()/beam.second->momentum().dirPlus();
xcombPtr(xc);
pdfs() = pdf;
fractions() = xs;
incoming() = in;
for(unsigned int ix=0;ix<subpro->outgoing().size();++ix) {
if(subpro->outgoing()[ix]->coloured())
outgoing().push_back(subpro->outgoing()[ix]);
}
if ( dipoles ) {
PList cordered = colourOrdered(incoming(),outgoing());
if ( !cordered.empty() )
- findChains(cordered,false);
+ findChains(cordered, offShellPartons, false);
}
}
void DipoleEventRecord::fillFromDecays(PerturbativeProcessPtr decayProc, vector<PPtr>& original) {
// Loop over the outgoing of the given perturbative process
for ( auto const & outIt : decayProc->outgoing() ) {
// Add the outgoing particle to the vector of original particles
original.push_back(outIt.first);
// Iterate through the outgoing
if ( outIt.second )
fillFromDecays( outIt.second, original);
}
}
void DipoleEventRecord::separateDecay(PerturbativeProcessPtr decayProc) {
// Iteratively replace all entries in the incoming
// with their copies.
for ( auto & inIt : decayProc->incoming() ) {
if ( theOriginals.find( inIt.first ) != theOriginals.end() )
inIt.first = theOriginals[inIt.first];
}
// Iteratively replace all entries in the outgoing
// with their copies.
for ( auto & outIt : decayProc->outgoing()) {
if ( theOriginals.count( outIt.first ) )
outIt.first = theOriginals[outIt.first];
if ( outIt.second )
separateDecay(outIt.second);
}
}
void DipoleEventRecord::clear() {
ShowerEventRecord::clear();
theDecays.clear();
theHard.clear();
theChains.clear();
theDoneChains.clear();
theOriginals.clear();
}
pair<PVector,PVector> DipoleEventRecord::tmpupdate(DipoleSplittingInfo& dsplit) {
PVector inc;
PVector out;
tcPPtr IF = incoming().first;
tcPPtr IS = incoming().second;
tcPPtr DE = dsplit.emitter();
tcPPtr DS = dsplit.spectator();
if ( IF != DE && IF != DS ) {
PPtr p = IF->data().produceParticle(IF->momentum());
inc.push_back(p);
}
else if ( IF == DE ) inc.push_back( dsplit.splitEmitter() );
else if ( IF == DS ) inc.push_back( dsplit.splitSpectator() );
if ( IS != DE && IS != DS ) {
PPtr p = IS->data().produceParticle(IS->momentum());
inc.push_back(p);
}
else if ( IS == DE ) inc.push_back( dsplit.splitEmitter() );
else if ( IS == DS ) inc.push_back( dsplit.splitSpectator() );
if ( IF != DE && IS != DE)
out.push_back( dsplit.splitEmitter());
if ( IF != DS && IS != DS)
out.push_back( dsplit.splitSpectator());
out.push_back( dsplit.emission());
for ( tcPPtr h : theHard ){
PPtr p = h->data().produceParticle(h->momentum());
if ( dsplit.splittingKinematics()->doesTransform() ) {
p->set5Momentum( dsplit.splittingKinematics()->transform(p->momentum()) );
}
out.push_back(p);
}
for ( tcPPtr p : outgoing() )
if ( p != DE &&
p != DS &&
p != dsplit.emission() ){
PPtr ou = p->data().produceParticle(p->momentum());;
if ( dsplit.splittingKinematics()->doesTransform() ){
ou->set5Momentum( dsplit.splittingKinematics()->transform(ou->momentum()) );
}
out.push_back(ou);
}
return {inc,out};
}
void DipoleEventRecord::update(DipoleSplittingInfo& dsplit) {
if ( incoming().first == dsplit.emitter() ) {
intermediates().push_back(dsplit.emitter());
incoming().first = dsplit.splitEmitter();
fractions().first /= dsplit.lastEmitterZ();
} else if ( incoming().first == dsplit.spectator() ) {
intermediates().push_back(dsplit.spectator());
incoming().first = dsplit.splitSpectator();
fractions().first /= dsplit.lastSpectatorZ();
}
if ( incoming().second == dsplit.emitter() ) {
intermediates().push_back(dsplit.emitter());
incoming().second = dsplit.splitEmitter();
fractions().second /= dsplit.lastEmitterZ();
} else if ( incoming().second == dsplit.spectator() ) {
intermediates().push_back(dsplit.spectator());
incoming().second = dsplit.splitSpectator();
fractions().second /= dsplit.lastSpectatorZ();
}
PList::iterator pos;
pos = find(outgoing().begin(), outgoing().end(), dsplit.emitter());
if (pos != outgoing().end()) {
intermediates().push_back(*pos);
*pos = dsplit.splitEmitter();
}
pos = find(outgoing().begin(), outgoing().end(), dsplit.spectator());
if (pos != outgoing().end()) {
intermediates().push_back(*pos);
*pos = dsplit.splitSpectator();
}
outgoing().push_back(dsplit.emission());
if (dsplit.splittingKinematics()->doesTransform()) {
for (PList::iterator p = intermediates().begin();
p != intermediates().end(); ++p) {
(**p).set5Momentum(dsplit.splittingKinematics()->transform((**p).momentum()));
}
for (PList::iterator h = theHard.begin();
h != theHard.end(); ++h) {
(**h).set5Momentum(dsplit.splittingKinematics()->transform((**h).momentum()));
}
for (PList::iterator p = outgoing().begin();
p != outgoing().end(); ++p) {
if ((*p) != dsplit.splitEmitter() &&
(*p) != dsplit.splitSpectator() &&
(*p) != dsplit.emission())
(**p).set5Momentum(dsplit.splittingKinematics()->transform((**p).momentum()));
}
}
// Handle updates related to decays
// Showering of decay processes
// Treat the evolution of the incoming
// decayed particle as in backward evolution
if ( dsplit.isDecayProc() ) {
// Create a pointer to the decay process
PerturbativeProcessPtr decayProc = currentDecay();
// Add the emission to the outgoing of the decay process
decayProc->outgoing().push_back( {dsplit.emission(), PerturbativeProcessPtr() });
// Bools to be used throughout
const bool decayedEmtr = dsplit.index().incomingDecayEmitter();
const bool decayedSpec = dsplit.index().incomingDecaySpectator();
/*
In the current implementation, **following the hard process**
all particles in theDecays evolve independently
e.g. if we have W -> XYZ where all X, Y and Z need to be
showered and decayed, we only identify them as needing decaying
(and hence put them in theDecays) AFTER showering the decay of W.
Hence, XYZ are not even in theDecays until W has been fully
showered and then they are decayed and showered completely independently
KEY POINT - Never need to update other entries of theDecays
Note: The PPtr in theDecays should remain unchanged and all changes
should be made to the relative PerturbativeProcess.
*/
// Splittings from dipoles in the decay process which
// do not have the decayed parton as emitter or spectator.
// Update the decay process in theDecays
if ( !decayedEmtr && !decayedSpec ) {
// Find and replace the old spectator and
// emitter in the outgoing of the decay process
bool decayProcEm = false;
bool decayProcSp = false;
for ( auto & outIt : decayProc->outgoing() ) {
if ( !decayProcEm && outIt.first == dsplit.emitter() ) {
outIt = {dsplit.splitEmitter(), PerturbativeProcessPtr()};
decayProcEm = true;
}
if ( !decayProcSp && outIt.first == dsplit.spectator() ) {
outIt = {dsplit.splitSpectator(), PerturbativeProcessPtr() };
decayProcSp = true;
}
if ( decayProcEm && decayProcSp )
break;
}
// Test that nothing strange is happening
assert( (decayProcEm && decayProcSp) );
return;
}
// The spectator is the decayed particle
else if ( decayedSpec ) {
// Update the dipole event record intermediates
intermediates().push_back(dsplit.splitSpectator());
// Update the the decayProcess incoming
decayProc->incoming().clear();
decayProc->incoming().push_back({dsplit.splitSpectator(),decayProc});
// Update the decay process outgoing
// Replace the old emitter with the new emitter
for ( auto & outEmtrIt : decayProc->outgoing() ) {
if ( outEmtrIt.first == dsplit.emitter() ){
outEmtrIt = {dsplit.splitEmitter(), PerturbativeProcessPtr() };
break;
}
}
// Perform the recoil transformation
// Find all particles in the recoil system
PList recoilSystem;
for ( auto const & outIt : decayProc->outgoing() ) {
if ( outIt.first != dsplit.splitEmitter() && outIt.first != dsplit.emission() ) {
recoilSystem.push_back(outIt.first);
}
}
dsplit.splittingKinematics()->decayRecoil( recoilSystem );
return;
}
// The emitter is the decayed particle
else {
throw Exception()
<< "DipoleEventRecord: The emitter as a decayed particle is currently not implemented."
<< Exception::runerror;
assert( currentDecay()->incoming()[0].first == dsplit.emitter() && decayedEmtr && !decayedSpec );
// Update the dipole event record intermediates
intermediates().push_back(dsplit.splitEmitter());
// Update the the decayProcess incoming
decayProc->incoming().clear();
decayProc->incoming().push_back({dsplit.splitEmitter(),decayProc});
// Update the decay process outgoing
// Replace the old spectator with the new spectator
for (auto & outSpecIt : decayProc->outgoing() ) {
if ( outSpecIt.first == dsplit.spectator() ){
outSpecIt = { dsplit.splitSpectator(), PerturbativeProcessPtr() };
break;
}
}
// Perform the recoil transformation
assert(dsplit.splittingKinematics()->isDecay());
// Find all particles in the recoil system
PList recoilSystem;
for ( auto const & outIt : decayProc->outgoing() ) {
if ( outIt.first != dsplit.splitSpectator() && outIt.first != dsplit.emission() ) {
recoilSystem.push_back(outIt.first);
}
}
dsplit.splittingKinematics()->decayRecoil( recoilSystem );
return;
}
}
}
void
DipoleEventRecord::split(list<Dipole>::iterator dip,
list<DipoleChain>::iterator ch,
DipoleSplittingInfo& dsplit,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators,
DipoleChain*& firstChain, DipoleChain*& secondChain,
bool colourSpectator) {
static DipoleChain empty;
pair<Dipole,Dipole> children = dip->split(dsplit,colourSpectator);
list<Dipole>::iterator breakup =
ch->insertSplitting(dip,children,childIterators);
if ( breakup == ch->dipoles().end() ) {
firstChain = &(*ch);
secondChain = &empty;
} else {
DipoleChain other;
other.dipoles().splice(other.dipoles().end(),ch->dipoles(),breakup,ch->dipoles().end());
chains().push_back(other);
firstChain = &(*ch);
secondChain = &(chains().back());
// explicitly fix iterators in case the splice implementation
// at hand does invalidate iterators (the SGI docu says, it doesn't,
// but it seems that this behaviour is not part of the standard)
childIterators.first = --firstChain->dipoles().end();
childIterators.second = secondChain->dipoles().begin(); }
if ( !colourSpectator ) {
update(dsplit); // otherwise done by recoil(...)
}
}
pair<PVector,PVector> DipoleEventRecord::tmpsplit(list<Dipole>::iterator dip,
list<DipoleChain>::iterator ,
DipoleSplittingInfo& dsplit,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& ,
DipoleChain*& , DipoleChain*& ,
bool colourSpectator) {
dip->tmpsplit(dsplit,colourSpectator);
return tmpupdate(dsplit); // otherwise done by recoil(...)
}
void DipoleEventRecord::recoil(list<Dipole>::iterator dip,
list<DipoleChain>::iterator ch,
DipoleSplittingInfo& dsplit) {
dip->recoil(dsplit);
ch->updateDipole(dip);
update(dsplit);
}
list<pair<list<Dipole>::iterator,list<DipoleChain>::iterator> >
DipoleEventRecord::inDipoles() {
list<pair<list<Dipole>::iterator,list<DipoleChain>::iterator> > res;
for ( list<DipoleChain>::iterator chit = theDoneChains.begin();
chit != theDoneChains.end(); ++chit ) {
bool haveOne = false;
for ( list<Dipole>::iterator dit = chit->dipoles().begin();
dit != chit->dipoles().end(); ++dit ) {
if ( dit->leftPDF().pdf() || dit->rightPDF().pdf() ) {
haveOne = true;
break;
}
}
if ( haveOne ) {
theChains.splice(theChains.begin(),theDoneChains,chit);
for ( list<Dipole>::iterator dit = theChains.front().dipoles().begin();
dit != theChains.front().dipoles().end(); ++dit ) {
if ( dit->leftPDF().pdf() || dit->rightPDF().pdf() ) {
res.push_back({dit,theChains.begin()});
}
}
}
}
return res;
}
void DipoleEventRecord::transform(const SpinOneLorentzRotation& rot) {
Lorentz5Momentum tmp;
for (PList::iterator p = intermediates().begin();
p != intermediates().end(); ++p) {
tmp = (**p).momentum(); tmp = rot * tmp;
(**p).set5Momentum(tmp);
}
for (PList::iterator h = theHard.begin();
h != theHard.end(); ++h) {
tmp = (**h).momentum(); tmp = rot * tmp;
(**h).set5Momentum(tmp);
}
for (PList::iterator p = outgoing().begin();
p != outgoing().end(); ++p) {
tmp = (**p).momentum(); tmp = rot * tmp;
(**p).set5Momentum(tmp);
}
}
tPPair DipoleEventRecord::fillEventRecord(StepPtr step, bool firstInteraction, bool) {
PPtr inSubPro = subProcess()->incoming().first;
PPtr inParticle;
if ( !(inSubPro->parents().empty()) )
inParticle = inSubPro->parents()[0];
else
inParticle = inSubPro;
PPtr inParton = theOriginals[inSubPro];
theOriginals.erase(inSubPro);
updateColour(incoming().first,true);
if ( inParticle != inSubPro )
inParticle->abandonChild(inSubPro);
inParton->addChild(inSubPro);
if ( inParticle != inSubPro )
inParticle->addChild(incoming().first);
intermediates().push_back(inSubPro);
intermediates().push_back(inParton);
// Repeat all the above for the second incoming particle
inSubPro = subProcess()->incoming().second;
if ( !(inSubPro->parents().empty()) )
inParticle = inSubPro->parents()[0];
else
inParticle = inSubPro;
inParton = theOriginals[inSubPro];
theOriginals.erase(inSubPro);
updateColour(incoming().second,true);
if ( inParticle != inSubPro )
inParticle->abandonChild(inSubPro);
inParton->addChild(inSubPro);
if ( inParticle != inSubPro )
inParticle->addChild(incoming().second);
intermediates().push_back(inSubPro);
intermediates().push_back(inParton);
// theOriginals is populated in ::prepare and contains all of the incoming and outgoing particles of the original hard process
// Here outgoing particles from theOriginals are added into the intermediates()
while ( !theOriginals.empty() ) {
PPtr outSubPro = theOriginals.begin()->first;
PPtr outParton = theOriginals.begin()->second;
// workaround for OS X Mavericks LLVM libc++
#ifdef _LIBCPP_VERSION
map<PPtr,PPtr>::const_iterator beg = theOriginals.begin();
#else
map<PPtr,PPtr>::iterator beg = theOriginals.begin();
#endif
theOriginals.erase(beg);
updateColour(outParton,true);
outSubPro->addChild(outParton);
intermediates().push_back(outSubPro);
}
// Update the intermediates of the step
step->addIntermediates(intermediates().begin(),intermediates().end());
for (auto const & p : outgoing())
step->addDecayProduct( p );
for (auto const & p : theHard)
step->addDecayProduct( p );
if ( firstInteraction &&
(incoming().first->coloured() ||
incoming().second->coloured() ) ) {
ShowerHandler::currentHandler()->lastExtractor()
->newRemnants(subProcess()->incoming(),incoming(),step);
}
step->addIntermediate(incoming().first);
step->addIntermediate(incoming().second);
return incoming();
}
-bool DipoleEventRecord::prepareDecay( PerturbativeProcessPtr decayProc ) {
+ bool DipoleEventRecord::prepareDecay( PerturbativeProcessPtr decayProc,
+ const set<long>& offShellPartons ) {
// Create objects containing the incoming and outgoing partons,
// required as inputs for colourOrdered.
PList out;
for( auto const & dec : decayProc->outgoing()) {
if(dec.first->coloured()) {
out.push_back(dec.first);
}
}
// Only need to shower if we have coloured outgoing particles
if ( out.empty() )
return false;
else {
// For the incoming, use a PPair containing the incoming and a null pointer
PPair in;
in.first = decayProc->incoming()[0].first;
// Create an ordered list of particles
PList cordered;
cordered = colourOrdered(in,out);
// Find the dipole chains for this decay
- findChains(cordered,true);
+ findChains(cordered, offShellPartons, true);
return true;
}
}
Energy DipoleEventRecord::decay(PPtr incoming, bool& powhegEmission) {
// get the process
PerturbativeProcessPtr process = theDecays[incoming];
assert(process);
//tDMPtr decayMode = new_ptr(DecayMode());
tDMPtr decayMode = DMPtr();
// Do not decay particles that have already been decayed
// Note the herwig decayer deals with colour connections
if ( process->outgoing().empty() ) {
process->incoming()[0].first = incoming;
DecayProcessMap decay;
// Decay the particle, returning a pointer to the decay mode
decayMode = ShowerHandler::currentHandler()->decay(process,decay,true);
}
// Sort out the colour connections of particles already decayed
else {
// sort out the colour of the incoming
map<tColinePtr,tColinePtr> cmap;
if(incoming->colourLine())
cmap[process->incoming()[0].first->colourLine()] = incoming->colourLine();
if(incoming->antiColourLine())
cmap[process->incoming()[0].first->antiColourLine()] = incoming->antiColourLine();
// fix colours of outgoing
for(auto const & outg : process->outgoing()) {
map<tColinePtr,tColinePtr>::iterator it =
cmap.find(outg.first->colourLine());
if(it!=cmap.end()) {
ColinePtr c1=outg.first->colourLine();
c1->removeColoured(outg.first);
it->second->addColoured(outg.first);
}
it = cmap.find(outg.first->antiColourLine());
if(it!=cmap.end()) {
ColinePtr c1=outg.first->antiColourLine();
c1->removeAntiColoured(outg.first);
it->second->addAntiColoured(outg.first);
}
}
// swap the incoming
process->incoming()[0].first = incoming;
}
// Set the scale of all particles involved in the decay process to the
// mass of the decaying particle
// Initialise the scale for the evolution of
// the parton shower following the decay
Energy showerScale = ZERO;
// Set the scale for the evolution of the shower
showerScale = process->incoming()[0].first->momentum().m();
Energy2 decayScaleSqr = sqr( showerScale );
process->incoming()[0].first->scale( decayScaleSqr );
for(auto & outg : process->outgoing()) {
outg.first->scale( decayScaleSqr );
}
// Update the decaying particle in the process and the event
PList::iterator posOut = find(outgoing().begin(), outgoing().end(), incoming);
PList::iterator posHard = find(hard().begin(), hard().end(), incoming);
assert((posOut!=outgoing().end() && posHard==hard().end()) ||
(posOut==outgoing().end() && posHard!=hard().end()) );
if ( posOut!=outgoing().end() ) {
outgoing().erase(posOut);
}
else {
hard().erase(posHard);
}
intermediates().push_back(process->incoming()[0].first);
// Populate the children of the incoming
for(auto const & outg : process->outgoing()) {
PPtr outgoing = outg.first;
process->incoming()[0].first->addChild(outgoing);
}
// If a decayed particle is not decayed above,
// e.g. a W in a 3-body top decay, find its decaymode.
if ( powhegEmission && !decayMode ) {
string tag = incoming->dataPtr()->name() + "->";
// Must use OrderedParticles for a tag search
ShowerHandler::OrderedParticles decayOut;
for(auto const & outg : process->outgoing()) {
decayOut.insert(outg.first->dataPtr());
}
// Construct the tag
for(auto const & dec : decayOut) {
if( dec!=*decayOut.begin() ) tag += ",";
tag +=dec->name();
}
tag += ";";
// Find the decay mode
decayMode = ShowerHandler::currentHandler()->findDecayMode(tag);
}
// Perform the powheg emission
if ( powhegEmission ) {
if ( decayMode ) {
HwDecayerBasePtr decayer;
decayer = dynamic_ptr_cast<HwDecayerBasePtr>(decayMode->decayer());
if ( decayer->hasPOWHEGCorrection() ) {
// Construct a real emission process and populate its
// incoming and outcoming prior to any powheg emission
RealEmissionProcessPtr born = new_ptr( RealEmissionProcess() );
born->bornIncoming().push_back( incoming );
for(auto const & outg : process->outgoing()) {
born->bornOutgoing().push_back(outg.first);
}
// Generate any powheg emission, returning 'real'
RealEmissionProcessPtr real = decayer->generateHardest( born );
// If an emission has been attempted
// (Note if the emission fails, a null ptr is returned)
if ( real ) {
showerScale = real->pT()[ShowerInteraction::QCD];
// If an emission is generated sort out the particles
if ( !real->outgoing().empty() ) {
// Update the decay process
// Note: Do not use the new incoming particle
PPtr oldEmitter;
PPtr newEmitter;
// Use the name recoiler to avoid confusion with
// the spectator in the POWHEGDecayer
// i.e. the recoiler can be coloured or non-coloured
PPtr oldRecoiler;
PPtr newRecoiler;
if ( real->emitter() == 1 ) {
oldEmitter = real->bornOutgoing()[0];
oldRecoiler = real->bornOutgoing()[1];
newEmitter = real->outgoing()[0];
newRecoiler = real->outgoing()[1];
}
else if ( real->emitter() == 2) {
oldEmitter = real->bornOutgoing()[1];
oldRecoiler = real->bornOutgoing()[0];
newEmitter = real->outgoing()[1];
newRecoiler = real->outgoing()[0];
}
PPtr emitted = real->outgoing()[ real->emitted()-1];
// Update the scales
newRecoiler->scale(oldRecoiler->scale());
newEmitter->scale(sqr(showerScale));
emitted->scale(sqr(showerScale));
// Update the colour flow of the new outgoing particles
// Note the emitted and newEmitter are already colour
// connected by the powheg emission function
emitted->incomingColour(oldEmitter, oldEmitter->id()<0);
if ( newRecoiler->coloured() )
newRecoiler->incomingColour(oldRecoiler, oldRecoiler->id()<0);
// Update the children of the outgoing
oldRecoiler->addChild( newRecoiler );
oldEmitter->addChild( newEmitter );
oldEmitter->addChild( emitted );
// Note: The particles in the pert proc outgoing and both outgoing
// vectors of the real emission proc are in the same order
for(unsigned int ix=0;ix<real->bornOutgoing().size();++ix) {
// Update the decay process
assert(process->outgoing()[ix].first == real->bornOutgoing()[ix]);
process->outgoing()[ix].first = real->outgoing()[ix];
// Add the outgoing from the born
// decay to the event intermediates
intermediates().push_back(real->bornOutgoing()[ix]);
}
// Add the emitted to the outgoing of the decay process
process->outgoing().push_back( { emitted, PerturbativeProcessPtr() } );
}
// Else, if no emission above pTmin, set particle scales
else {
for(auto & outg : process->outgoing()) {
outg.first->scale( sqr(showerScale) );
}
powhegEmission = false;
}
}
// No powheg emission occurred:
else
powhegEmission = false;
}
// No powheg emission occurred:
else
powhegEmission = false;
}
// No powheg emission occurred:
else
powhegEmission = false;
}
// Copy the outgoing from the decay
// process to the event record
for(auto const & outg : process->outgoing()) {
if ( outg.first->coloured() )
outgoing().push_back(outg.first);
else
hard().push_back(outg.first);
}
return showerScale;
}
void DipoleEventRecord::updateDecayMom( PPtr decayParent, PerturbativeProcessPtr decayProc ) {
// Only particles that have already been decayed
// should be passed to this function
assert( !(decayProc->outgoing().empty()) );
// Create a list of the children to update their momenta
PList children;
for ( auto const & outg : decayProc->outgoing() ) {
children.push_back( outg.first );
}
// Boost the children
PList::iterator beginChildren = children.begin();
PList::iterator endChildren = children.end();
ThePEG::UtilityBase::setMomentum(beginChildren, endChildren, decayParent->momentum().vect() );
}
void DipoleEventRecord::updateDecayChainMom( PPtr decayParent, PerturbativeProcessPtr decayProc ) {
// Note - this updates the momenta of the
// outgoing of the given decay process
// Update the momenta of the outgoing from this decay
updateDecayMom( decayParent, decayProc );
// Iteratively update the momenta of the rest of the decay chain
for ( auto & outg : decayProc->outgoing() ) {
// If a child has a corresponding pert proc
// then it has decay products
if ( outg.second ) {
for ( auto & dec : theDecays ) {
if(dec.second==outg.second) {
dec.first->setMomentum(outg.first->momentum());
break;
}
}
// Iteratively update any decay products
if ( !outg.second->outgoing().empty() )
updateDecayChainMom( outg.first, outg.second );
}
}
}
void DipoleEventRecord::updateDecays(PerturbativeProcessPtr decayProc, bool iterate) {
// Note - This does not update the momenta of the outgoing
// of decayProc.
// i.e. it is for use following the (non-)showering
// of a decay when the daughter momentum are correct.
// With iterate = true, this updates the rest of the decay chain.
// Loop over the outgoing from this decay
for ( auto & outg : decayProc->outgoing() ) {
if ( outg.second && !outg.second->outgoing().empty() ) {
// Outgoing particles which have already been decayed
PPtr newDecayed = outg.first;
PerturbativeProcessPtr newDecayProc = outg.second;
// Update the outgoing momenta from this decay
updateDecayMom( newDecayed, newDecayProc);
// If this decay is already in theDecays then erase it
for ( auto const & dec : theDecays ) {
if(dec.second==newDecayProc) {
theDecays.erase(dec.first);
break;
}
}
// Add to theDecays
theDecays[newDecayed] = newDecayProc;
//assert(theDecays[newDecayed]->incoming()[0].second==decayProc);
// Iteratively update theDecays from the decay chain
if ( iterate )
updateDecays( newDecayProc );
}
// Deal with any outgoing which need to be decayed
else if ( ShowerHandler::currentHandler()->decaysInShower(outg.first->id()) ) {
PerturbativeProcessPtr newDecay=new_ptr(PerturbativeProcess());
newDecay->incoming().push_back({ outg.first , decayProc } );
theDecays[outg.first] = newDecay;
}
}
}
void DipoleEventRecord::debugLastEvent(ostream& os) const {
bool first = ShowerHandler::currentHandler()->firstInteraction();
os << "--- DipoleEventRecord ----------------------------------------------------------\n";
os << " the " << (first ? "hard" : "secondary") << " subprocess is:\n"
<< (*subProcess());
os << " using PDF's " << pdfs().first.pdf() << " and "
<< pdfs().second.pdf() << "\n";
os << " chains showering currently:\n";
for ( list<DipoleChain>::const_iterator chit = theChains.begin();
chit != theChains.end(); ++chit )
os << (*chit);
os << " chains which finished showering:\n";
for ( list<DipoleChain>::const_iterator chit = theDoneChains.begin();
chit != theDoneChains.end(); ++chit )
os << (*chit);
os << "--------------------------------------------------------------------------------\n";
os << flush;
}
diff --git a/Shower/Dipole/Base/DipoleEventRecord.h b/Shower/Dipole/Base/DipoleEventRecord.h
--- a/Shower/Dipole/Base/DipoleEventRecord.h
+++ b/Shower/Dipole/Base/DipoleEventRecord.h
@@ -1,499 +1,511 @@
// -*- C++ -*-
//
// DipoleEventRecord.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_DipoleEventRecord_H
#define HERWIG_DipoleEventRecord_H
//
// This is the declaration of the DipoleEventRecord class.
//
#include "Herwig/Shower/ShowerEventRecord.h"
#include "Herwig/Shower/PerturbativeProcess.h"
#include "ThePEG/PDF/PDF.h"
#include "Dipole.h"
#include "DipoleChain.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer, Johannes Bellm
*
* \brief Generalized dipole splitting info to deal with subleading-N
* splittings.
*/
class SubleadingSplittingInfo
: public DipoleSplittingInfo {
public:
/**
* Default constructor
*/
SubleadingSplittingInfo()
: DipoleSplittingInfo() {}
/**
* Get the iterator of the emitter dipole chain
*/
list<DipoleChain>::iterator emitterChain() const { return theEmitterChain; }
/**
* Get the iterator of the emitter dipole
*/
list<Dipole>::iterator emitterDipole() const { return theEmitterDipole; }
/**
* Get the iterator of the spectator dipole chain
*/
list<DipoleChain>::iterator spectatorChain() const { return theSpectatorChain; }
/**
* Get the iterator of the spectator dipole
*/
list<Dipole>::iterator spectatorDipole() const { return theSpectatorDipole; }
/**
* Get the starting scale
*/
Energy startScale() const { return theStartScale; }
/**
* Set the iterator of the emitter dipole chain
*/
void emitterChain(list<DipoleChain>::iterator it) { theEmitterChain = it; }
/**
* Set the iterator of the emitter dipole
*/
void emitterDipole(list<Dipole>::iterator it) { theEmitterDipole = it; }
/**
* Set the iterator of the spectator dipole chain
*/
void spectatorChain(list<DipoleChain>::iterator it) { theSpectatorChain = it; }
/**
* Set the iterator of the spectator dipole
*/
void spectatorDipole(list<Dipole>::iterator it) { theSpectatorDipole = it; }
/**
* Set the starting scale
*/
void startScale(Energy s) { theStartScale = s; }
private:
/**
* Iterator of the emitter dipole chain
*/
list<DipoleChain>::iterator theEmitterChain;
/**
* Iterator of the emitter dipole
*/
list<Dipole>::iterator theEmitterDipole;
/**
* Iterator of the spectator dipole chain
*/
list<DipoleChain>::iterator theSpectatorChain;
/**
* Iterator of the spectator dipole
*/
list<Dipole>::iterator theSpectatorDipole;
/**
* The starting scale
*/
Energy theStartScale;
};
/**
* \ingroup DipoleShower
* \author Simon Platzer, Stephen Webster
*
* \brief The DipoleEventRecord class is
* used internally by the dipole shower.
*/
class DipoleEventRecord : public ShowerEventRecord {
public:
/**
* The default constructor.
*/
DipoleEventRecord() {}
/**
* The default destructor just cleans up.
*/
~DipoleEventRecord() { clear(); }
public:
/**
* Return any non-coloured outgoing particles in the
* current subprocess.
*/
PList& hard() { return theHard; }
/**
* Return any non-coloured outgoing particles in the
* current subprocess.
*/
const PList& hard() const { return theHard; }
/**
* Return the momentum of the hard system
*/
const Lorentz5Momentum& pX() const { return thePX; }
/**
* Transform all intermediate, hard and outgoing
* partciles using the given transformation.
*/
void transform(const SpinOneLorentzRotation& rot);
public:
/**
* Return the dipole chains to be showered.
*/
const list<DipoleChain>& chains() const { return theChains; }
/**
* Access the dipole chains to be showered.
*/
list<DipoleChain>& chains() { return theChains; }
/**
* Return the dipole chains which ceased evolving.
*/
const list<DipoleChain>& doneChains() const { return theDoneChains; }
/**
* Access the dipole chains which ceased evolving.
*/
list<DipoleChain>& doneChains() { return theDoneChains; }
/**
* Return true, if there are chains to be
* showered.
*/
bool haveChain() const { return !theChains.empty(); }
/**
* Return the current dipole chain
*/
DipoleChain& currentChain() { assert(haveChain()); return theChains.front(); }
/**
* Pop the current dipole chain
*/
void popChain();
/**
* Remove the given chain.
*/
void popChain(list<DipoleChain>::iterator);
/**
* Remove the given chains.
*/
void popChains(const list<list<DipoleChain>::iterator>&);
/**
* Create a merged dipole index given two independent dipoles;
* the first dipole is to provide the emitter.
*/
DipoleIndex
mergeIndex(list<Dipole>::iterator firstDipole, const pair<bool,bool>& whichFirst,
list<Dipole>::iterator secondDipole, const pair<bool,bool>& whichSecond) const;
/**
* Create a SubleadingSplitingInfo given two independent dipoles;
* the first dipole is to provide the emitter.
*/
SubleadingSplittingInfo
mergeSplittingInfo(list<DipoleChain>::iterator firstChain, list<Dipole>::iterator firstDipole,
const pair<bool,bool>& whichFirst,
list<DipoleChain>::iterator secondChain, list<Dipole>::iterator secondDipole,
const pair<bool,bool>& whichSecond) const;
/**
* Return a list of all possible subleading-N emitting pairs
*/
void getSubleadingSplittings(list<SubleadingSplittingInfo>&);
public:
/**
* Split the dipole pointed to by the given iterator.
* Return references to the affected chains, and update
* iterators pointing to the children in the returned
* chains.
*/
void split(list<Dipole>::iterator dip,
DipoleSplittingInfo& dsplit,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators,
DipoleChain*& firstChain, DipoleChain*& secondChain) {
split(dip,theChains.begin(),dsplit,childIterators,firstChain,secondChain,false);
}
/**
* Split the dipole pointed to by the given iterator
* in the indicated chain, indicating a splitting with
* a colour spectator.
* Return references to the affected chains, and update
* iterators pointing to the children in the returned
* chains.
*/
void split(list<Dipole>::iterator dip,
list<DipoleChain>::iterator ch,
DipoleSplittingInfo& dsplit,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators,
DipoleChain*& firstChain, DipoleChain*& secondChain,
bool colourSpectator = true);
/**
* As split, but not touching the acctual event record.
*/
pair<PVector,PVector> tmpsplit(list<Dipole>::iterator dip,
DipoleSplittingInfo& dsplit,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators,
DipoleChain*& firstChain, DipoleChain*& secondChain) {
return tmpsplit(dip,theChains.begin(),dsplit,childIterators,firstChain,secondChain,false);
}
/**
* As split, but not touching the acctual event record.
*/
pair<PVector,PVector> tmpsplit(list<Dipole>::iterator dip,
list<DipoleChain>::iterator ch,
DipoleSplittingInfo& dsplit,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators,
DipoleChain*& firstChain, DipoleChain*& secondChain,
bool colourSpectator = true);
/**
* Let the given dipole take the recoil of
* the indicated splitting.
*/
void recoil(list<Dipole>::iterator dip,
list<DipoleChain>::iterator ch,
DipoleSplittingInfo& dsplit);
/**
* Peform a subleading-N splitting
*/
void splitSubleading(SubleadingSplittingInfo& dsplit,
pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators,
DipoleChain*& firstChain, DipoleChain*& secondChain);
/**
* Update the particles upon insertion of the
* given splitting.
*/
void update(DipoleSplittingInfo& dsplit);
/**
* As update, but not touching the acctual event record.
*/
pair<PVector,PVector> tmpupdate(DipoleSplittingInfo& dsplit);
/**
* Return the dipole(s) containing the incoming
* partons after the evolution has ended. Put back
* the chains containing these to the chains to be
* showered.
*/
list<pair<list<Dipole>::iterator,list<DipoleChain>::iterator> >
inDipoles();
/**
* Fill the given step and return incoming partons.
*/
tPPair fillEventRecord(StepPtr step, bool firstInteraction, bool realigned);
public:
/**
* Prepare the event record for the given
* subprocess.
*/
const map<PPtr,PPtr>& prepare(tSubProPtr subpro,
tStdXCombPtr xc,
StepPtr step,
const pair<PDF,PDF>& pdf,
tPPair beam,
bool firstInteraction,
+ const set<long>& offShellPartons,
bool dipoles = true);
/**
* Prepare the event record for the given
* subprocess.
*/
void slimprepare(tSubProPtr subpro,
tStdXCombPtr xc,
const pair<PDF,PDF>& pdf,tPPair beam,
+ const set<long>& offShellPartons,
bool dipoles = true);
/**
* Clear the event record: Give up ownership
* on any object involved in the evolution.
*/
virtual void clear();
public:
/**
* Print event record at current state.
*/
void debugLastEvent(ostream&) const;
public:
/**
* Get the decays
*/
map<PPtr,PerturbativeProcessPtr> & decays() {return theDecays;}
/**
* Used in DipoleEventRecord::prepare.
* Add the outgoing particles from a perturbative
* process to the vector of original particles.
* Iterates through decay chains.
**/
void fillFromDecays(PerturbativeProcessPtr decayProc, vector<PPtr>& original);
/**
* Used in DipoleEventRecord::prepare.
* Replace the particles in the given
* perturbative process with their copies from the
* map, theOriginals.
* Iterates through decays chains.
**/
void separateDecay(PerturbativeProcessPtr decayProc);
/**
* Decay the particle
*/
Energy decay(PPtr incoming, bool& powhegEmission);
/**
* Prepare the event record for the showering of a decay.
* Return false if the decay does not need to be showered.
**/
- bool prepareDecay(PerturbativeProcessPtr decayProc);
+ bool prepareDecay(PerturbativeProcessPtr decayProc,
+ const set<long>& offShellPartons);
/**
* Boost the momentum of the outgoing of the given
* perturbative process to the momentum of given particle.
**/
void updateDecayMom(PPtr decayParent, PerturbativeProcessPtr decayProc);
/**
* Iteratively update the momenta of all
* particles in a decay chain, starting
* with the outgoing from the given parent
**/
void updateDecayChainMom(PPtr decayParent, PerturbativeProcessPtr decayProc);
/**
* Update theDecays following the decay and/or
* showering of a decay particle.
* With iteration switched on (true) this will
* update theDecays with the entire decay chain.
`**/
void updateDecays(PerturbativeProcessPtr decayProc, bool iterate = true);
/**
* Access current decay process
*/
PerturbativeProcessPtr currentDecay() {return theCurrentDecay;}
/**
* Set current decay process
*/
void currentDecay(PerturbativeProcessPtr in) {theCurrentDecay=in;}
// SW - Changed from protected to public so that functions can be used in DipoleShowerHandler
public:
/**
* Find the chains to be showered.
* The decay bool avoids mixing up decaying particles in hard and decay processes
*/
- void findChains(const PList& ordered, const bool decay = false);
+ void findChains(const PList& ordered,
+ const set<long>& offShellpartons,
+ const bool decay = false);
/**
* Sort the coloured partons into a colour ordered ensemble.
*/
PList colourOrdered(PPair & in,PList & out);
private:
struct getMomentum {
const Lorentz5Momentum& operator() (PPtr particle) const {
return particle->momentum();
}
};
/**
* The momentum of the hard system
*/
Lorentz5Momentum thePX;
/**
* Any non-coloured outgoing particles in the
* current subprocess.
*/
PList theHard;
/**
* Map originals to copies.
*/
map<PPtr,PPtr> theOriginals;
/**
* The dipole chains currently showered.
*/
list<DipoleChain> theChains;
/**
* The dipole chains which ceased evolving.
*/
list<DipoleChain> theDoneChains;
+ /**
+ * The coloured partons that can be off-shell
+ * To only be filled by DipoleShowerHandler.
+ **/
+
+
+
private:
/**
* Storage of the particles which need to be decayed
*/
map<PPtr,PerturbativeProcessPtr> theDecays;
/**
*
*/
PerturbativeProcessPtr theCurrentDecay;
};
}
#endif /* HERWIG_DipoleEventRecord_H */
diff --git a/Shower/Dipole/Base/DipoleSplittingGenerator.cc b/Shower/Dipole/Base/DipoleSplittingGenerator.cc
--- a/Shower/Dipole/Base/DipoleSplittingGenerator.cc
+++ b/Shower/Dipole/Base/DipoleSplittingGenerator.cc
@@ -1,823 +1,875 @@
// -*- C++ -*-
//
// DipoleSplittingGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DipoleSplittingGenerator class.
//
#include <config.h>
#include "DipoleSplittingGenerator.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Shower/Dipole/DipoleShowerHandler.h"
using namespace Herwig;
DipoleSplittingGenerator::DipoleSplittingGenerator()
: HandlerBase(),
theExponentialGenerator(0), prepared(false), presampling(false),
theDoCompensate(false), theSplittingWeight(1.) {
if ( ShowerHandler::currentHandler() )
setGenerator(ShowerHandler::currentHandler()->generator());
}
DipoleSplittingGenerator::~DipoleSplittingGenerator() {
if ( theExponentialGenerator ) {
delete theExponentialGenerator;
theExponentialGenerator = 0;
}
}
IBPtr DipoleSplittingGenerator::clone() const {
return new_ptr(*this);
}
IBPtr DipoleSplittingGenerator::fullclone() const {
return new_ptr(*this);
}
void DipoleSplittingGenerator::wrap(Ptr<DipoleSplittingGenerator>::ptr other) {
assert(!prepared);
theOtherGenerator = other;
}
void DipoleSplittingGenerator::resetVariations() {
for ( map<string,double>::iterator w = currentWeights.begin();
w != currentWeights.end(); ++w )
w->second = 1.;
}
void DipoleSplittingGenerator::veto(const vector<double>&, double p, double r) {
double factor = 1.;
if ( splittingReweight() ) {
if ( ( ShowerHandler::currentHandler()->firstInteraction() &&
splittingReweight()->firstInteraction() ) ||
( !ShowerHandler::currentHandler()->firstInteraction() &&
splittingReweight()->secondaryInteractions() ) ) {
factor = splittingReweight()->evaluate(generatedSplitting);
theSplittingWeight *= (r-factor*p)/(r-p);
}
}
splittingKernel()->veto(generatedSplitting, factor*p, r, currentWeights);
}
void DipoleSplittingGenerator::accept(const vector<double>&, double p, double r) {
double factor = 1.;
if ( splittingReweight() ) {
if ( ( ShowerHandler::currentHandler()->firstInteraction() &&
splittingReweight()->firstInteraction() ) ||
( !ShowerHandler::currentHandler()->firstInteraction() &&
splittingReweight()->secondaryInteractions() ) ) {
factor = splittingReweight()->evaluate(generatedSplitting);
theSplittingWeight *= factor;
}
}
splittingKernel()->accept(generatedSplitting, factor*p, r, currentWeights);
}
void DipoleSplittingGenerator::prepare(const DipoleSplittingInfo& sp) {
generatedSplitting = sp;
generatedSplitting.splittingKinematics(splittingKernel()->splittingKinematics());
generatedSplitting.splittingParameters().resize(splittingKernel()->nDimAdditional());
if ( wrapping() ) {
generatedSplitting.emitterData(theSplittingKernel->emitter(generatedSplitting.index()));
generatedSplitting.spectatorData(theSplittingKernel->spectator(generatedSplitting.index()));
generatedSplitting.emissionData(theSplittingKernel->emission(generatedSplitting.index()));
parameters.resize(theOtherGenerator->nDim());
prepared = true;
return;
}
generatedSplitting.emitterData(splittingKernel()->emitter(generatedSplitting.index()));
generatedSplitting.spectatorData(splittingKernel()->spectator(generatedSplitting.index()));
generatedSplitting.emissionData(splittingKernel()->emission(generatedSplitting.index()));
presampledSplitting = generatedSplitting;
prepared = true;
parameters.resize(nDim());
theExponentialGenerator =
new exsample::exponential_generator<DipoleSplittingGenerator,UseRandom>();
theExponentialGenerator->sampling_parameters().maxtry = maxtry();
theExponentialGenerator->sampling_parameters().presampling_points = presamplingPoints();
theExponentialGenerator->sampling_parameters().freeze_grid = freezeGrid();
theExponentialGenerator->detuning(detuning());
theExponentialGenerator->docompensate(theDoCompensate);
theExponentialGenerator->function(this);
theExponentialGenerator->initialize();
}
void DipoleSplittingGenerator::fixParameters(const DipoleSplittingInfo& sp,
Energy optHardPt) {
assert(generator());
assert(!presampling);
assert(prepared);
assert(sp.index() == generatedSplitting.index());
generatedSplitting.scale(sp.scale());
- // For dipoles containing a decayed particle,
- // the scale is fixed but the mass of the recoil
- // system is not so sample over recoilMass(),
- // so the parameter is related to recoilMass()
- if (generatedSplitting.index().incomingDecayEmitter() ||
- generatedSplitting.index().incomingDecaySpectator() ) {
+ // If dealing with a decay, need to set recoilMass
+ if ( generatedSplitting.index().incomingDecaySpectator() ||
+ generatedSplitting.index().incomingDecayEmitter() )
generatedSplitting.recoilMass(sp.recoilMass());
+
+ // Need to copy emitter and spectator masses
+ generatedSplitting.emitterMass(sp.emitterMass());
+ generatedSplitting.spectatorMass(sp.spectatorMass());
+
+ // Counter to track if there is an off-shell
+ // emitter AND/OR spectator
+ int count = parameters.size()-1;
+
+ // Off shell spectator mass
+ if ( sp.index().offShellSpectator() ) {
+ parameters[count] = sp.spectatorMass()/generator()->maximumCMEnergy();
+ count -= 1;
+ }
+
+ // Off shell emitter mass
+ if ( sp.index().offShellEmitter() )
+ parameters[count] = sp.emitterMass()/generator()->maximumCMEnergy();
+
+
+ // If not a decay, point[3] samples over the dipole scale
+ if ( !sp.index().incomingDecaySpectator() && !sp.index().incomingDecayEmitter() )
+ parameters[3] = sp.scale()/generator()->maximumCMEnergy();
+ // If it is a decay, point[3] samples over the recoilMass
+ else
parameters[3] = sp.recoilMass()/generator()->maximumCMEnergy();
- }
- // If not a decay dipole, sample over the scale of the dipole,
- // so the parameter is related to scale()
- else
- parameters[3] = sp.scale()/generator()->maximumCMEnergy();
-
+
generatedSplitting.hardPt(sp.hardPt());
parameters[0] = splittingKinematics()->ptToRandom(optHardPt == ZERO ?
generatedSplitting.hardPt() :
min(generatedSplitting.hardPt(),optHardPt),
sp.scale(),
sp.emitterX(), sp.spectatorX(),
generatedSplitting.index(),
*splittingKernel());
size_t shift = 4;
if ( generatedSplitting.index().emitterPDF().pdf() &&
generatedSplitting.index().spectatorPDF().pdf() ) {
generatedSplitting.emitterX(sp.emitterX());
generatedSplitting.spectatorX(sp.spectatorX());
parameters[4] = sp.emitterX();
parameters[5] = sp.spectatorX();
shift += 2;
}
if ( generatedSplitting.index().emitterPDF().pdf() &&
!generatedSplitting.index().spectatorPDF().pdf() ) {
generatedSplitting.emitterX(sp.emitterX());
parameters[4] = sp.emitterX();
++shift;
}
if ( !generatedSplitting.index().emitterPDF().pdf() &&
generatedSplitting.index().spectatorPDF().pdf() ) {
generatedSplitting.spectatorX(sp.spectatorX());
parameters[4] = sp.spectatorX();
++shift;
}
if ( splittingKernel()->nDimAdditional() )
copy(sp.lastSplittingParameters().begin(),
sp.lastSplittingParameters().end(),
parameters.begin()+shift);
if ( sp.emitter() )
generatedSplitting.emitter(sp.emitter());
if ( sp.spectator() )
generatedSplitting.spectator(sp.spectator());
}
int DipoleSplittingGenerator::nDim() const {
assert(!wrapping());
assert(prepared);
- int ret = 4; // 0 pt, 1 z, 2 phi, 3 scale, 4/5 xs + parameters
+ // Note this use of [3] for either the scale or the recoil mass
+ // is a bit of a nasty hack.
+ int ret = 4; // 0 pt, 1 z, 2 phi, 3 scale or recoilMass, 4/5 xs + parameters
if ( generatedSplitting.index().emitterPDF().pdf() ) {
++ret;
}
if ( generatedSplitting.index().spectatorPDF().pdf() ) {
++ret;
}
ret += splittingKernel()->nDimAdditional();
+ assert(splittingKernel()->nDimAdditional() == 0);
+ // Put off-shell spectator mass at back [-1]
+ // followed by off-shell emitter mass (i.e. [-1] or [-2])
+
+ // Off-shell emitter
+ if ( generatedSplitting.index().offShellEmitter() )
+ ++ret;
+
+ // Off-shell spectator
+ if ( generatedSplitting.index().offShellSpectator() )
+ ++ret;
+
+
return ret;
}
const vector<bool>& DipoleSplittingGenerator::sampleFlags() {
assert(!wrapping());
if ( !theFlags.empty() )
return theFlags;
theFlags.resize(nDim(),false);
theFlags[0] = true; theFlags[1] = true; theFlags[2] = true; // 0 pt, 1 z, 2 phi
return theFlags;
}
const pair<vector<double>,vector<double> >& DipoleSplittingGenerator::support() {
assert(!wrapping());
if ( !theSupport.first.empty() )
return theSupport;
vector<double> lower(nDim(),0.);
vector<double> upper(nDim(),1.);
pair<double,double> kSupport =
generatedSplitting.splittingKinematics()->kappaSupport(generatedSplitting);
pair<double,double> xSupport =
generatedSplitting.splittingKinematics()->xiSupport(generatedSplitting);
lower[0] = kSupport.first;
lower[1] = xSupport.first;
upper[0] = kSupport.second;
upper[1] = xSupport.second;
theSupport.first = lower;
theSupport.second = upper;
return theSupport;
}
void DipoleSplittingGenerator::startPresampling() {
assert(!wrapping());
splittingKernel()->startPresampling(generatedSplitting.index());
presampling = true;
}
void DipoleSplittingGenerator::stopPresampling() {
assert(!wrapping());
splittingKernel()->stopPresampling(generatedSplitting.index());
presampling = false;
}
bool DipoleSplittingGenerator::haveOverestimate() const {
assert(!wrapping());
assert(prepared);
return
generatedSplitting.splittingKinematics()->haveOverestimate() &&
splittingKernel()->haveOverestimate(generatedSplitting);
}
double DipoleSplittingGenerator::overestimate(const vector<double>& point) {
assert(!wrapping());
assert(prepared);
assert(!presampling);
assert(haveOverestimate());
if ( ! generatedSplitting.splittingKinematics()->generateSplitting(point[0],point[1],point[2],
generatedSplitting,
*splittingKernel()) )
return 0.;
generatedSplitting.splittingKinematics()->prepareSplitting(generatedSplitting);
return
( generatedSplitting.splittingKinematics()->jacobianOverestimate() *
splittingKernel()->overestimate(generatedSplitting) );
}
double DipoleSplittingGenerator::invertOverestimateIntegral(double value) const {
assert(!wrapping());
assert(prepared);
assert(!presampling);
assert(haveOverestimate());
return
splittingKernel()->invertOverestimateIntegral(generatedSplitting,value);
}
double DipoleSplittingGenerator::evaluate(const vector<double>& point) {
assert(!wrapping());
assert(prepared);
assert(generator());
DipoleSplittingInfo& split =
( !presampling ? generatedSplitting : presampledSplitting );
split.continuesEvolving();
size_t shift = 4;
if ( presampling ) {
- // For dipoles containing a decayed particle,
- // the scale is fixed but the mass of the recoil
- // system is not so sample over recoilMass()
- if ( split.index().incomingDecaySpectator() ) {
- split.scale(split.index().spectatorData()->mass());
- split.recoilMass(point[3] * generator()->maximumCMEnergy());
+ // Counter to track if there is an off-shell
+ // emitter AND/OR spectator
+ int count = parameters.size()-1;
+
+ // Sample over off-shell emitter and spectator masss
+ // Do not sample if zero mass or off-shell
+ if ( split.index().spectatorData()->mass() != ZERO ) {
+ if ( !split.index().offShellSpectator() )
+ split.spectatorMass(split.index().spectatorData()->mass());
+ else {
+ split.spectatorMass(point[count] * generator()->maximumCMEnergy());
+ count -= 1;
+ }
}
- // Currently do not have decaying emitters
- //else if ( split.index().incomingDecayEmitter() ) {
- // split.scale(split.index().emitterData()->mass());
- // split.recoilMass(point[3] * generator()->maximumCMEnergy());
- //}
-
- // If not a decay dipole, sample over the scale of the dipole
+ if ( split.index().emitterData()->mass() != ZERO ) {
+ if ( !split.index().offShellEmitter() )
+ split.emitterMass(split.index().emitterData()->mass());
+ else
+ split.emitterMass(point[count] * generator()->maximumCMEnergy());
+ }
+
+ // If not a decay, point[3] samples over the dipole scale
+ if ( ! split.index().incomingDecaySpectator()
+ && ! split.index().incomingDecayEmitter() )
+ split.scale(point[3] * generator()->maximumCMEnergy());
+
+ // For dipoles containing a decayed spectator:
+ // 1) Use point[3] to sample over the recoil mass
+ // 2) The dipole scale is the spectator mass
+ else if ( split.index().incomingDecaySpectator() ) {
+ split.recoilMass(point[3] * generator()->maximumCMEnergy());
+ assert(split.spectatorMass() != ZERO );
+ split.scale(split.spectatorMass());
+ }
+ // Not currently intended to work with decaying emitters
else
- split.scale(point[3] * generator()->maximumCMEnergy());
-
-
+ assert(false);
+
if ( split.index().emitterPDF().pdf() &&
split.index().spectatorPDF().pdf() ) {
split.emitterX(point[4]);
split.spectatorX(point[5]);
shift += 2;
}
-
+
if ( split.index().emitterPDF().pdf() &&
!split.index().spectatorPDF().pdf() ) {
split.emitterX(point[4]);
++shift;
}
-
+
if ( !split.index().emitterPDF().pdf() &&
split.index().spectatorPDF().pdf() ) {
split.spectatorX(point[4]);
++shift;
}
-
+
if ( splittingKernel()->nDimAdditional() )
copy(point.begin()+shift,point.end(),split.splittingParameters().begin());
-
+
split.hardPt(split.splittingKinematics()->ptMax(split.scale(),
split.emitterX(),
split.spectatorX(),
split,
*splittingKernel()));
}
if ( ! split.splittingKinematics()->generateSplitting(point[0],
point[1],
point[2],
split,
*splittingKernel()) ) {
split.lastValue(0.);
return 0.;
}
split.splittingKinematics()->prepareSplitting(split);
if ( split.stoppedEvolving() ) {
split.lastValue(0.);
return 0.;
}
if ( !presampling )
splittingKernel()->clearAlphaPDFCache();
double kernel = splittingKernel()->evaluate(split);
double jac = split.splittingKinematics()->jacobian();
// multiply in the profile scales when relevant
assert(ShowerHandler::currentHandler());
if ( ShowerHandler::currentHandler()->firstInteraction() &&
ShowerHandler::currentHandler()->profileScales() &&
!presampling ) {
Energy hard = ShowerHandler::currentHandler()->hardScale();
if ( hard > ZERO )
kernel *= ShowerHandler::currentHandler()->profileScales()->
hardScaleProfile(hard,split.lastPt());
}
split.lastValue( abs(jac) * kernel );
if ( ! isfinite(split.lastValue()) ) {
generator()->log() << "DipoleSplittingGenerator:evaluate():"
<<"problematic splitting kernel encountered for "
<< splittingKernel()->name() << "\n" << flush;
split.lastValue(0.0);
}
if ( kernel < 0. )
return 0.;
return split.lastValue();
}
void DipoleSplittingGenerator::doGenerate(map<string,double>& variations,
Energy optCutoff) {
assert(!wrapping());
double res = 0.;
Energy startPt = generatedSplitting.hardPt();
double optKappaCutoff = 0.0;
if ( optCutoff > splittingKinematics()->IRCutoff() ) {
optKappaCutoff = splittingKinematics()->ptToRandom(optCutoff,
generatedSplitting.scale(),
generatedSplitting.emitterX(),
generatedSplitting.spectatorX(),
generatedSplitting.index(),
*splittingKernel());
}
resetVariations();
theSplittingWeight = 1.;
double enhance = 1.;
if ( splittingReweight() ) {
if ( ( ShowerHandler::currentHandler()->firstInteraction() &&
splittingReweight()->firstInteraction() ) ||
( !ShowerHandler::currentHandler()->firstInteraction() &&
splittingReweight()->secondaryInteractions() ) ) {
enhance = splittingReweight()->hint(generatedSplitting);
}
}
while (true) {
try {
if ( optKappaCutoff == 0.0 ) {
res = theExponentialGenerator->generate(enhance);
} else {
res = theExponentialGenerator->generate(optKappaCutoff,enhance);
}
} catch (exsample::exponential_regenerate&) {
resetVariations();
theSplittingWeight = 1.;
generatedSplitting.hardPt(startPt);
continue;
} catch (exsample::hit_and_miss_maxtry&) {
throw DipoleShowerHandler::RedoShower();
} catch (exsample::selection_maxtry&) {
throw DipoleShowerHandler::RedoShower();
}
break;
}
for ( map<string,double>::const_iterator w = currentWeights.begin();
w != currentWeights.end(); ++w ) {
map<string,double>::iterator v = variations.find(w->first);
if ( v != variations.end() )
v->second *= w->second;
else
variations[w->first] = w->second;
}
if ( res == 0. ) {
generatedSplitting.lastPt(0.0*GeV);
generatedSplitting.didStopEvolving();
} else {
generatedSplitting.continuesEvolving();
if ( theMCCheck )
theMCCheck->book(generatedSplitting.emitterX(),
generatedSplitting.spectatorX(),
generatedSplitting.scale(),
startPt,
generatedSplitting.lastPt(),
generatedSplitting.lastZ(),
1.);
}
}
Energy DipoleSplittingGenerator::generate(const DipoleSplittingInfo& split,
map<string,double>& variations,
Energy optHardPt,
Energy optCutoff) {
fixParameters(split,optHardPt);
if ( wrapping() ) {
return theOtherGenerator->generateWrapped(generatedSplitting,variations,optHardPt,optCutoff);
}
doGenerate(variations,optCutoff);
return generatedSplitting.lastPt();
}
double DipoleSplittingGenerator::sudakovExpansion(const DipoleSplittingInfo& split,
Energy down,Energy fixedScale){
fixParameters(split);
if ( wrapping() ) {
return theOtherGenerator->wrappedSudakovExpansion( generatedSplitting, down,fixedScale);
}
return dosudakovExpansion( split, down,fixedScale);
}
double DipoleSplittingGenerator::sudakov(const DipoleSplittingInfo& split,Energy down){
fixParameters(split);
if ( wrapping() ) {
return theOtherGenerator->wrappedSudakov( generatedSplitting, down);
}
return dosudakov( split, down);
}
double DipoleSplittingGenerator::dosudakovExpansion(const DipoleSplittingInfo& ,
Energy down,Energy fixedScale){
assert(down > splittingKinematics()->IRCutoff());
double optKappaCutoffd =
splittingKinematics()->ptToRandom(down,
generatedSplitting.scale(),
generatedSplitting.emitterX(),
generatedSplitting.spectatorX(),
generatedSplitting.index(),
*splittingKernel());
double optKappaCutoffu = splittingKinematics()->ptToRandom(generatedSplitting.hardPt(),
generatedSplitting.scale(),
generatedSplitting.emitterX(),
generatedSplitting.spectatorX(),
generatedSplitting.index(),
*splittingKernel());
pair<double,double> xSupport =
generatedSplitting.splittingKinematics()->xiSupport(generatedSplitting);
vector<double> RN;
RN.resize(3);
double res=0.;
double resq=0.;
double varx=10.;
int k=0;
generatedSplitting.setCalcFixedExpansion(true);
generatedSplitting.fixedScale(fixedScale);
while ( k<1000 ){
k+=1.;
RN[0]= optKappaCutoffd+(optKappaCutoffu-optKappaCutoffd)*UseRandom::rnd(); //PT
RN[1]=xSupport.first+UseRandom::rnd()*(xSupport.second-xSupport.first); //
RN[2]= UseRandom::rnd(); //PHI
double tmp=(xSupport.second-xSupport.first)*
(optKappaCutoffu-optKappaCutoffd)*
evaluate(RN);
res+= tmp;
resq+=pow(tmp,2.);
if(k%50==0.){
varx=sqrt((resq/pow(1.*k,2)-pow(res,2)/pow(1.*k,3)))/(res/(1.0*k));
if(varx<theSudakovAccuracy)break;
}
}
generatedSplitting.setCalcFixedExpansion(false);
return -res/(1.0*k);
}
double DipoleSplittingGenerator::dosudakov(const DipoleSplittingInfo& ,Energy down){
double optKappaCutoffd = splittingKinematics()->ptToRandom(down,
generatedSplitting.scale(),
generatedSplitting.emitterX(),
generatedSplitting.spectatorX(),
generatedSplitting.index(),
*splittingKernel());
double optKappaCutoffu = splittingKinematics()->ptToRandom(generatedSplitting.hardPt(),
generatedSplitting.scale(),
generatedSplitting.emitterX(),
generatedSplitting.spectatorX(),
generatedSplitting.index(),
*splittingKernel());
pair<double,double> kSupport =
generatedSplitting.splittingKinematics()->kappaSupport(generatedSplitting);
assert(kSupport.first==0&&kSupport.second==1);
pair<double,double> xSupport =
generatedSplitting.splittingKinematics()->xiSupport(generatedSplitting);
vector<double> RN;
RN.resize(3);
double res=0.;
double resq=0.;
double var=10.;
double varx=10.;
int k=0;
while (((k<40.||var>theSudakovAccuracy)&&k<50000)){
k+=1.;
RN[0]= optKappaCutoffd+(optKappaCutoffu-optKappaCutoffd)*UseRandom::rnd(); //PT
RN[1]=xSupport.first+UseRandom::rnd()*(xSupport.second-xSupport.first); //Z
RN[2]=UseRandom::rnd(); //PHI
double tmp=(xSupport.second-xSupport.first)*
(optKappaCutoffu-optKappaCutoffd)*
evaluate(RN);
res+= tmp;
resq+=pow(tmp,2.);
if(k%20==0.){
varx=sqrt((resq/pow(1.*k,2)-pow(res,2)/pow(1.*k,3)));
var= (exp(-(res)/(1.0*k)+varx)-exp(-(res)/(1.0*k)-varx))/exp(-res/(1.0*k));
}
}
return exp(-res/(1.0*k));
}
double DipoleSplittingGenerator::wrappedSudakovExpansion(DipoleSplittingInfo& split,
Energy down,Energy fixedScale) {
assert(!wrapping());
DipoleSplittingInfo backup = generatedSplitting;
generatedSplitting = split;
fixParameters(split);
double res=dosudakovExpansion( split, down,fixedScale);
split = generatedSplitting;
generatedSplitting = backup;
return res;
}
double DipoleSplittingGenerator::wrappedSudakov(DipoleSplittingInfo& split,
Energy down) {
assert(!wrapping());
DipoleSplittingInfo backup = generatedSplitting;
generatedSplitting = split;
fixParameters(split);
double res=dosudakov( split, down);
split = generatedSplitting;
generatedSplitting = backup;
return res;
}
Energy DipoleSplittingGenerator::generateWrapped(DipoleSplittingInfo& split,
map<string,double>& variations,
Energy optHardPt,
Energy optCutoff) {
assert(!wrapping());
DipoleSplittingInfo backup = generatedSplitting;
generatedSplitting = split;
fixParameters(split,optHardPt);
try {
doGenerate(variations,optCutoff);
} catch (...) {
split = generatedSplitting;
generatedSplitting = backup;
throw;
}
Energy pt = generatedSplitting.lastPt();
split = generatedSplitting;
generatedSplitting = backup;
return pt;
}
void DipoleSplittingGenerator::completeSplitting(DipoleSplittingInfo& sp) const {
pair<bool,bool> conf = sp.configuration();
sp = generatedSplitting;
sp.configuration(conf);
}
Ptr<DipoleSplittingKernel>::tptr DipoleSplittingGenerator::splittingKernel() const {
if ( wrapping() )
return theOtherGenerator->splittingKernel();
return theSplittingKernel;
}
Ptr<DipoleSplittingReweight>::tptr DipoleSplittingGenerator::splittingReweight() const {
if ( wrapping() )
return theOtherGenerator->splittingReweight();
return theSplittingReweight;
}
Ptr<DipoleSplittingKinematics>::tptr DipoleSplittingGenerator::splittingKinematics() const {
if ( wrapping() )
return theOtherGenerator->splittingKinematics();
return theSplittingKernel->splittingKinematics();
}
void DipoleSplittingGenerator::splittingKernel(Ptr<DipoleSplittingKernel>::tptr sp) {
theSplittingKernel = sp;
if ( theSplittingKernel->mcCheck() )
theMCCheck = theSplittingKernel->mcCheck();
}
void DipoleSplittingGenerator::splittingReweight(Ptr<DipoleSplittingReweight>::tptr sp) {
theSplittingReweight = sp;
}
void DipoleSplittingGenerator::debugGenerator(ostream& os) const {
os << "--- DipoleSplittingGenerator ---------------------------------------------------\n";
os << " generating splittings using\n"
<< " splittingKernel = " << splittingKernel()->name()
<< " splittingKinematics = " << generatedSplitting.splittingKinematics()->name() << "\n"
<< " to sample splittings of type:\n";
os << generatedSplitting;
os << "--------------------------------------------------------------------------------\n";
}
void DipoleSplittingGenerator::debugLastEvent(ostream& os) const {
os << "--- DipoleSplittingGenerator ---------------------------------------------------\n";
os << " last generated event:\n";
os << generatedSplitting;
os << "--------------------------------------------------------------------------------\n";
}
// If needed, insert default implementations of virtual function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void DipoleSplittingGenerator::persistentOutput(PersistentOStream & os) const {
os << theOtherGenerator << theSplittingKernel << theSplittingReweight << theMCCheck << theDoCompensate;
}
void DipoleSplittingGenerator::persistentInput(PersistentIStream & is, int) {
is >> theOtherGenerator >> theSplittingKernel >> theSplittingReweight >> theMCCheck >> theDoCompensate;
}
ClassDescription<DipoleSplittingGenerator> DipoleSplittingGenerator::initDipoleSplittingGenerator;
// Definition of the static class description member.
void DipoleSplittingGenerator::Init() {
static ClassDocumentation<DipoleSplittingGenerator> documentation
("DipoleSplittingGenerator is used by the dipole shower "
"to sample splittings from a given dipole splitting kernel.");
static Reference<DipoleSplittingGenerator,DipoleSplittingKernel> interfaceSplittingKernel
("SplittingKernel",
"Set the splitting kernel to sample from.",
&DipoleSplittingGenerator::theSplittingKernel, false, false, true, false, false);
static Reference<DipoleSplittingGenerator,DipoleSplittingReweight> interfaceSplittingReweight
("SplittingReweight",
"Set the splitting reweight.",
&DipoleSplittingGenerator::theSplittingReweight, false, false, true, true, false);
static Reference<DipoleSplittingGenerator,DipoleMCCheck> interfaceMCCheck
("MCCheck",
"[debug option] MCCheck",
&DipoleSplittingGenerator::theMCCheck, false, false, true, true, false);
interfaceMCCheck.rank(-1);
}
diff --git a/Shower/Dipole/Base/DipoleSplittingInfo.cc b/Shower/Dipole/Base/DipoleSplittingInfo.cc
--- a/Shower/Dipole/Base/DipoleSplittingInfo.cc
+++ b/Shower/Dipole/Base/DipoleSplittingInfo.cc
@@ -1,173 +1,181 @@
// -*- C++ -*-
//
// DipoleSplittingInfo.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DipoleIndex and DipoleSplittingInfo classes.
//
#include "DipoleSplittingInfo.h"
#include <iterator>
using std::ostream_iterator;
using namespace Herwig;
DipoleIndex::DipoleIndex()
: theInitialStateEmitter(false), theIncomingDecayEmitter(false),
- theInitialStateSpectator(false), theIncomingDecaySpectator(false) {}
+ theOffShellEmitter(false),
+ theInitialStateSpectator(false), theIncomingDecaySpectator(false),
+ theOffShellSpectator(false) {}
+
DipoleIndex::DipoleIndex(tcPDPtr newEmitter, tcPDPtr newSpectator,
const PDF& newEmitterPDF, const PDF& newSpectatorPDF,
- const bool decayingEmitter, const bool decayingSpectator)
+ const bool decayingEmitter, const bool decayingSpectator,
+ const bool offShellEmitter, const bool offShellSpectator)
: theEmitterData(newEmitter), theInitialStateEmitter(newEmitterPDF.pdf()),
theIncomingDecayEmitter(decayingEmitter),
+ theOffShellEmitter(offShellEmitter),
theEmitterPDF(newEmitterPDF),
theSpectatorData(newSpectator), theInitialStateSpectator(newSpectatorPDF.pdf()),
theIncomingDecaySpectator(decayingSpectator),
+ theOffShellSpectator(offShellSpectator),
theSpectatorPDF(newSpectatorPDF) {}
// SW Note, this is used in DipoleShowerHandler.getWinner(),
// not including the comparison of the decay booleans led to a bug which took a long time to fix
// remember to update this function in case of new characteristics in DipoleIndex
bool DipoleIndex::operator ==(const DipoleIndex& x) const {
return
theEmitterData == x.theEmitterData &&
theInitialStateEmitter == x.theInitialStateEmitter &&
theEmitterPDF == x.theEmitterPDF &&
theIncomingDecayEmitter == x.incomingDecayEmitter() &&
theSpectatorData == x.theSpectatorData &&
theInitialStateSpectator == x.theInitialStateSpectator &&
theSpectatorPDF == x.theSpectatorPDF &&
theIncomingDecaySpectator == x.incomingDecaySpectator();
}
bool DipoleIndex::operator <(const DipoleIndex& x) const {
if ( theEmitterData == x.theEmitterData ) {
if ( theInitialStateEmitter == x.theInitialStateEmitter ) {
if ( theEmitterPDF == x.theEmitterPDF ) {
if ( theIncomingDecayEmitter == x.theIncomingDecayEmitter ) {
if ( theSpectatorData == x.theSpectatorData ) {
if ( theInitialStateSpectator == x.theInitialStateSpectator ) {
if ( theSpectatorPDF == x.theSpectatorPDF ) {
return theIncomingDecaySpectator < x.theIncomingDecaySpectator;
}
return theSpectatorPDF < x.theSpectatorPDF;
}
return theInitialStateSpectator < x.theInitialStateSpectator;
}
return theSpectatorData < x.theSpectatorData;
}
return theIncomingDecayEmitter < x.theIncomingDecayEmitter;
}
return theEmitterPDF < x.theEmitterPDF;
}
return theInitialStateEmitter < x.theInitialStateEmitter;
}
return theEmitterData < x.theEmitterData;
}
void DipoleIndex::swap() {
std::swap(theEmitterData,theSpectatorData);
std::swap(theInitialStateEmitter,theInitialStateSpectator);
std::swap(theEmitterPDF,theSpectatorPDF);
std::swap(theIncomingDecayEmitter,theIncomingDecaySpectator);
+ std::swap(theOffShellEmitter, theOffShellSpectator);
}
pair<DipoleIndex,DipoleIndex> DipoleIndex::split(tcPDPtr emm) const {
-
+ assert(false);
DipoleIndex first(emitterData(),emm,emitterPDF(),PDF());
DipoleIndex second(emm,spectatorData(),PDF(),spectatorPDF());
return {first,second};
}
void DipoleIndex::print(ostream& os) const {
os << "[" << emitterData()->PDGName();
if ( emitterPDF().pdf() ) {
os << "<-" << emitterPDF().particle()->PDGName()
<< "(" << emitterPDF().pdf() << ")";
}
os << "," << spectatorData()->PDGName();
if ( spectatorPDF().pdf() ) {
os << "<-" << spectatorPDF().particle()->PDGName()
<< "(" << spectatorPDF().pdf() << ")";
}
os << "]";
os << flush;
}
DipoleSplittingInfo::DipoleSplittingInfo()
: theConfiguration(false,false),
theSpectatorConfiguration(false,false),
theScale(0.0*GeV),theIsDecayProc(false), theRecoilMass(0.0*GeV),
+ theEmitterMass(0.0*GeV), theSpectatorMass(0.0*GeV),
theEmitterX(1.0), theSpectatorX(1.0),
theHardPt(0.0*GeV), theLastPt(0.0*GeV),
theLastZ(0.0), theLastPhi(0.0), theLastEmitterZ(0.0),
theLastSpectatorZ(0.0), theLastValue(0.0),
theStoppedEvolving(false),theCalcFixedExpansion(false) {}
void DipoleSplittingInfo::fill(const DipoleSplittingInfo& other) {
*this = other;
}
void DipoleSplittingInfo::print(ostream& os) const {
os << "--- DipoleSplittingInfo --------------------------------------------------------\n";
os << " index = " << theIndex << "\n";
os << " configuration = (" << theConfiguration.first << "," << theConfiguration.second << ")\n"
<< " momentum fractions = [" << theEmitterX << "," << theSpectatorX << "]\n"
<< " generated starting from hard pt/GeV = " << theHardPt/GeV << "\n";
if ( theEmitterData && theEmissionData && theSpectatorData ) {
os << " splitting products = [(" << theEmitterData->PDGName()
<< "," << theEmissionData->PDGName() << "),"
<< theSpectatorData->PDGName() << "]\n";
} else {
os << " splitting products not available.\n";
}
if ( theSplittingKinematics ) {
os << " kinematic variables associated to '" << theSplittingKinematics->name() << "':\n"
<< " scale = " << (theScale/GeV)
<< " pt/GeV = " << (theLastPt/GeV) << " z = " << theLastZ << " phi = " << theLastPhi << "\n"
<< " emitter z = " << theLastEmitterZ << " spectator z = " << theLastSpectatorZ << "\n"
<< " splitting kernel value = " << theLastValue << "\n"
<< " further parameters = ";
copy(theLastSplittingParameters.begin(),theLastSplittingParameters.end(),ostream_iterator<double>(os," "));
os << "\n the splitting " << (theStoppedEvolving ? "terminated " : "did not terminate ") << "the evolution\n";
} else {
os << " No kinematic variables have been generated yet.\n";
}
if ( theEmitter && theSpectator && theSplitEmitter && theSplitSpectator && theEmission ) {
os << " the splitting has been performed:\n"
<< " emitter before emission:\n" << (*theEmitter)
<< " spectator before emission:\n" << (*theSpectator)
<< " emitter after emission:\n" << (*theSplitEmitter)
<< " emission:\n" << (*theEmission)
<< " spectator after emission:\n" << (*theSplitSpectator);
} else {
os << " the splitting has not yet been performed.\n";
}
os << "--------------------------------------------------------------------------------\n";
os << flush;
}
diff --git a/Shower/Dipole/Base/DipoleSplittingInfo.h b/Shower/Dipole/Base/DipoleSplittingInfo.h
--- a/Shower/Dipole/Base/DipoleSplittingInfo.h
+++ b/Shower/Dipole/Base/DipoleSplittingInfo.h
@@ -1,729 +1,791 @@
// -*- C++ -*-
//
// DipoleSplittingInfo.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_DipoleSplittingInfo_H
#define HERWIG_DipoleSplittingInfo_H
//
// This is the declaration of the DipoleIndex and DipoleSplittingInfo classes.
//
#include "ThePEG/PDF/PDF.h"
#include "ThePEG/PDT/ParticleData.h"
#include "Herwig/Shower/Dipole/Kinematics/DipoleSplittingKinematics.h"
namespace Herwig {
using namespace ThePEG;
class DipoleSplittingKinematics;
/**
* \ingroup DipoleShower
* \author Simon Platzer, Stephen Webster
*
* \brief DipoleIndex is used to index splitting generators
* for a particular dipole.
*
*/
class DipoleIndex {
public:
/**
* The default constructor.
*/
DipoleIndex();
/**
* The standard constructor
*/
DipoleIndex(tcPDPtr newEmitter, tcPDPtr newSpectator,
const PDF& newEmitterPDF = PDF(), const PDF& newSpectatorPDF = PDF(),
- const bool decayingEmitter = false, const bool decayingSpectator = false);
+ const bool decayingEmitter = false, const bool decayingSpectator = false,
+ const bool offShellEmitter = false, const bool offShellSpectator = false);
public:
/**
* Compare for equality.
*/
bool operator ==(const DipoleIndex& x) const;
/**
* Compare for ordering.
*/
bool operator <(const DipoleIndex& x) const;
/**
* Swap emitter and spectator.
*/
void swap();
/**
* Produce a pair of dipole indices given
* a particle data object for the emission.
* The ME correction is ignored in the children.
* The emission is inserted between the emitter
* and spectator, being a spectator in the first
* dipole index containing the original emitter,
* and an emitter in the second dipole, containing
* the original spectator.
*/
pair<DipoleIndex,DipoleIndex> split(tcPDPtr) const;
public:
/**
* Return the emitter particle data object.
*/
tcPDPtr emitterData() const { return theEmitterData; }
/**
* Return true, if the emitter is an incoming parton
*/
bool initialStateEmitter() const { return theInitialStateEmitter; }
/**
* Return true, if the emitter is incoming to a decay
*/
bool incomingDecayEmitter() const { return theIncomingDecayEmitter; }
/**
+ * Return true, if the emitter can be off-shell
+ */
+ bool offShellEmitter() const { return theOffShellEmitter; }
+ //bool offShellEmitter() const { return theEmitterData->width() != ZERO; }
+
+ /**
* Return the PDF object associated with the emitter
*/
const PDF& emitterPDF() const { return theEmitterPDF; }
/**
* Return the spectator particle data object.
*/
tcPDPtr spectatorData() const { return theSpectatorData; }
/**
* Return true, if the spectator is an incoming parton
*/
bool initialStateSpectator() const { return theInitialStateSpectator; }
/**
* Return true, if the spectator is incoming to a decay
*/
bool incomingDecaySpectator() const { return theIncomingDecaySpectator; }
/**
+ * Return true, if the spectator can be off-shell
+ */
+ bool offShellSpectator() const { return theOffShellSpectator; }
+ //bool offShellSpectator() const { return theSpectatorData->width() != ZERO; }
+
+ /**
* Return the PDF object associated with the spectator
*/
const PDF& spectatorPDF() const { return theSpectatorPDF; }
public:
/**
* Put information to ostream
*/
void print(ostream&) const;
private:
/**
* The particle data object of the emitter.
*/
tcPDPtr theEmitterData;
/**
* Whether or not the emitter is an incoming parton.
*/
bool theInitialStateEmitter;
/**
* Whether or not the emitter is incoming to a decay.
*/
bool theIncomingDecayEmitter;
/**
+ * Can the emitter be off-shell?
+ */
+ bool theOffShellEmitter;
+
+ /**
* The PDF object for the emitter.
*/
PDF theEmitterPDF;
/**
* The particle data object of the spectator.
*/
tcPDPtr theSpectatorData;
/**
* Whether or not the spectator is an incoming parton.
*/
bool theInitialStateSpectator;
/**
* Whether or not the spectator is incoming to a decay.
*/
bool theIncomingDecaySpectator;
+
+ /**
+ * Can the spectator be off-shell?
+ */
+ bool theOffShellSpectator;
/**
* The PDF object for the spectator.
*/
PDF theSpectatorPDF;
};
inline ostream& operator << (ostream& os, const DipoleIndex& di) {
di.print(os);
return os;
}
/**
* \ingroup DipoleShower
* \author Simon Platzer
*
* \brief DipoleSplittingInfo contains all parameters to generate a full
* dipole splitting.
*
*/
class DipoleSplittingInfo {
public:
/**
* The default constructor.
*/
DipoleSplittingInfo();
/**
* Destructor
*/
virtual ~DipoleSplittingInfo() {}
/**
* Standard constructor.
*/
DipoleSplittingInfo(DipoleIndex ind,pair<bool,bool> conf,double emitX,
double spectX,tPPtr emit,tPPtr spect){
theIndex=ind;
theConfiguration=conf;
theEmitterX=emitX;
theSpectatorX=spectX;
theEmitter=emit;
theSpectator=spect;
}
public:
/**
* Assign data from another splitting info
*/
void fill(const DipoleSplittingInfo&);
public:
/**
* Return the dipole index
*/
const DipoleIndex& index() const { return theIndex; }
/**
* Return which of the particles
* in the dipole should be considered emitter (true)
* and spectator (false)
*/
const pair<bool,bool>& configuration() const { return theConfiguration; }
/**
* Get the configuration marking the spectator
*/
const pair<bool,bool>& spectatorConfiguration() const { return theSpectatorConfiguration; }
/**
* Return the particle data object of the emitter
* after the splitting.
*/
tcPDPtr emitterData() const { return theEmitterData; }
/**
* Return the particle data object of the emission
* after the splitting.
*/
tcPDPtr emissionData() const { return theEmissionData; }
/**
* Return the particle data object of the spectator
* after the splitting.
*/
tcPDPtr spectatorData() const { return theSpectatorData; }
/**
* Return the momentum fraction of the emitter.
*/
double emitterX() const { return theEmitterX; }
/**
* Return the momentum fraction of the spectator.
*/
double spectatorX() const { return theSpectatorX; }
public:
/**
* Return a pointer to the DipoleSplittingKinematics object
* which is to be used to perform the splitting.
*/
Ptr<DipoleSplittingKinematics>::tptr splittingKinematics() const { return theSplittingKinematics; }
/**
* Return the dipole scale
*/
Energy scale() const { return theScale; }
/**
* Return whether or not this dipole is
* part of a decay process.
**/
bool isDecayProc() const { return theIsDecayProc; }
/**
* Return the mass of the recoil system
* in decay dipoles.
*/
Energy recoilMass() const { return theRecoilMass; }
/**
+ * Return the spectator mass
+ * (to cope with off-shell particles)
+ **/
+ Energy spectatorMass() const { return theSpectatorMass; }
+
+ /**
+ * Return the emitter mass
+ * (to cope with off-shell particles)
+ **/
+ Energy emitterMass() const { return theEmitterMass; }
+
+ /**
* Return the pt below which this
* splitting has been generated.
*/
Energy hardPt() const { return theHardPt; }
/**
* Return the last generated pt
*/
Energy lastPt() const { return theLastPt; }
/**
* Return the last generated momentum fraction.
*/
double lastZ() const { return theLastZ; }
/**
* Return the last generated azimuthal angle.
*/
double lastPhi() const { return theLastPhi; }
/**
* Return the momentum fraction, by which the emitter's
* momentum fraction should be divided after the splitting.
*/
double lastEmitterZ() const { return theLastEmitterZ; }
/**
* Return the momentum fraction, by which the spectator's
* momentum fraction should be divided after the splitting.
*/
double lastSpectatorZ() const { return theLastSpectatorZ; }
/**
* Return any additional parameters needed to
* evaluate the splitting kernel or to generate the
* full splitting.
*/
const vector<double>& lastSplittingParameters() const { return theLastSplittingParameters; }
/**
* Return true, if this splitting will terminate
* the evolution of the dipole considered.
*/
bool stoppedEvolving() const { return theStoppedEvolving; }
public:
/**
* Set the index.
*/
void index(const DipoleIndex& ind) { theIndex = ind; }
/**
* Set the DipoleSplittingKinematics object
*/
void splittingKinematics(Ptr<DipoleSplittingKinematics>::tptr newSplittingKinematics) {
theSplittingKinematics = newSplittingKinematics;
}
/**
* Set the particle data object of the emitter
* after the splitting.
*/
void emitterData(tcPDPtr p) { theEmitterData = p; }
/**
* Set the particle data object of the emission
* after the splitting.
*/
void emissionData(tcPDPtr p) { theEmissionData = p; }
/**
* Set the particle data object of the spectator
* after the splitting.
*/
void spectatorData(tcPDPtr p) { theSpectatorData = p; }
/**
* Set the dipole scale
*/
void scale(Energy s) { theScale = s; }
/**
* Set whether or not this dipole is
* part of a decay process.
**/
void isDecayProc(bool isDecayProc) { theIsDecayProc = isDecayProc; }
/**
* Set the mass of the recoil system
* in decay dipoles
*/
void recoilMass(Energy mass) { theRecoilMass = mass; }
-
/**
+ * Set the spectator mass
+ * (to cope with off-shell particles)
+ **/
+ void spectatorMass(Energy mass){ theSpectatorMass = mass; }
+
+ /**
+ * Set the emitter mass
+ * (to cope with off-shell particles)
+ **/
+ void emitterMass(Energy mass){ theEmitterMass = mass; }
+
+ /**
* Set the emitter's momentum fraction
*/
void emitterX(double x) { theEmitterX = x; }
/**
* Set the spectator's momentum fraction
*/
void spectatorX(double x) { theSpectatorX = x; }
/**
* Set the pt below which this
* splitting has been generated.
*/
void hardPt(Energy p) { theHardPt = p; }
-
+
/**
* Set the last generated pt
*/
void lastPt(Energy p) { theLastPt = p; }
/**
* Set the last generated momentum fraction.
*/
void lastZ(double z) { theLastZ = z; }
/**
* Set the last generated azimuthal angle.
*/
void lastPhi(double p) { theLastPhi = p; }
/**
* Set the momentum fraction, by which the emitter's
* momentum fraction should be divided after the splitting.
*/
void lastEmitterZ(double z) { theLastEmitterZ = z; }
/**
* Set the momentum fraction, by which the spectator's
* momentum fraction should be divided after the splitting.
*/
void lastSpectatorZ(double z) { theLastSpectatorZ = z; }
/**
* Return the last splitting kernel value encountered.
*/
double lastValue() const { return theLastValue; }
/**
* Set the last splitting kernel value encountered.
*/
void lastValue(double v) { theLastValue = v; }
/**
* Set the flag to calculate the Sudakov with fixed scales.
*/
void setCalcFixedExpansion(bool c){theCalcFixedExpansion=c;}
/**
* Flag to calculate the Sudakov with fixed scales.
*/
bool calcFixedExpansion()const{ return theCalcFixedExpansion;}
/**
* Fixed scale for Sudakov sampling with fixed scales.
*/
Energy fixedScale() const{return theFixedScale;}
/**
* Set the fixed scale.
*/
void fixedScale(Energy fix){ theFixedScale=fix;}
/**
* Set the last splitting parameters.
*/
void lastSplittingParameters(const vector<double>& p) { theLastSplittingParameters = p; }
/**
* Access the splitting parameters
*/
vector<double>& splittingParameters() { return theLastSplittingParameters; }
/**
* Indicate that this splitting will terminate
* the evolution of the dipole considered.
*/
void didStopEvolving() { theStoppedEvolving = true; }
/**
* Indicate that this splitting will not terminate
* the evolution of the dipole considered.
*/
void continuesEvolving() { theStoppedEvolving = false; }
/**
* Reset the configuration.
*/
void configuration(const pair<bool,bool>& newConfig) { theConfiguration = newConfig; }
/**
* Set the configuration marking the spectator
*/
void spectatorConfiguration(const pair<bool,bool>& conf) { theSpectatorConfiguration = conf; }
public:
/**
* Set a pointer to the emitter parton before emission.
*/
void emitter(tPPtr newEmitter) { theEmitter = newEmitter; }
/**
* Set a pointer to the spectator parton before emission.
*/
void spectator(tPPtr newSpectator) { theSpectator = newSpectator; }
/**
* Set a pointer to the emitter parton after emission.
*/
void splitEmitter(tPPtr newEmitter) { theSplitEmitter = newEmitter; }
/**
* Set a pointer to the spectator parton after emission.
*/
void splitSpectator(tPPtr newSpectator) { theSplitSpectator = newSpectator; }
/**
* Set a pointer to the emitted parton.
*/
void emission(tPPtr newEmission) { theEmission = newEmission; }
/**
* Return a pointer to the emitter parton before emission.
*/
tPPtr emitter() const { return theEmitter; }
/**
* Return a pointer to the spectator parton before emission.
*/
tPPtr spectator() const { return theSpectator; }
/**
* Return a pointer to the emitter parton after emission.
*/
tPPtr splitEmitter() const { return theSplitEmitter; }
/**
* Return a pointer to the spectator parton after emission.
*/
tPPtr splitSpectator() const { return theSplitSpectator; }
/**
* Return a pointer to the emitted parton.
*/
tPPtr emission() const { return theEmission; }
public:
/**
* Put information to ostream
*/
void print(ostream&) const;
private:
/**
* The DipoleIndex associated
* with this splitting.
*/
DipoleIndex theIndex;
/**
* Flags indicateing which of the particles
* in the dipole should be considered emitter (true)
* and spectator (false)
*/
pair<bool,bool> theConfiguration;
/**
* The configuration marking the spectator
*/
pair<bool,bool> theSpectatorConfiguration;
/**
* The particle data object of the emitter
* after the splitting.
*/
tcPDPtr theEmitterData;
/**
* The particle data object of the emission
* after the splitting.
*/
tcPDPtr theEmissionData;
/**
* The particle data object of the spectator
* after the splitting.
*/
tcPDPtr theSpectatorData;
/**
* A pointer to the DipoleSplittingKinematics object
* which is to be used to perform the splitting.
*/
Ptr<DipoleSplittingKinematics>::tptr theSplittingKinematics;
/**
* The scale for this dipole.
*/
Energy theScale;
/**
* Whether or not this dipole comes from a decay process.
*/
bool theIsDecayProc;
/**
* The mass of the recoil system in
* decay dipoles.
*/
Energy theRecoilMass;
+
+ /**
+ * The mass of the emitter.
+ * (To account for off-shell).
+ */
+ Energy theEmitterMass;
+
+ /**
+ * The mass of the spectator.
+ * (To account for off-shell).
+ */
+ Energy theSpectatorMass;
+
+
+
+
/**
* The momentum fraction of the emitter.
*/
double theEmitterX;
/**
* The momentum fraction of the spectator.
*/
double theSpectatorX;
/**
* The pt below which this splitting has
* been generated.
*/
Energy theHardPt;
/**
* The last generated pt
*/
Energy theLastPt;
/**
* The last generated momentum fraction.
*/
double theLastZ;
/**
* The last calculated zPrime required for massive FF
* and decay kinematics dipoles.
* zPrime := qi.nk / (qi+qj).nk (qj = emission momentum)
*/
// Note: Not required in current implementation
//double theLastZPrime;
/**
* The last generated azimuthal angle.
*/
double theLastPhi;
/**
* The momentum fraction, by which the emitter's
* momentum fraction should be divided after the splitting.
*/
double theLastEmitterZ;
/**
* The momentum fraction, by which the spectator's
* momentum fraction should be divided after the splitting.
*/
double theLastSpectatorZ;
/**
* The last splitting kernel value encountered.
*/
double theLastValue;
/**
* Any additional parameters needed to
* evaluate the splitting kernel or to generate the
* full splitting.
*/
vector<double> theLastSplittingParameters;
/**
* True, if this splitting will terminate
* the evolution of the dipole considered.
*/
bool theStoppedEvolving;
/**
* A pointer to the emitter parton before emission.
*/
PPtr theEmitter;
/**
* A pointer to the spectator parton before emission.
*/
PPtr theSpectator;
/**
* A pointer to the emitter parton after emission.
*/
PPtr theSplitEmitter;
/**
* A pointer to the spectator parton after emission.
*/
PPtr theSplitSpectator;
/**
* A pointer to the emitted parton.
*/
PPtr theEmission;
/**
* Flag to calculate Splitting kernels with a fixed scale
* and without alphas/2pi
**/
bool theCalcFixedExpansion;
/**
* Fixed scale for Sudakov evaluation.
*/
Energy theFixedScale;
};
inline ostream& operator << (ostream& os, const DipoleSplittingInfo& di) {
di.print(os);
return os;
}
}
#endif /* HERWIG_DipoleSplittingInfo_H */
diff --git a/Shower/Dipole/Base/Makefile.am b/Shower/Dipole/Base/Makefile.am
--- a/Shower/Dipole/Base/Makefile.am
+++ b/Shower/Dipole/Base/Makefile.am
@@ -1,13 +1,13 @@
noinst_LTLIBRARIES = libHwDipoleShowerBase.la
libHwDipoleShowerBase_la_SOURCES = \
DipoleSplittingInfo.h DipoleSplittingInfo.cc \
Dipole.h Dipole.cc \
- DipoleChain.h DipoleChain.cc \
+ DipoleChain.fh DipoleChain.h DipoleChain.cc \
DipoleEventRecord.h DipoleEventRecord.cc \
DipoleEventReweight.h DipoleEventReweight.cc \
DipoleSplittingGenerator.h DipoleSplittingGenerator.cc \
DipoleSplittingReweight.h DipoleSplittingReweight.cc \
DipoleEvolutionOrdering.h DipoleEvolutionOrdering.cc \
DipoleChainOrdering.h DipoleChainOrdering.cc
diff --git a/Shower/Dipole/Colorea/Colorea.cc b/Shower/Dipole/Colorea/Colorea.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/Colorea.cc
@@ -0,0 +1,716 @@
+ // -*- C++ -*-
+ //
+ // Colorea.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
+ // Copyright (C) 2002-2017 The Herwig Collaboration
+ //
+ // Herwig is licenced under version 3 of the GPL, see COPYING for details.
+ // Please respect the MCnet academic guidelines, see GUIDELINES for details.
+ //
+ //
+ // This is the implementation of the non-inlined, non-templated member
+ // functions of the Colorea class.
+ //
+
+#include "Colorea.h"
+#include "eeuugg.h"
+#include "eeuuggg.h"
+#include "eeuugggg.h"
+#include "Herwig/Shower/Dipole/Utility/DipolePartonSplitter.h"
+#include "Herwig/Shower/Dipole/Base/DipoleChain.h"
+#include "Herwig/Shower/Dipole/Base/Dipole.h"
+
+
+#include <iterator>
+
+using namespace Herwig;
+
+Colorea::Colorea(){}
+
+list<Dipole>& Colorea::dipoles() { return theChain->dipoles(); }
+
+void Colorea::rearrange( int dipmax , int diplong ){
+
+ assert( dipmax >= diplong );
+ // if there are only 2 dipoles in the chain
+ //there is nothing to do for now.
+ if( dipoles().size() < 3 )return;
+
+ if( dipoles().size() == 3 ){
+ // get the 3 dipoles:
+ auto dipi=dipoles().begin();
+ auto dipj=dipoles().begin();dipj++;
+ auto dipk=dipoles().begin();dipk++;dipk++;
+ rearrange3(dipi,dipj,dipk);
+
+ if( theChain->circular () ){
+ // if the chain is circular,
+ // we need to check also the
+ // connected ends.
+ rearrange3(dipj,dipk,dipi);
+ rearrange3(dipk,dipi,dipj);
+ }
+ return;
+ }
+ if( dipoles().size() == 4 && dipmax >= 4 ){
+ // get the 4 dipoles
+ auto dipi=dipoles().begin();
+ auto dipj=dipoles().begin();dipj++;
+ auto dipk=dipoles().begin();dipk++;dipk++;
+ auto dipl=dipoles().begin();dipl++;dipl++;dipl++;
+ rearrange4(dipi,dipj,dipk,dipl);
+ return;
+ }
+ if( dipoles().size() == 5 && dipmax >= 5 ){
+ // get the 5 dipoles
+ auto dipi=dipoles().begin();
+ auto dipj=dipoles().begin();dipj++;
+ auto dipk=dipoles().begin();dipk++;dipk++;
+ auto dipl=dipoles().begin();dipl++;dipl++;dipl++;
+ auto dipm=dipoles().begin();dipm++;dipm++;dipm++;dipm++;
+ rearrange5(dipi,dipj,dipk,dipl,dipm);
+ return;
+ }
+ // if the chain is longer than dipmax
+ // go though the chain with diplong dipoles.
+ rearrangeLong( diplong );
+ return;
+
+}
+
+void Colorea::rearrangeLong( int diplong ){
+ if ( diplong == 3 ){
+ // get the 3 dipoles:
+ auto dipi=dipoles().begin();
+ auto dipj=dipoles().begin();dipj++;
+ auto dipk=dipoles().begin();dipk++;dipk++;
+ while (dipk!=dipoles().end()) {
+ rearrange3(dipi,dipj,dipk);
+ dipi++;dipj++;dipk++;
+ }
+ if( theChain->circular() ){
+ // if the chain is circular,
+ // we need to check also the
+ // connected ends.
+ dipk=dipoles().begin(); // as dipk was end
+ rearrange3( dipi , dipj , dipk );
+ // rotate further.
+ dipi++;dipk++;
+ dipj=dipoles().begin();
+ rearrange3(dipi,dipj,dipk);
+ }
+ }else if (diplong ==4){
+ // get the 4 dipoles:
+ assert(!theChain->circular ());
+ auto dipi=dipoles().begin();
+ auto dipj=dipoles().begin();dipj++;
+ auto dipk=dipoles().begin();dipk++;dipk++;
+ auto dipl=dipoles().begin();dipl++;dipl++;dipl++;
+ while (dipl!=dipoles().end()) {
+ rearrange4(dipi,dipj,dipk,dipl);
+ dipi++;dipj++;dipk++;dipl++;
+ }
+ }else if (diplong ==5){
+ // get the 5 dipoles:
+ assert(!theChain->circular ());
+ auto dipi=dipoles().begin();
+ auto dipj=dipoles().begin();dipj++;
+ auto dipk=dipoles().begin();dipk++;dipk++;
+ auto dipl=dipoles().begin();dipl++;dipl++;dipl++;
+ auto dipm=dipoles().begin();dipm++;dipm++;dipm++;dipm++;
+
+ while (dipm!=dipoles().end()) {
+ rearrange5(dipi,dipj,dipk,dipl,dipm);
+ dipi++;dipj++;dipk++;dipl++;dipm++;
+ }
+ }else{
+ assert(false);
+ }
+}
+
+
+
+void Colorea::rmcol(tColinePtr A,
+ tColinePtr B,
+ list<Dipole>::iterator & dip){
+ if(A==B){
+ auto AA=A->coloured();
+ for (auto col:AA){
+ if(col==dip->leftParticle()) A->removeColoured (col);
+ if(col==dip->rightParticle())A->removeColoured (col);
+ }
+ auto BB=A->antiColoured();
+ for (auto col:BB){
+ if(col==dip->leftParticle()) A->removeAntiColoured (col);
+ if(col==dip->rightParticle())A->removeAntiColoured (col);
+ }
+ }
+}
+
+
+
+void Colorea::removeColors(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk){
+ auto ilc = dipi->leftParticle()->colourInfo()-> colourLine();
+ auto irc = dipi->rightParticle()->colourInfo()-> colourLine();
+ auto ila = dipi->leftParticle()->colourInfo()-> antiColourLine();
+ auto ira = dipi->rightParticle()->colourInfo()-> antiColourLine();
+ auto jlc = dipj->leftParticle()->colourInfo()-> colourLine();
+ auto jrc = dipj->rightParticle()->colourInfo()-> colourLine();
+ auto jla = dipj->leftParticle()->colourInfo()-> antiColourLine();
+ auto jra = dipj->rightParticle()->colourInfo()-> antiColourLine();
+ auto klc = dipk->leftParticle()->colourInfo()-> colourLine();
+ auto krc = dipk->rightParticle()->colourInfo()-> colourLine();
+ auto kla = dipk->leftParticle()->colourInfo()-> antiColourLine();
+ auto kra = dipk->rightParticle()->colourInfo()-> antiColourLine();
+
+ if( ilc && irc ) rmcol(ilc,irc,dipi);
+ if( ila && ira ) rmcol(ila,ira,dipi);
+ if( jlc && jrc ) rmcol(jlc,jrc,dipj);
+ if( jla && jra ) rmcol(jla,jra,dipj);
+ if( klc && krc ) rmcol(klc,krc,dipk);
+ if( kla && kra ) rmcol(kla,kra,dipk);
+
+ return;
+}
+
+
+
+void Colorea::rearrange3_FF_FF_FF(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk){
+ produceSwapping( dipi, dipj, dipk,true);
+ // compared to IF of FI dipoles we do not need to repair colors as
+ // the swapping just modified the gluon momenta.
+}
+
+
+
+
+
+void Colorea::rearrange3_FF_FI_IF(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk){
+ auto ilc = dipi->leftParticle()->colourInfo()-> colourLine();
+ auto irc = dipi->rightParticle()->colourInfo()-> colourLine();
+ auto ila = dipi->leftParticle()->colourInfo()-> antiColourLine();
+ auto ira = dipi->rightParticle()->colourInfo()-> antiColourLine();
+ auto jlc = dipj->leftParticle()->colourInfo()-> colourLine();
+ auto jrc = dipj->rightParticle()->colourInfo()-> colourLine();
+ auto jla = dipj->leftParticle()->colourInfo()-> antiColourLine();
+ auto jra = dipj->rightParticle()->colourInfo()-> antiColourLine();
+ auto klc = dipk->leftParticle()->colourInfo()-> colourLine();
+ auto krc = dipk->rightParticle()->colourInfo()-> colourLine();
+ auto kla = dipk->leftParticle()->colourInfo()-> antiColourLine();
+ auto kra = dipk->rightParticle()->colourInfo()-> antiColourLine();
+
+ bool didperm = produceSwapping( dipi, dipj, dipk,false);
+
+ if (!didperm)return;
+ removeColors(dipi,dipj,dipk);
+ auto new1Line = new_ptr(ColourLine());
+ auto new2Line = new_ptr(ColourLine());
+ auto new3Line = new_ptr(ColourLine());
+ //Example:
+ // before
+ //ila (F)--irc (F) =g1(in,jl)= jla (F) -- jra(I)=g2(in,jr)=klc(I) -- krc(F)
+ // Should be after:
+ //ila (F) -- ira (I) =g2(in,jl)= jlc (I) -- jrc(F) =g1(out,jr)= kla(F) -- krc(F)
+
+ //Then:
+ // FaFc_FaIa_IcFc FFFIIF aa -> FaIa_IcFc_FaFc
+ // FcFa_FcIc_IaFa FFFIIF cc -> FcIc_IaFa_FcFa
+ // FaFc_FaIa_IcIa FFFIII aa -> FaIa_IcFc_FaIa
+ // FcFa_FcIc_IaIc FFFIII cc -> FcIc_IaFa_FcIc
+ // IcFc_FaIa_IcFc IFFIIF aa -> IcIa_IcFc_FaFc
+ // IaFa_FcIc_IaFa IFFIIF cc -> IaIc_IaFa_FcFa
+ // IcFc_FaIa_IcIa IFFIII aa -> IcIa_IcFc_FaIa
+ // IaFa_FcIc_IaIc IFFIII cc -> IaIc_IaFa_FcIc
+ // end particles keep colors
+ // central all change color.
+ //
+
+ if(ilc==irc){
+ new1Line->addColoured (dipi->leftParticle());
+ new1Line->addAntiColoured (dipi->rightParticle());}
+ if(ilc==ira){
+ new1Line->addColoured (dipi->leftParticle());
+ new1Line->addColoured (dipi->rightParticle());}
+ if(ila==irc){
+ new1Line->addAntiColoured (dipi->leftParticle());
+ new1Line->addAntiColoured (dipi->rightParticle());}
+ if(ila==ira){
+ new1Line->addAntiColoured (dipi->leftParticle());
+ new1Line->addColoured (dipi->rightParticle());}
+
+ if(jlc==jrc){
+ new2Line->addAntiColoured (dipj->leftParticle());
+ new2Line->addAntiColoured (dipj->rightParticle());}
+ if(jlc==jra){
+ new2Line->addAntiColoured (dipj->leftParticle());
+ new2Line->addColoured (dipj->rightParticle());}
+ if(jla==jrc){
+ new2Line->addColoured (dipj->leftParticle());
+ new2Line->addAntiColoured (dipj->rightParticle());}
+ if(jla==jra){
+ new2Line->addColoured (dipj->leftParticle());
+ new2Line->addColoured (dipj->rightParticle());}
+
+ if(klc==krc){
+ new3Line->addAntiColoured (dipk->leftParticle());
+ new3Line->addColoured (dipk->rightParticle());}
+ if(klc==kra){
+ new3Line->addAntiColoured (dipk->leftParticle());
+ new3Line->addAntiColoured (dipk->rightParticle());}
+ if(kla==krc){
+ new3Line->addColoured (dipk->leftParticle());
+ new3Line->addColoured (dipk->rightParticle());}
+ if(kla==kra){
+ new3Line->addColoured (dipk->leftParticle());
+ new3Line->addAntiColoured (dipk->rightParticle());}
+
+}
+
+
+
+void Colorea::rearrange3(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk){
+
+ // We only care about the cenral dipole.
+ // If central dipole is FI or IF we need to take care that
+ // momentum fractions and pdfs are treated correctly.
+ // If central dipole is FF we only swap momenta.
+ // Also the color lines of IF and FI swappings
+ // needs to be repaired.
+
+ bool dipjisFF = dipj->leftFraction() == 1 && dipj->rightFraction() == 1;
+ bool dipjisIF = dipj->leftFraction() != 1 && dipj->rightFraction() == 1;
+ bool dipjisFI = dipj->leftFraction() == 1 && dipj->rightFraction() != 1;
+ bool dipjisII = dipj->leftFraction() != 1 && dipj->rightFraction() != 1;
+
+ // if the possibly swaping dipole is II we
+ // do nothing as this should not be swapped!(?)
+ if(dipjisII) return;
+
+ if(dipjisFF){
+ // possibly swap gluon momenta
+ rearrange3_FF_FF_FF(dipi,dipj,dipk);
+ }
+ // If central dipole is IF or FI -> keep end colors and swap central colors
+ else if( dipjisIF || dipjisFI ){
+ rearrange3_FF_FI_IF(dipi,dipj,dipk);
+ }
+ else {
+ assert(false);
+ }
+
+
+ return;
+
+}
+
+ // local helper function to fill madgraph momenta.
+void fillMGmom(double * mom,Lorentz5Momentum lmom){
+ mom[0]=lmom.t()/GeV;
+ mom[1]=lmom.x()/GeV;
+ mom[2]=lmom.y()/GeV;
+ mom[3]=lmom.z()/GeV;
+}
+
+
+bool Colorea::produceSwapping(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk,bool FF){
+
+ // get the process for all tripple dipole swappings.
+ static auto pro= eeuugg();
+
+ // set mass of q qbar
+ pro.setMass( 3 , dipi->leftParticle()->momentum().m()/GeV);
+ pro.setMass( 4 , dipk->rightParticle()->momentum().m()/GeV);
+
+ // If the central dipole dipj is not a FF-dipole the rearragment is
+ // not a simple swapping of gluon momenta. We need to take care that
+ // the 'new' dipoles get the correct fraction, pdf and index assignments.
+ if(!FF){
+ // for the interfacing with madgraph we need new momenta
+ double mom0[4], mom1[4], mom2[4];
+ double mom3[4], mom4[4], mom5[4];
+
+ //q
+ double prefact=1.;//dipi->leftFraction()!=0.?-1.:1.; ??
+ auto PP=dipi->leftParticle()->momentum();
+ PP.setX(prefact*PP.x());
+ PP.setY(prefact*PP.y());
+ PP.setZ(prefact*PP.z());
+ // get the momentum sum for the triple dipole system.
+ // we need this for the incoming e+e-.
+ auto fmomsum=PP;
+ // lets rotate the system to be sure that momenta
+ // are not misinterpreted as incomming.
+ PP=PP.rotateX(0.3);
+ fillMGmom(mom2,PP);
+
+
+ //qbar
+ prefact=1.;//dipk->rightFraction()!=0.?-1.:1.;
+ PP=dipk->rightParticle()->momentum();
+ PP.setX(prefact*PP.x());
+ PP.setY(prefact*PP.y());
+ PP.setZ(prefact*PP.z());
+ fmomsum+=PP;
+ PP=PP.rotateX(0.3);
+ fillMGmom(mom3,PP);
+
+ //g1
+ prefact=1.;//dipj->leftFraction()!=0.?-1.:1.;
+ PP=dipj->leftParticle()->momentum();
+ PP.setX(prefact*PP.x());
+ PP.setY(prefact*PP.y());
+ PP.setZ(prefact*PP.z());
+ fmomsum+=PP;
+ PP=PP.rotateX(0.3);
+ fillMGmom(mom4,PP);
+
+ //g2
+ prefact=1.;//dipj->rightFraction()!=0.?-1.:1.;
+ PP=dipj->rightParticle()->momentum();
+ PP.setX(prefact*PP.x());
+ PP.setY(prefact*PP.y());
+ PP.setZ(prefact*PP.z());
+ fmomsum+=PP;
+ PP=PP.rotateX(0.3);
+ fillMGmom(mom5,PP);
+
+ // get the boost to to triple dipole restframe
+ auto boostto=fmomsum.findBoostToCM();
+ // center of mass energy.
+ auto CME=fmomsum.m2();
+ // construct incoming momenta.
+ // point incoming axis along arbitrary y axis;
+ Lorentz5Momentum in1=Lorentz5Momentum(ZERO,sqrt(CME)/2.,ZERO,sqrt(CME)/2.);
+ Lorentz5Momentum in2=Lorentz5Momentum(ZERO,-sqrt(CME)/2.,ZERO,sqrt(CME)/2.);
+
+ in1=in1.boost(-boostto);
+ in1=in1.rotateX(0.3);
+ in2=in2.boost(-boostto);
+ in2=in2.rotateX(0.3);
+ fillMGmom(mom0,in1);
+ fillMGmom(mom1,in2);
+
+ vector < double * > momenta{{ mom0, mom1, mom2,
+ mom3, mom4, mom5}};
+
+ // calculate the permutation from madgraph process.
+ auto perm=pro.producePermutation(UseRandom::rnd(),momenta);
+ // for tripple dipoles there is only one possible permutation.
+ bool didperm=perm[0]!=5;
+
+ if(!didperm) return didperm;
+
+ // insert the original dipj fractions
+ vector<double > tmpfrac{{dipj->leftFraction(),dipj->rightFraction()}};
+ // insert the original dipj pdfs
+ vector< PDF > tmppdf;
+ tmppdf.push_back(dipj->leftPDF());
+ tmppdf.push_back(dipj->rightPDF());
+ // insert the original dipj particles
+ vector<PPtr> tmppart;
+ tmppart.push_back(dipj->leftParticle());
+ tmppart.push_back(dipj->rightParticle());
+ // make sure the dipj are gluons.
+ assert(dipj->leftParticle()->id()==21);
+ assert(dipj->rightParticle()->id()==21);
+
+ // Now set the new or old particles in the dipole
+ dipi->rightParticle(tmppart[perm[0]-1-4]);
+ dipj->leftParticle (tmppart[perm[0]-1-4]);
+ dipj->rightParticle(tmppart[perm[1]-1-4]);
+ dipk->leftParticle(tmppart[perm[1]-1-4]);
+
+ dipi->rightPDF(tmppdf[perm[0]-1-4]);
+ dipj->leftPDF (tmppdf[perm[0]-1-4]);
+ dipj->rightPDF(tmppdf[perm[1]-1-4]);
+ dipk->leftPDF (tmppdf[perm[1]-1-4]);
+
+ dipi->rightFraction(tmpfrac[perm[0]-1-4]);
+ dipj->leftFraction (tmpfrac[perm[0]-1-4]);
+ dipj->rightFraction(tmpfrac[perm[1]-1-4]);
+ dipk->leftFraction (tmpfrac[perm[1]-1-4]);
+
+
+ auto firstindex =DipoleIndex(&(dipj->leftParticle()->data()),
+ &(dipj->rightParticle()->data()),
+ dipj->leftPDF(),
+ dipj->rightPDF());
+ auto secondindex =DipoleIndex(&(dipj->rightParticle()->data()),
+ &(dipj->leftParticle()->data()),
+ dipj->rightPDF(),
+ dipj->leftPDF());
+ dipj->setFirstIndex(firstindex);
+ dipj->setSecondIndex(secondindex);
+
+ auto firstindex2 =DipoleIndex(&(dipi->leftParticle()->data()),
+ &(dipi->rightParticle()->data()),
+ dipi->leftPDF(),
+ dipi->rightPDF());
+ auto secondindex2 =DipoleIndex(&(dipi->rightParticle()->data()),
+ &(dipi->leftParticle()->data()),
+ dipi->rightPDF(),
+ dipi->leftPDF());
+ dipi->setFirstIndex(firstindex2);
+ dipi->setSecondIndex(secondindex2);
+
+ auto firstindex3 =DipoleIndex(&(dipk->leftParticle()->data()),
+ &(dipk->rightParticle()->data()),
+ dipk->leftPDF(),
+ dipk->rightPDF());
+ auto secondindex3 =DipoleIndex(&(dipk->rightParticle()->data()),
+ &(dipk->leftParticle()->data()),
+ dipk->rightPDF(),
+ dipk->leftPDF());
+ dipk->setFirstIndex(firstindex3);
+ dipk->setSecondIndex(secondindex3);
+ // check a few things
+ // assert(dipj->leftFraction()!=1.&&(dipj->leftPDF().pdf() ) || dipj->leftFraction()==1. &&!(dipj->leftPDF().pdf()));
+ // assert(dipj->rightFraction()!=1.&&(dipj->rightPDF().pdf() )|| dipj->rightFraction()==1.&&!(dipj->rightPDF().pdf()));
+ // assert(dipi->leftFraction()!=1.&&(dipi->leftPDF().pdf() ) || dipi->leftFraction()==1. &&!(dipi->leftPDF().pdf()));
+ // assert(dipi->rightFraction()!=1.&&(dipi->rightPDF().pdf() )|| dipi->rightFraction()==1.&&!(dipi->rightPDF().pdf()));
+ // assert(dipk->leftFraction()!=1.&&(dipk->leftPDF().pdf() ) || dipk->leftFraction()==1. &&!(dipk->leftPDF().pdf()));
+ // assert(dipk->rightFraction()!=1.&&(dipk->rightPDF().pdf() )|| dipk->rightFraction()==1.&&!(dipk->rightPDF().pdf()));
+
+ return didperm;
+ }else{
+ // if dipj is a FF dipole the color rearrangement is done by
+ // swapping the gluon momenta. Let's do this!
+
+ double mom0[4];
+ double mom1[4];
+ double mom2[4];
+ double mom3[4];
+ double mom4[4];
+ double mom5[4];
+ vector<Lorentz5Momentum> tmpvec;
+
+ //q
+ auto PP=dipi->leftParticle()->momentum();
+ auto fmomsum=PP;
+ PP=PP.rotateX(0.3);
+ fillMGmom(mom2,PP);
+
+ //qbar
+ PP=dipk->rightParticle()->momentum();
+ fmomsum+=PP;
+ PP=PP.rotateX(0.3);
+ fillMGmom(mom3,PP);
+
+ //g1
+ PP=dipj->leftParticle()->momentum();
+ fmomsum+=PP;
+ PP=PP.rotateX(0.3);
+ fillMGmom(mom4,PP);
+
+ //g2
+ PP=dipj->rightParticle()->momentum();
+ fmomsum+=PP;
+ PP=PP.rotateX(0.3);
+ fillMGmom(mom5,PP);
+
+ // get the boost to to triple dipole restframe
+ auto boostto=fmomsum.findBoostToCM();
+
+ auto CME=fmomsum.m2();
+ // point incoming axis along arbitrary y axis;
+ Lorentz5Momentum in1=Lorentz5Momentum(ZERO,sqrt(CME)/2.,ZERO,sqrt(CME)/2.);
+ Lorentz5Momentum in2=Lorentz5Momentum(ZERO,-sqrt(CME)/2.,ZERO,sqrt(CME)/2.);
+
+
+
+ assert(dipj->leftParticle()->id()==21);
+ assert(dipj->rightParticle()->id()==21);
+
+ in1=in1.boost(-boostto);
+ in1=in1.rotateX(0.3);
+ in2=in2.boost(-boostto);
+ in2=in2.rotateX(0.3);
+ fillMGmom(mom0,in1);
+ fillMGmom(mom1,in2);
+
+ vector < double * > momenta{{ mom0, mom1, mom2,
+ mom3, mom4, mom5}};
+
+ // calculate the permutation from madgraph process.
+ auto perm=pro.producePermutation(UseRandom::rnd(),momenta);
+
+ bool didperm=perm[0]!=5;
+
+ // For final state we can just swap gluon momenta.
+ tmpvec.push_back(dipj->leftParticle()->momentum()); // g1
+ tmpvec.push_back(dipj->rightParticle()->momentum()); // g2
+
+ dipj->leftParticle() ->setMomentum(tmpvec[perm[0]-1-4]);
+ dipj->rightParticle()->setMomentum(tmpvec[perm[1]-1-4]);
+
+ return didperm;
+ }
+
+}
+
+
+
+
+
+void Colorea::rearrange4(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk,
+ list<Dipole>::iterator dipl){
+
+ assert(dipk->leftParticle()==dipj->rightParticle());
+ assert(dipl->leftParticle()==dipk->rightParticle());
+
+ double mom0[4], mom1[4], mom2[4], mom3[4];
+ double mom6[4], mom4[4], mom5[4];
+
+ // q g1 g2 g3 qbar
+ // il -- ir=jl -- jr=kl -- kr=ll -- lr
+
+ //q
+ fillMGmom(mom2,dipi->leftParticle()->momentum());
+ //qbar
+ fillMGmom(mom3,dipl->rightParticle()->momentum());
+ //g1
+ fillMGmom(mom4,dipj->leftParticle()->momentum());
+ //g2
+ fillMGmom(mom5,dipj->rightParticle()->momentum());
+ //g3
+ fillMGmom(mom6,dipl->leftParticle()->momentum());
+
+ // q g1 g2 g3 qbar
+ // il -- ir=jl -- jr=kl -- kr=ll -- lr
+ auto fmomsum=dipi->leftParticle()->momentum()+
+ dipj->leftParticle()->momentum()+
+ dipj->rightParticle()->momentum()+
+ dipl->leftParticle()->momentum()+
+ dipl->rightParticle()->momentum();
+
+ auto boostto=fmomsum.findBoostToCM();
+
+ auto CME=fmomsum.m2();
+ // point incoming axis along arbitrary y axis;
+ Lorentz5Momentum in1=Lorentz5Momentum(ZERO,sqrt(CME)/2.,ZERO,sqrt(CME)/2.);
+ Lorentz5Momentum in2=Lorentz5Momentum(ZERO,-sqrt(CME)/2.,ZERO,sqrt(CME)/2.);
+
+ in1=in1.boost(-boostto);
+ in2=in2.boost(-boostto);
+ fillMGmom(mom0,in1);
+ fillMGmom(mom1,in2);
+
+ vector < double * > momenta{{ mom0, mom1,
+ mom2, mom3,
+ mom4, mom5, mom6}};
+
+ static auto pro= eeuuggg();
+
+ // set mass of q qbar
+ pro.setMass( 3 , dipi->leftParticle()->momentum().m()/GeV);
+ pro.setMass( 5 , dipl->rightParticle()->momentum().m()/GeV);
+
+
+ auto perm=pro.producePermutation(UseRandom::rnd(),momenta);
+
+ vector<Lorentz5Momentum> tmpvec;
+ tmpvec.push_back(dipj->leftParticle()->momentum()); // g1
+ tmpvec.push_back(dipj->rightParticle()->momentum()); // g2
+ tmpvec.push_back(dipl->leftParticle()->momentum()); // g3
+
+ dipj->leftParticle() ->setMomentum(tmpvec[perm[0]-1-4]);
+ dipj->rightParticle()->setMomentum(tmpvec[perm[1]-1-4]);
+ dipl->leftParticle() ->setMomentum(tmpvec[perm[2]-1-4]);
+
+}
+
+
+
+
+
+void Colorea::rearrange5(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk,
+ list<Dipole>::iterator dipl,
+ list<Dipole>::iterator dipm){
+
+ assert(dipk->leftParticle()==dipj->rightParticle());
+ assert(dipl->leftParticle()==dipk->rightParticle());
+
+
+ double mom0[4], mom1[4], mom2[4], mom3[4];
+ double mom4[4], mom5[4], mom6[4], mom7[4];
+ // q g1 g2 g3 g4 qbar
+ // il -- ir=jl -- jr=kl -- kr=ll -- lr=ml -- mr
+
+ //q
+ fillMGmom(mom2,dipi->leftParticle()->momentum());
+ //qbar
+ fillMGmom(mom3,dipm->rightParticle()->momentum());
+ //g1
+ fillMGmom(mom4,dipj->leftParticle()->momentum());
+ //g2
+ fillMGmom(mom5,dipj->rightParticle()->momentum());
+ //g3
+ fillMGmom(mom6,dipl->leftParticle()->momentum());
+ //g4
+ fillMGmom(mom7,dipm->leftParticle()->momentum());
+
+ // q g1 g2 g3 g4 qbar
+ // il -- ir=jl -- jr=kl -- kr=ll -- lr=ml -- mr
+ auto fmomsum=dipi->leftParticle()->momentum()+
+ dipj->leftParticle()->momentum()+
+ dipj->rightParticle()->momentum()+
+ dipl->leftParticle()->momentum()+
+ dipl->rightParticle()->momentum()+
+ dipm->rightParticle()->momentum();
+
+ auto boostto=fmomsum.findBoostToCM();
+
+ auto CME=fmomsum.m2();
+ // point incoming axis along arbitrary y axis;
+ Lorentz5Momentum in1=Lorentz5Momentum(ZERO,sqrt(CME)/2.,ZERO,sqrt(CME)/2.);
+ Lorentz5Momentum in2=Lorentz5Momentum(ZERO,-sqrt(CME)/2.,ZERO,sqrt(CME)/2.);
+
+
+ in1=in1.boost(-boostto);
+ in2=in2.boost(-boostto);
+ fillMGmom(mom0,in1);
+ fillMGmom(mom1,in2);
+
+ vector < double * > momenta{{ mom0, mom1, mom2, mom3,
+ mom4, mom5, mom6, mom7}};
+
+ static auto pro= eeuugggg();
+
+ // set mass of q qbar
+ pro.setMass( 3 , dipi->leftParticle()->momentum().m()/GeV);
+ pro.setMass( 5 , dipl->rightParticle()->momentum().m()/GeV);
+
+ auto perm=pro.producePermutation(UseRandom::rnd(),momenta);
+
+ vector<Lorentz5Momentum> tmpvec;
+ tmpvec.push_back(dipj->leftParticle()->momentum()); // g1
+ tmpvec.push_back(dipj->rightParticle()->momentum()); // g2
+ tmpvec.push_back(dipl->leftParticle()->momentum()); // g3
+ tmpvec.push_back(dipm->leftParticle()->momentum()); // g4
+
+ // set the gluon momenta with permuted momenta.
+ dipj->leftParticle() ->setMomentum(tmpvec[perm[0]-1-4]);
+ dipj->rightParticle()->setMomentum(tmpvec[perm[1]-1-4]);
+ dipl->leftParticle() ->setMomentum(tmpvec[perm[2]-1-4]);
+ dipm->leftParticle() ->setMomentum(tmpvec[perm[3]-1-4]);
+
+}
+
+
+
+
+
+
diff --git a/Shower/Dipole/Colorea/Colorea.fh b/Shower/Dipole/Colorea/Colorea.fh
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/Colorea.fh
@@ -0,0 +1,21 @@
+// -*- C++ -*-
+// This is the forward declaration of the Colorea class
+
+#ifndef HERWIG_Colorea_FH
+#define HERWIG_Colorea_FH
+
+#include "ThePEG/Config/ThePEG.h"
+#include "ThePEG/Config/Pointers.h"
+
+
+namespace Herwig {
+
+class Colorea;
+using namespace ThePEG;
+
+ ThePEG_DECLARE_POINTERS(Colorea , ColoreaPtr );
+
+
+}
+
+#endif // HERWIG_Colorea_FH
diff --git a/Shower/Dipole/Colorea/Colorea.h b/Shower/Dipole/Colorea/Colorea.h
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/Colorea.h
@@ -0,0 +1,147 @@
+// -*- C++ -*-
+//
+// Colorea.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_Colorea_H
+#define HERWIG_Colorea_H
+//
+// This is the declaration of the Colorea class.
+//
+#include "Herwig/Shower/Dipole/Base/DipoleChain.fh"
+#include "Herwig/Shower/Dipole/Base/Dipole.h"
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * \ingroup DipoleShower
+ * \author Johannes Bellm
+ *
+ * This class implemets the method described in arXiv:1801.06113.
+ * and it's extension described in arXiv:180X.XXXXX.
+ * It allows to calculate the probability to rearrange
+ * dipole chains with simple matrix elements.
+ *
+ * The implementation currently allows:
+ * - rearranging pure FF dipole chains with
+ * processes: eeuugg eeuuggg and eeuugggg
+ * - IF or FI dipoles can be rearranged with eeuugg.
+ * - II should not be rearranged.
+ * - masses of the q qbar particles are set.
+ *
+ */
+class Colorea {
+
+public:
+
+ /**
+ * Default constructor
+ */
+ Colorea();
+
+ /**
+ * main function to rearrange the dipole chain.
+ * - dipmax: chains with dipmax are rearranged with matix elements including
+ * dipmax dipoles:
+ * dipmax=3 -> eeuugg
+ * dipmax=4 -> eeuuggg
+ * dipmax=5 -> eeuugggg
+ * if a chain contains more than dipmax dipoles, we treat the chain
+ * as long.
+ * - diplong: this parameter allows to change the behaviour for Coloreas
+ * that are longer than dipmax (long chains).
+ * If diplong is 3 the chain is rearranged with eeuugg
+ * matrix elements.
+ * If diplong is 4 the chain is rearranged with eeuuggg
+ * matrix elements. diplong > 4 is currently not implemented.
+ * Note: We dont observe a difference between the diplong=3 or
+ * diplong=4 treatment.
+ */
+ void rearrange(int dipmax,int diplong);
+
+ /**
+ * Set the chain to use in the rearrangement.
+ */
+ void setChain(Ptr<DipoleChain>::tptr ch){theChain=ch;};
+
+ // Everything below is private. The rearranging is acting only on the current chain.
+ private:
+ /**
+ * Main function for rearranging tripple dipoles.
+ */
+ void rearrange3(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk);
+
+ /**
+ * Function to rearrange triple dipoles in the all FF dipole case.
+ */
+ void rearrange3_FF_FF_FF(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk);
+
+ /**
+ * Function to rearrange triple dipoles if dipj is FI dipole.
+ * This function is also used for IF.
+ */
+ void rearrange3_FF_FI_IF(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk);
+ /**
+ * Main function for rearranging 4 dipoles.
+ * This funtion currently only implements the case of 4 FF dipoles.
+ */
+ void rearrange4(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk,
+ list<Dipole>::iterator dipl);
+ /**
+ * Main function for rearranging 5 dipoles.
+ * This funtion currently only implements the case of 5 FF dipoles.
+ */
+ void rearrange5(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk,
+ list<Dipole>::iterator dipl,
+ list<Dipole>::iterator dipm);
+ /**
+ * Rearrange long chains.
+ */
+ void rearrangeLong(int diplong);
+
+ /**
+ * Produce the possible swapping or the dipj gluons.
+ */
+ bool produceSwapping(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk,bool FF);
+
+ // helper function to remove particles from color line if color line connects them.
+ void rmcol(tColinePtr A,tColinePtr B, list<Dipole>::iterator & dip);
+
+ // remove connecting color lines from these dipoles
+ void removeColors(list<Dipole>::iterator dipi,
+ list<Dipole>::iterator dipj,
+ list<Dipole>::iterator dipk);
+
+ // Access the dipoles of the current chain.
+ list<Dipole>& dipoles();
+
+ private:
+ // the current chain to rearrange.
+ Ptr<DipoleChain>::tptr theChain;
+
+};
+
+inline ostream& operator << (ostream& os, const Colorea& ) {
+ return os;
+}
+
+}
+
+#endif /* HERWIG_Colorea_H */
diff --git a/Shower/Dipole/Colorea/HelAmps_sm.cc b/Shower/Dipole/Colorea/HelAmps_sm.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/HelAmps_sm.cc
@@ -0,0 +1,1035 @@
+//==========================================================================
+// This file has been automatically generated for C++ Standalone by
+// MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+// By the MadGraph5_aMC@NLO Development Team
+// Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+//==========================================================================
+
+#include "HelAmps_sm.h"
+#include <complex>
+#include <cmath>
+#include <iostream>
+#include <cstdlib>
+using namespace std;
+
+namespace MG5_sm_COLOREA
+{
+
+void ixxxxx(double p[4], double fmass, int nhel, int nsf, complex<double> fi[6])
+{
+ complex<double> chi[2];
+ double sf[2], sfomega[2], omega[2], pp, pp3, sqp0p3, sqm[2];
+ int ip, im, nh;
+ fi[0] = complex<double> (-p[0] * nsf, -p[3] * nsf);
+ fi[1] = complex<double> (-p[1] * nsf, -p[2] * nsf);
+ nh = nhel * nsf;
+ if (fmass != 0.0)
+ {
+ pp = min(p[0], sqrt(p[1] * p[1] + p[2] * p[2] + p[3] * p[3]));
+ if (pp == 0.0)
+ {
+ sqm[0] = sqrt(std::abs(fmass));
+ sqm[1] = Sgn(sqm[0], fmass);
+ ip = (1 + nh)/2;
+ im = (1 - nh)/2;
+ fi[2] = ip * sqm[ip];
+ fi[3] = im * nsf * sqm[ip];
+ fi[4] = ip * nsf * sqm[im];
+ fi[5] = im * sqm[im];
+ }
+ else
+ {
+ sf[0] = (1 + nsf + (1 - nsf) * nh) * 0.5;
+ sf[1] = (1 + nsf - (1 - nsf) * nh) * 0.5;
+ omega[0] = sqrt(p[0] + pp);
+ omega[1] = fmass/omega[0];
+ ip = (1 + nh)/2;
+ im = (1 - nh)/2;
+ sfomega[0] = sf[0] * omega[ip];
+ sfomega[1] = sf[1] * omega[im];
+ pp3 = max(pp + p[3], 0.0);
+ chi[0] = complex<double> (sqrt(pp3 * 0.5/pp), 0);
+ if (pp3 == 0.0)
+ {
+ chi[1] = complex<double> (-nh, 0);
+ }
+ else
+ {
+ chi[1] = complex<double> (nh * p[1], p[2])/sqrt(2.0 * pp * pp3);
+ }
+ fi[2] = sfomega[0] * chi[im];
+ fi[3] = sfomega[0] * chi[ip];
+ fi[4] = sfomega[1] * chi[im];
+ fi[5] = sfomega[1] * chi[ip];
+ }
+ }
+ else
+ {
+ if (p[1] == 0.0 and p[2] == 0.0 and p[3] < 0.0)
+ {
+ sqp0p3 = 0.0;
+ }
+ else
+ {
+ sqp0p3 = sqrt(max(p[0] + p[3], 0.0)) * nsf;
+ }
+ chi[0] = complex<double> (sqp0p3, 0.0);
+ if (sqp0p3 == 0.0)
+ {
+ chi[1] = complex<double> (-nhel * sqrt(2.0 * p[0]), 0.0);
+ }
+ else
+ {
+ chi[1] = complex<double> (nh * p[1], p[2])/sqp0p3;
+ }
+ if (nh == 1)
+ {
+ fi[2] = complex<double> (0.0, 0.0);
+ fi[3] = complex<double> (0.0, 0.0);
+ fi[4] = chi[0];
+ fi[5] = chi[1];
+ }
+ else
+ {
+ fi[2] = chi[1];
+ fi[3] = chi[0];
+ fi[4] = complex<double> (0.0, 0.0);
+ fi[5] = complex<double> (0.0, 0.0);
+ }
+ }
+ return;
+}
+
+
+double Sgn(double a, double b)
+{
+ return (b < 0)? - abs(a):abs(a);
+}
+
+
+void txxxxx(double p[4], double tmass, int nhel, int nst, complex<double>
+ tc[18])
+{
+ complex<double> ft[6][4], ep[4], em[4], e0[4];
+ double pt, pt2, pp, pzpt, emp, sqh, sqs;
+ int i, j;
+
+ sqh = sqrt(0.5);
+ sqs = sqrt(0.5/3);
+
+ pt2 = p[1] * p[1] + p[2] * p[2];
+ pp = min(p[0], sqrt(pt2 + p[3] * p[3]));
+ pt = min(pp, sqrt(pt2));
+
+ ft[4][0] = complex<double> (p[0] * nst, p[3] * nst);
+ ft[5][0] = complex<double> (p[1] * nst, p[2] * nst);
+
+ // construct eps+
+ if(nhel >= 0)
+ {
+ if(pp == 0)
+ {
+ ep[0] = complex<double> (0, 0);
+ ep[1] = complex<double> (-sqh, 0);
+ ep[2] = complex<double> (0, nst * sqh);
+ ep[3] = complex<double> (0, 0);
+ }
+ else
+ {
+ ep[0] = complex<double> (0, 0);
+ ep[3] = complex<double> (pt/pp * sqh, 0);
+
+ if(pt != 0)
+ {
+ pzpt = p[3]/(pp * pt) * sqh;
+ ep[1] = complex<double> (-p[1] * pzpt, -nst * p[2]/pt * sqh);
+ ep[2] = complex<double> (-p[2] * pzpt, nst * p[1]/pt * sqh);
+ }
+ else
+ {
+ ep[1] = complex<double> (-sqh, 0);
+ ep[2] = complex<double> (0, nst * Sgn(sqh, p[3]));
+ }
+ }
+
+ }
+
+ // construct eps-
+ if(nhel <= 0)
+ {
+ if(pp == 0)
+ {
+ em[0] = complex<double> (0, 0);
+ em[1] = complex<double> (sqh, 0);
+ em[2] = complex<double> (0, nst * sqh);
+ em[3] = complex<double> (0, 0);
+ }
+ else
+ {
+ em[0] = complex<double> (0, 0);
+ em[3] = complex<double> (-pt/pp * sqh, 0);
+
+ if(pt != 0)
+ {
+ pzpt = -p[3]/(pp * pt) * sqh;
+ em[1] = complex<double> (-p[1] * pzpt, -nst * p[2]/pt * sqh);
+ em[2] = complex<double> (-p[2] * pzpt, nst * p[1]/pt * sqh);
+ }
+ else
+ {
+ em[1] = complex<double> (sqh, 0);
+ em[2] = complex<double> (0, nst * Sgn(sqh, p[3]));
+ }
+ }
+ }
+
+ // construct eps0
+ if(std::labs(nhel) <= 1)
+ {
+ if(pp == 0)
+ {
+ e0[0] = complex<double> (0, 0);
+ e0[1] = complex<double> (0, 0);
+ e0[2] = complex<double> (0, 0);
+ e0[3] = complex<double> (1, 0);
+ }
+ else
+ {
+ emp = p[0]/(tmass * pp);
+ e0[0] = complex<double> (pp/tmass, 0);
+ e0[3] = complex<double> (p[3] * emp, 0);
+
+ if(pt != 0)
+ {
+ e0[1] = complex<double> (p[1] * emp, 0);
+ e0[2] = complex<double> (p[2] * emp, 0);
+ }
+ else
+ {
+ e0[1] = complex<double> (0, 0);
+ e0[2] = complex<double> (0, 0);
+ }
+ }
+ }
+
+ if(nhel == 2)
+ {
+ for(j = 0; j < 4; j++ )
+ {
+ for(i = 0; i < 4; i++ )
+ ft[i][j] = ep[i] * ep[j];
+ }
+ }
+ else if(nhel == -2)
+ {
+ for(j = 0; j < 4; j++ )
+ {
+ for(i = 0; i < 4; i++ )
+ ft[i][j] = em[i] * em[j];
+ }
+ }
+ else if(tmass == 0)
+ {
+ for(j = 0; j < 4; j++ )
+ {
+ for(i = 0; i < 4; i++ )
+ ft[i][j] = 0;
+ }
+ }
+ else if(tmass != 0)
+ {
+ if(nhel == 1)
+ {
+ for(j = 0; j < 4; j++ )
+ {
+ for(i = 0; i < 4; i++ )
+ ft[i][j] = sqh * (ep[i] * e0[j] + e0[i] * ep[j]);
+ }
+ }
+ else if(nhel == 0)
+ {
+ for(j = 0; j < 4; j++ )
+ {
+ for(i = 0; i < 4; i++ )
+ ft[i][j] = sqs * (ep[i] * em[j] + em[i] * ep[j]
+ + 2.0 * e0[i] * e0[j]);
+ }
+ }
+ else if(nhel == -1)
+ {
+ for(j = 0; j < 4; j++ )
+ {
+ for(i = 0; i < 4; i++ )
+ ft[i][j] = sqh * (em[i] * e0[j] + e0[i] * em[j]);
+ }
+ }
+ else
+ {
+ std::cerr << "Invalid helicity in txxxxx.\n";
+ std::exit(1);
+ }
+ }
+
+ tc[0] = ft[4][0];
+ tc[1] = ft[5][0];
+
+ for(j = 0; j < 4; j++ )
+ {
+ for(i = 0; i < 4; i++ )
+ tc[j * 4 + i + 2] = ft[j][i];
+ }
+}
+
+void vxxxxx(double p[4], double vmass, int nhel, int nsv, complex<double> vc[6])
+{
+ double hel, hel0, pt, pt2, pp, pzpt, emp, sqh;
+ int nsvahl;
+ sqh = sqrt(0.5);
+ hel = double(nhel);
+ nsvahl = nsv * std::abs(hel);
+ pt2 = (p[1] * p[1]) + (p[2] * p[2]);
+ pp = min(p[0], sqrt(pt2 + (p[3] * p[3])));
+ pt = min(pp, sqrt(pt2));
+ vc[0] = complex<double> (p[0] * nsv, p[3] * nsv);
+ vc[1] = complex<double> (p[1] * nsv, p[2] * nsv);
+ if (vmass != 0.0)
+ {
+ hel0 = 1.0 - std::abs(hel);
+ if(pp == 0.0)
+ {
+ vc[2] = complex<double> (0.0, 0.0);
+ vc[3] = complex<double> (-hel * sqh, 0.0);
+ vc[4] = complex<double> (0.0, nsvahl * sqh);
+ vc[5] = complex<double> (hel0, 0.0);
+ }
+ else
+ {
+ emp = p[0]/(vmass * pp);
+ vc[2] = complex<double> (hel0 * pp/vmass, 0.0);
+ vc[5] = complex<double> (hel0 * p[3] * emp + hel * pt/pp * sqh, 0.0);
+ if (pt != 0.0)
+ {
+ pzpt = p[3]/(pp * pt) * sqh * hel;
+ vc[3] = complex<double> (hel0 * p[1] * emp - p[1] * pzpt, -nsvahl *
+ p[2]/pt * sqh);
+ vc[4] = complex<double> (hel0 * p[2] * emp - p[2] * pzpt, nsvahl *
+ p[1]/pt * sqh);
+ }
+ else
+ {
+ vc[3] = complex<double> (-hel * sqh, 0.0);
+ vc[4] = complex<double> (0.0, nsvahl * Sgn(sqh, p[3]));
+ }
+ }
+ }
+ else
+ {
+ pp = p[0];
+ pt = sqrt((p[1] * p[1]) + (p[2] * p[2]));
+ vc[2] = complex<double> (0.0, 0.0);
+ vc[5] = complex<double> (hel * pt/pp * sqh, 0.0);
+ if (pt != 0.0)
+ {
+ pzpt = p[3]/(pp * pt) * sqh * hel;
+ vc[3] = complex<double> (-p[1] * pzpt, -nsv * p[2]/pt * sqh);
+ vc[4] = complex<double> (-p[2] * pzpt, nsv * p[1]/pt * sqh);
+ }
+ else
+ {
+ vc[3] = complex<double> (-hel * sqh, 0.0);
+ vc[4] = complex<double> (0.0, nsv * Sgn(sqh, p[3]));
+ }
+ }
+ return;
+}
+
+void sxxxxx(double p[4], int nss, complex<double> sc[3])
+{
+ sc[2] = complex<double> (1.00, 0.00);
+ sc[0] = complex<double> (p[0] * nss, p[3] * nss);
+ sc[1] = complex<double> (p[1] * nss, p[2] * nss);
+ return;
+}
+
+void oxxxxx(double p[4], double fmass, int nhel, int nsf, complex<double> fo[6])
+{
+ complex<double> chi[2];
+ double sf[2], sfomeg[2], omega[2], pp, pp3, sqp0p3, sqm[2];
+ int nh, ip, im;
+ fo[0] = complex<double> (p[0] * nsf, p[3] * nsf);
+ fo[1] = complex<double> (p[1] * nsf, p[2] * nsf);
+ nh = nhel * nsf;
+ if (fmass != 0.000)
+ {
+ pp = min(p[0], sqrt((p[1] * p[1]) + (p[2] * p[2]) + (p[3] * p[3])));
+ if (pp == 0.000)
+ {
+ sqm[0] = sqrt(std::abs(fmass));
+ sqm[1] = Sgn(sqm[0], fmass);
+ ip = -((1 - nh)/2) * nhel;
+ im = (1 + nh)/2 * nhel;
+ fo[2] = im * sqm[std::abs(ip)];
+ fo[3] = ip * nsf * sqm[std::abs(ip)];
+ fo[4] = im * nsf * sqm[std::abs(im)];
+ fo[5] = ip * sqm[std::abs(im)];
+ }
+ else
+ {
+ pp = min(p[0], sqrt((p[1] * p[1]) + (p[2] * p[2]) + (p[3] * p[3])));
+ sf[0] = double(1 + nsf + (1 - nsf) * nh) * 0.5;
+ sf[1] = double(1 + nsf - (1 - nsf) * nh) * 0.5;
+ omega[0] = sqrt(p[0] + pp);
+ omega[1] = fmass/omega[0];
+ ip = (1 + nh)/2;
+ im = (1 - nh)/2;
+ sfomeg[0] = sf[0] * omega[ip];
+ sfomeg[1] = sf[1] * omega[im];
+ pp3 = max(pp + p[3], 0.00);
+ chi[0] = complex<double> (sqrt(pp3 * 0.5/pp), 0.00);
+ if (pp3 == 0.00)
+ {
+ chi[1] = complex<double> (-nh, 0.00);
+ }
+ else
+ {
+ chi[1] = complex<double> (nh * p[1], -p[2])/sqrt(2.0 * pp * pp3);
+ }
+ fo[2] = sfomeg[1] * chi[im];
+ fo[3] = sfomeg[1] * chi[ip];
+ fo[4] = sfomeg[0] * chi[im];
+ fo[5] = sfomeg[0] * chi[ip];
+ }
+ }
+ else
+ {
+ if((p[1] == 0.00) and (p[2] == 0.00) and (p[3] < 0.00))
+ {
+ sqp0p3 = 0.00;
+ }
+ else
+ {
+ sqp0p3 = sqrt(max(p[0] + p[3], 0.00)) * nsf;
+ }
+ chi[0] = complex<double> (sqp0p3, 0.00);
+ if(sqp0p3 == 0.000)
+ {
+ chi[1] = complex<double> (-nhel, 0.00) * sqrt(2.0 * p[0]);
+ }
+ else
+ {
+ chi[1] = complex<double> (nh * p[1], -p[2])/sqp0p3;
+ }
+ if(nh == 1)
+ {
+ fo[2] = chi[0];
+ fo[3] = chi[1];
+ fo[4] = complex<double> (0.00, 0.00);
+ fo[5] = complex<double> (0.00, 0.00);
+ }
+ else
+ {
+ fo[2] = complex<double> (0.00, 0.00);
+ fo[3] = complex<double> (0.00, 0.00);
+ fo[4] = chi[1];
+ fo[5] = chi[0];
+ }
+ }
+ return;
+}
+
+void FFV1P0_3(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> COUP, double M3, double W3, std::complex<double> V3[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ double P3[4];
+ std::complex<double> denom;
+ V3[0] = +F1[0] + F2[0];
+ V3[1] = +F1[1] + F2[1];
+ P3[0] = -V3[0].real();
+ P3[1] = -V3[1].real();
+ P3[2] = -V3[1].imag();
+ P3[3] = -V3[0].imag();
+ denom = COUP/((P3[0] * P3[0]) - (P3[1] * P3[1]) - (P3[2] * P3[2]) - (P3[3] *
+ P3[3]) - M3 * (M3 - cI * W3));
+ V3[2] = denom * (-cI) * (F1[2] * F2[4] + F1[3] * F2[5] + F1[4] * F2[2] +
+ F1[5] * F2[3]);
+ V3[3] = denom * (-cI) * (F1[4] * F2[3] + F1[5] * F2[2] - F1[2] * F2[5] -
+ F1[3] * F2[4]);
+ V3[4] = denom * (-cI) * (-cI * (F1[2] * F2[5] + F1[5] * F2[2]) + cI * (F1[3]
+ * F2[4] + F1[4] * F2[3]));
+ V3[5] = denom * (-cI) * (F1[3] * F2[5] + F1[4] * F2[2] - F1[2] * F2[4] -
+ F1[5] * F2[3]);
+}
+
+
+void FFV2_2(std::complex<double> F1[], std::complex<double> V3[],
+ std::complex<double> COUP, double M2, double W2, std::complex<double> F2[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ double P2[4];
+ std::complex<double> denom;
+ F2[0] = +F1[0] + V3[0];
+ F2[1] = +F1[1] + V3[1];
+ P2[0] = -F2[0].real();
+ P2[1] = -F2[1].real();
+ P2[2] = -F2[1].imag();
+ P2[3] = -F2[0].imag();
+ denom = COUP/((P2[0] * P2[0]) - (P2[1] * P2[1]) - (P2[2] * P2[2]) - (P2[3] *
+ P2[3]) - M2 * (M2 - cI * W2));
+ F2[2] = denom * cI * (F1[2] * (P2[0] * (V3[2] + V3[5]) + (P2[1] * (-1.) *
+ (V3[3] + cI * (V3[4])) + (P2[2] * (+cI * (V3[3]) - V3[4]) - P2[3] *
+ (V3[2] + V3[5])))) + F1[3] * (P2[0] * (V3[3] - cI * (V3[4])) + (P2[1] *
+ (V3[5] - V3[2]) + (P2[2] * (-cI * (V3[5]) + cI * (V3[2])) + P2[3] * (+cI
+ * (V3[4]) - V3[3])))));
+ F2[3] = denom * cI * (F1[2] * (P2[0] * (V3[3] + cI * (V3[4])) + (P2[1] *
+ (-1.) * (V3[2] + V3[5]) + (P2[2] * (-1.) * (+cI * (V3[2] + V3[5])) +
+ P2[3] * (V3[3] + cI * (V3[4]))))) + F1[3] * (P2[0] * (V3[2] - V3[5]) +
+ (P2[1] * (+cI * (V3[4]) - V3[3]) + (P2[2] * (-1.) * (V3[4] + cI *
+ (V3[3])) + P2[3] * (V3[2] - V3[5])))));
+ F2[4] = denom * - cI * M2 * (F1[2] * (-1.) * (V3[2] + V3[5]) + F1[3] * (+cI *
+ (V3[4]) - V3[3]));
+ F2[5] = denom * cI * M2 * (F1[2] * (V3[3] + cI * (V3[4])) + F1[3] * (V3[2] -
+ V3[5]));
+}
+
+void FFV2_5_2(std::complex<double> F1[], std::complex<double> V3[],
+ std::complex<double> COUP1, std::complex<double> COUP2, double M2, double
+ W2, std::complex<double> F2[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> Ftmp[6];
+ double P2[4];
+ std::complex<double> denom;
+ int i;
+ FFV2_2(F1, V3, COUP1, M2, W2, F2);
+ FFV5_2(F1, V3, COUP2, M2, W2, Ftmp);
+ i = 2;
+ while (i < 6)
+ {
+ F2[i] = F2[i] + Ftmp[i];
+ i++;
+ }
+}
+
+void FFV1_2(std::complex<double> F1[], std::complex<double> V3[],
+ std::complex<double> COUP, double M2, double W2, std::complex<double> F2[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ double P2[4];
+ std::complex<double> denom;
+ F2[0] = +F1[0] + V3[0];
+ F2[1] = +F1[1] + V3[1];
+ P2[0] = -F2[0].real();
+ P2[1] = -F2[1].real();
+ P2[2] = -F2[1].imag();
+ P2[3] = -F2[0].imag();
+ denom = COUP/((P2[0] * P2[0]) - (P2[1] * P2[1]) - (P2[2] * P2[2]) - (P2[3] *
+ P2[3]) - M2 * (M2 - cI * W2));
+ F2[2] = denom * cI * (F1[2] * (P2[0] * (V3[2] + V3[5]) + (P2[1] * (-1.) *
+ (V3[3] + cI * (V3[4])) + (P2[2] * (+cI * (V3[3]) - V3[4]) - P2[3] *
+ (V3[2] + V3[5])))) + (F1[3] * (P2[0] * (V3[3] - cI * (V3[4])) + (P2[1] *
+ (V3[5] - V3[2]) + (P2[2] * (-cI * (V3[5]) + cI * (V3[2])) + P2[3] * (+cI
+ * (V3[4]) - V3[3])))) + M2 * (F1[4] * (V3[2] - V3[5]) + F1[5] * (+cI *
+ (V3[4]) - V3[3]))));
+ F2[3] = denom * (-cI) * (F1[2] * (P2[0] * (-1.) * (V3[3] + cI * (V3[4])) +
+ (P2[1] * (V3[2] + V3[5]) + (P2[2] * (+cI * (V3[2] + V3[5])) - P2[3] *
+ (V3[3] + cI * (V3[4]))))) + (F1[3] * (P2[0] * (V3[5] - V3[2]) + (P2[1] *
+ (V3[3] - cI * (V3[4])) + (P2[2] * (V3[4] + cI * (V3[3])) + P2[3] * (V3[5]
+ - V3[2])))) + M2 * (F1[4] * (V3[3] + cI * (V3[4])) - F1[5] * (V3[2] +
+ V3[5]))));
+ F2[4] = denom * (-cI) * (F1[4] * (P2[0] * (V3[5] - V3[2]) + (P2[1] * (V3[3] +
+ cI * (V3[4])) + (P2[2] * (V3[4] - cI * (V3[3])) + P2[3] * (V3[5] -
+ V3[2])))) + (F1[5] * (P2[0] * (V3[3] - cI * (V3[4])) + (P2[1] * (-1.) *
+ (V3[2] + V3[5]) + (P2[2] * (+cI * (V3[2] + V3[5])) + P2[3] * (V3[3] - cI
+ * (V3[4]))))) + M2 * (F1[2] * (-1.) * (V3[2] + V3[5]) + F1[3] * (+cI *
+ (V3[4]) - V3[3]))));
+ F2[5] = denom * cI * (F1[4] * (P2[0] * (-1.) * (V3[3] + cI * (V3[4])) +
+ (P2[1] * (V3[2] - V3[5]) + (P2[2] * (-cI * (V3[5]) + cI * (V3[2])) +
+ P2[3] * (V3[3] + cI * (V3[4]))))) + (F1[5] * (P2[0] * (V3[2] + V3[5]) +
+ (P2[1] * (+cI * (V3[4]) - V3[3]) + (P2[2] * (-1.) * (V3[4] + cI *
+ (V3[3])) - P2[3] * (V3[2] + V3[5])))) + M2 * (F1[2] * (V3[3] + cI *
+ (V3[4])) + F1[3] * (V3[2] - V3[5]))));
+}
+
+
+void FFV2_0(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> V3[], std::complex<double> COUP, std::complex<double>
+ & vertex)
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> TMP9;
+ TMP9 = (F1[2] * (F2[4] * (V3[2] + V3[5]) + F2[5] * (V3[3] + cI * (V3[4]))) +
+ F1[3] * (F2[4] * (V3[3] - cI * (V3[4])) + F2[5] * (V3[2] - V3[5])));
+ vertex = COUP * - cI * TMP9;
+}
+
+void FFV2_5_0(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> V3[], std::complex<double> COUP1, std::complex<double>
+ COUP2, std::complex<double> & vertex)
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> tmp;
+ FFV2_0(F1, F2, V3, COUP1, vertex);
+ FFV5_0(F1, F2, V3, COUP2, tmp);
+ vertex = vertex + tmp;
+}
+
+void FFV5_1(std::complex<double> F2[], std::complex<double> V3[],
+ std::complex<double> COUP, double M1, double W1, std::complex<double> F1[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ double P1[4];
+ std::complex<double> denom;
+ F1[0] = +F2[0] + V3[0];
+ F1[1] = +F2[1] + V3[1];
+ P1[0] = -F1[0].real();
+ P1[1] = -F1[1].real();
+ P1[2] = -F1[1].imag();
+ P1[3] = -F1[0].imag();
+ denom = COUP/((P1[0] * P1[0]) - (P1[1] * P1[1]) - (P1[2] * P1[2]) - (P1[3] *
+ P1[3]) - M1 * (M1 - cI * W1));
+ F1[2] = denom * 4. * cI * (F2[2] * (P1[0] * (V3[5] - V3[2]) + (P1[1] * (V3[3]
+ - cI * (V3[4])) + (P1[2] * (V3[4] + cI * (V3[3])) + P1[3] * (V3[5] -
+ V3[2])))) + (+1./4. * (M1 * (F2[5] * (V3[3] + cI * (V3[4])) + 4. * (F2[4]
+ * 1./4. * (V3[2] + V3[5])))) + F2[3] * (P1[0] * (V3[3] + cI * (V3[4])) +
+ (P1[1] * (-1.) * (V3[2] + V3[5]) + (P1[2] * (-1.) * (+cI * (V3[2] +
+ V3[5])) + P1[3] * (V3[3] + cI * (V3[4])))))));
+ F1[3] = denom * 4. * cI * (F2[2] * (P1[0] * (V3[3] - cI * (V3[4])) + (P1[1] *
+ (V3[5] - V3[2]) + (P1[2] * (-cI * (V3[5]) + cI * (V3[2])) + P1[3] * (+cI
+ * (V3[4]) - V3[3])))) + (+1./4. * (M1 * (F2[5] * (V3[2] - V3[5]) + 4. *
+ (F2[4] * 1./4. * (V3[3] - cI * (V3[4]))))) + F2[3] * (P1[0] * (-1.) *
+ (V3[2] + V3[5]) + (P1[1] * (V3[3] + cI * (V3[4])) + (P1[2] * (V3[4] - cI
+ * (V3[3])) + P1[3] * (V3[2] + V3[5]))))));
+ F1[4] = denom * (-cI) * (F2[4] * (P1[0] * (V3[2] + V3[5]) + (P1[1] * (+cI *
+ (V3[4]) - V3[3]) + (P1[2] * (-1.) * (V3[4] + cI * (V3[3])) - P1[3] *
+ (V3[2] + V3[5])))) + (F2[5] * (P1[0] * (V3[3] + cI * (V3[4])) + (P1[1] *
+ (V3[5] - V3[2]) + (P1[2] * (-cI * (V3[2]) + cI * (V3[5])) - P1[3] *
+ (V3[3] + cI * (V3[4]))))) + M1 * (F2[2] * 4. * (V3[5] - V3[2]) + 4. *
+ (F2[3] * (V3[3] + cI * (V3[4]))))));
+ F1[5] = denom * cI * (F2[4] * (P1[0] * (+cI * (V3[4]) - V3[3]) + (P1[1] *
+ (V3[2] + V3[5]) + (P1[2] * (-1.) * (+cI * (V3[2] + V3[5])) + P1[3] * (+cI
+ * (V3[4]) - V3[3])))) + (F2[5] * (P1[0] * (V3[5] - V3[2]) + (P1[1] *
+ (V3[3] + cI * (V3[4])) + (P1[2] * (V3[4] - cI * (V3[3])) + P1[3] * (V3[5]
+ - V3[2])))) + M1 * (F2[2] * 4. * (+cI * (V3[4]) - V3[3]) + 4. * (F2[3] *
+ (V3[2] + V3[5])))));
+}
+
+
+void FFV1_0(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> V3[], std::complex<double> COUP, std::complex<double>
+ & vertex)
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> TMP13;
+ TMP13 = (F1[2] * (F2[4] * (V3[2] + V3[5]) + F2[5] * (V3[3] + cI * (V3[4]))) +
+ (F1[3] * (F2[4] * (V3[3] - cI * (V3[4])) + F2[5] * (V3[2] - V3[5])) +
+ (F1[4] * (F2[2] * (V3[2] - V3[5]) - F2[3] * (V3[3] + cI * (V3[4]))) +
+ F1[5] * (F2[2] * (+cI * (V3[4]) - V3[3]) + F2[3] * (V3[2] + V3[5])))));
+ vertex = COUP * - cI * TMP13;
+}
+
+
+void VVVV4P0_1(std::complex<double> V2[], std::complex<double> V3[],
+ std::complex<double> V4[], std::complex<double> COUP, double M1, double W1,
+ std::complex<double> V1[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> TMP12;
+ std::complex<double> TMP11;
+ double P1[4];
+ std::complex<double> denom;
+ V1[0] = +V2[0] + V3[0] + V4[0];
+ V1[1] = +V2[1] + V3[1] + V4[1];
+ P1[0] = -V1[0].real();
+ P1[1] = -V1[1].real();
+ P1[2] = -V1[1].imag();
+ P1[3] = -V1[0].imag();
+ TMP11 = (V2[2] * V4[2] - V2[3] * V4[3] - V2[4] * V4[4] - V2[5] * V4[5]);
+ TMP12 = (V3[2] * V4[2] - V3[3] * V4[3] - V3[4] * V4[4] - V3[5] * V4[5]);
+ denom = COUP/((P1[0] * P1[0]) - (P1[1] * P1[1]) - (P1[2] * P1[2]) - (P1[3] *
+ P1[3]) - M1 * (M1 - cI * W1));
+ V1[2] = denom * (-cI * (V3[2] * TMP11) + cI * (V2[2] * TMP12));
+ V1[3] = denom * (-cI * (V3[3] * TMP11) + cI * (V2[3] * TMP12));
+ V1[4] = denom * (-cI * (V3[4] * TMP11) + cI * (V2[4] * TMP12));
+ V1[5] = denom * (-cI * (V3[5] * TMP11) + cI * (V2[5] * TMP12));
+}
+
+
+void VVVV3P0_1(std::complex<double> V2[], std::complex<double> V3[],
+ std::complex<double> V4[], std::complex<double> COUP, double M1, double W1,
+ std::complex<double> V1[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> TMP12;
+ double P1[4];
+ std::complex<double> TMP6;
+ std::complex<double> denom;
+ V1[0] = +V2[0] + V3[0] + V4[0];
+ V1[1] = +V2[1] + V3[1] + V4[1];
+ P1[0] = -V1[0].real();
+ P1[1] = -V1[1].real();
+ P1[2] = -V1[1].imag();
+ P1[3] = -V1[0].imag();
+ TMP6 = (V3[2] * V2[2] - V3[3] * V2[3] - V3[4] * V2[4] - V3[5] * V2[5]);
+ TMP12 = (V3[2] * V4[2] - V3[3] * V4[3] - V3[4] * V4[4] - V3[5] * V4[5]);
+ denom = COUP/((P1[0] * P1[0]) - (P1[1] * P1[1]) - (P1[2] * P1[2]) - (P1[3] *
+ P1[3]) - M1 * (M1 - cI * W1));
+ V1[2] = denom * (-cI * (TMP6 * V4[2]) + cI * (V2[2] * TMP12));
+ V1[3] = denom * (-cI * (TMP6 * V4[3]) + cI * (V2[3] * TMP12));
+ V1[4] = denom * (-cI * (TMP6 * V4[4]) + cI * (V2[4] * TMP12));
+ V1[5] = denom * (-cI * (TMP6 * V4[5]) + cI * (V2[5] * TMP12));
+}
+
+
+void VVV1_0(std::complex<double> V1[], std::complex<double> V2[],
+ std::complex<double> V3[], std::complex<double> COUP, std::complex<double>
+ & vertex)
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> TMP2;
+ std::complex<double> TMP1;
+ double P1[4];
+ std::complex<double> TMP0;
+ double P2[4];
+ std::complex<double> TMP7;
+ double P3[4];
+ std::complex<double> TMP6;
+ std::complex<double> TMP5;
+ std::complex<double> TMP4;
+ std::complex<double> TMP3;
+ std::complex<double> TMP8;
+ P1[0] = V1[0].real();
+ P1[1] = V1[1].real();
+ P1[2] = V1[1].imag();
+ P1[3] = V1[0].imag();
+ P2[0] = V2[0].real();
+ P2[1] = V2[1].real();
+ P2[2] = V2[1].imag();
+ P2[3] = V2[0].imag();
+ P3[0] = V3[0].real();
+ P3[1] = V3[1].real();
+ P3[2] = V3[1].imag();
+ P3[3] = V3[0].imag();
+ TMP8 = (V1[2] * P3[0] - V1[3] * P3[1] - V1[4] * P3[2] - V1[5] * P3[3]);
+ TMP5 = (V2[2] * P3[0] - V2[3] * P3[1] - V2[4] * P3[2] - V2[5] * P3[3]);
+ TMP4 = (P1[0] * V2[2] - P1[1] * V2[3] - P1[2] * V2[4] - P1[3] * V2[5]);
+ TMP7 = (V1[2] * P2[0] - V1[3] * P2[1] - V1[4] * P2[2] - V1[5] * P2[3]);
+ TMP6 = (V3[2] * V2[2] - V3[3] * V2[3] - V3[4] * V2[4] - V3[5] * V2[5]);
+ TMP1 = (V2[2] * V1[2] - V2[3] * V1[3] - V2[4] * V1[4] - V2[5] * V1[5]);
+ TMP0 = (V3[2] * P1[0] - V3[3] * P1[1] - V3[4] * P1[2] - V3[5] * P1[3]);
+ TMP3 = (V3[2] * V1[2] - V3[3] * V1[3] - V3[4] * V1[4] - V3[5] * V1[5]);
+ TMP2 = (V3[2] * P2[0] - V3[3] * P2[1] - V3[4] * P2[2] - V3[5] * P2[3]);
+ vertex = COUP * (TMP1 * (-cI * (TMP0) + cI * (TMP2)) + (TMP3 * (-cI * (TMP5)
+ + cI * (TMP4)) + TMP6 * (-cI * (TMP7) + cI * (TMP8))));
+}
+
+
+void FFV2_3(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> COUP, double M3, double W3, std::complex<double> V3[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> denom;
+ std::complex<double> TMP10;
+ double P3[4];
+ double OM3;
+ OM3 = 0.;
+ if (M3 != 0.)
+ OM3 = 1./(M3 * M3);
+ V3[0] = +F1[0] + F2[0];
+ V3[1] = +F1[1] + F2[1];
+ P3[0] = -V3[0].real();
+ P3[1] = -V3[1].real();
+ P3[2] = -V3[1].imag();
+ P3[3] = -V3[0].imag();
+ TMP10 = (F1[2] * (F2[4] * (P3[0] + P3[3]) + F2[5] * (P3[1] + cI * (P3[2]))) +
+ F1[3] * (F2[4] * (P3[1] - cI * (P3[2])) + F2[5] * (P3[0] - P3[3])));
+ denom = COUP/((P3[0] * P3[0]) - (P3[1] * P3[1]) - (P3[2] * P3[2]) - (P3[3] *
+ P3[3]) - M3 * (M3 - cI * W3));
+ V3[2] = denom * (-cI) * (F1[2] * F2[4] + F1[3] * F2[5] - P3[0] * OM3 *
+ TMP10);
+ V3[3] = denom * (-cI) * (-F1[2] * F2[5] - F1[3] * F2[4] - P3[1] * OM3 *
+ TMP10);
+ V3[4] = denom * (-cI) * (-cI * (F1[2] * F2[5]) + cI * (F1[3] * F2[4]) - P3[2]
+ * OM3 * TMP10);
+ V3[5] = denom * (-cI) * (F1[3] * F2[5] - F1[2] * F2[4] - P3[3] * OM3 *
+ TMP10);
+}
+
+void FFV2_4_3(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> COUP1, std::complex<double> COUP2, double M3, double
+ W3, std::complex<double> V3[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> denom;
+ double P3[4];
+ double OM3;
+ int i;
+ std::complex<double> Vtmp[6];
+ FFV2_3(F1, F2, COUP1, M3, W3, V3);
+ FFV4_3(F1, F2, COUP2, M3, W3, Vtmp);
+ i = 2;
+ while (i < 6)
+ {
+ V3[i] = V3[i] + Vtmp[i];
+ i++;
+ }
+}
+
+void FFV5_2(std::complex<double> F1[], std::complex<double> V3[],
+ std::complex<double> COUP, double M2, double W2, std::complex<double> F2[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ double P2[4];
+ std::complex<double> denom;
+ F2[0] = +F1[0] + V3[0];
+ F2[1] = +F1[1] + V3[1];
+ P2[0] = -F2[0].real();
+ P2[1] = -F2[1].real();
+ P2[2] = -F2[1].imag();
+ P2[3] = -F2[0].imag();
+ denom = COUP/((P2[0] * P2[0]) - (P2[1] * P2[1]) - (P2[2] * P2[2]) - (P2[3] *
+ P2[3]) - M2 * (M2 - cI * W2));
+ F2[2] = denom * cI * (F1[2] * (P2[0] * (V3[2] + V3[5]) + (P2[1] * (-1.) *
+ (V3[3] + cI * (V3[4])) + (P2[2] * (+cI * (V3[3]) - V3[4]) - P2[3] *
+ (V3[2] + V3[5])))) + (F1[3] * (P2[0] * (V3[3] - cI * (V3[4])) + (P2[1] *
+ (V3[5] - V3[2]) + (P2[2] * (-cI * (V3[5]) + cI * (V3[2])) + P2[3] * (+cI
+ * (V3[4]) - V3[3])))) + M2 * (F1[4] * 4. * (V3[2] - V3[5]) + 4. * (F1[5]
+ * (+cI * (V3[4]) - V3[3])))));
+ F2[3] = denom * cI * (F1[2] * (P2[0] * (V3[3] + cI * (V3[4])) + (P2[1] *
+ (-1.) * (V3[2] + V3[5]) + (P2[2] * (-1.) * (+cI * (V3[2] + V3[5])) +
+ P2[3] * (V3[3] + cI * (V3[4]))))) + (F1[3] * (P2[0] * (V3[2] - V3[5]) +
+ (P2[1] * (+cI * (V3[4]) - V3[3]) + (P2[2] * (-1.) * (V3[4] + cI *
+ (V3[3])) + P2[3] * (V3[2] - V3[5])))) + M2 * (F1[4] * (-4.) * (V3[3] + cI
+ * (V3[4])) + 4. * (F1[5] * (V3[2] + V3[5])))));
+ F2[4] = denom * (-4. * cI) * (F1[4] * (P2[0] * (V3[5] - V3[2]) + (P2[1] *
+ (V3[3] + cI * (V3[4])) + (P2[2] * (V3[4] - cI * (V3[3])) + P2[3] * (V3[5]
+ - V3[2])))) + (+1./4. * (M2 * (F1[3] * (+cI * (V3[4]) - V3[3]) + 4. *
+ (F1[2] * (-1./4.) * (V3[2] + V3[5])))) + F1[5] * (P2[0] * (V3[3] - cI *
+ (V3[4])) + (P2[1] * (-1.) * (V3[2] + V3[5]) + (P2[2] * (+cI * (V3[2] +
+ V3[5])) + P2[3] * (V3[3] - cI * (V3[4])))))));
+ F2[5] = denom * (-4. * cI) * (F1[4] * (P2[0] * (V3[3] + cI * (V3[4])) +
+ (P2[1] * (V3[5] - V3[2]) + (P2[2] * (-cI * (V3[2]) + cI * (V3[5])) -
+ P2[3] * (V3[3] + cI * (V3[4]))))) + (+1./4. * (M2 * (F1[3] * (V3[5] -
+ V3[2]) + 4. * (F1[2] * (-1./4.) * (V3[3] + cI * (V3[4]))))) + F1[5] *
+ (P2[0] * (-1.) * (V3[2] + V3[5]) + (P2[1] * (V3[3] - cI * (V3[4])) +
+ (P2[2] * (V3[4] + cI * (V3[3])) + P2[3] * (V3[2] + V3[5]))))));
+}
+
+
+void FFV2_1(std::complex<double> F2[], std::complex<double> V3[],
+ std::complex<double> COUP, double M1, double W1, std::complex<double> F1[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ double P1[4];
+ std::complex<double> denom;
+ F1[0] = +F2[0] + V3[0];
+ F1[1] = +F2[1] + V3[1];
+ P1[0] = -F1[0].real();
+ P1[1] = -F1[1].real();
+ P1[2] = -F1[1].imag();
+ P1[3] = -F1[0].imag();
+ denom = COUP/((P1[0] * P1[0]) - (P1[1] * P1[1]) - (P1[2] * P1[2]) - (P1[3] *
+ P1[3]) - M1 * (M1 - cI * W1));
+ F1[2] = denom * cI * M1 * (F2[4] * (V3[2] + V3[5]) + F2[5] * (V3[3] + cI *
+ (V3[4])));
+ F1[3] = denom * - cI * M1 * (F2[4] * (+cI * (V3[4]) - V3[3]) + F2[5] * (V3[5]
+ - V3[2]));
+ F1[4] = denom * (-cI) * (F2[4] * (P1[0] * (V3[2] + V3[5]) + (P1[1] * (+cI *
+ (V3[4]) - V3[3]) + (P1[2] * (-1.) * (V3[4] + cI * (V3[3])) - P1[3] *
+ (V3[2] + V3[5])))) + F2[5] * (P1[0] * (V3[3] + cI * (V3[4])) + (P1[1] *
+ (V3[5] - V3[2]) + (P1[2] * (-cI * (V3[2]) + cI * (V3[5])) - P1[3] *
+ (V3[3] + cI * (V3[4]))))));
+ F1[5] = denom * (-cI) * (F2[4] * (P1[0] * (V3[3] - cI * (V3[4])) + (P1[1] *
+ (-1.) * (V3[2] + V3[5]) + (P1[2] * (+cI * (V3[2] + V3[5])) + P1[3] *
+ (V3[3] - cI * (V3[4]))))) + F2[5] * (P1[0] * (V3[2] - V3[5]) + (P1[1] *
+ (-1.) * (V3[3] + cI * (V3[4])) + (P1[2] * (+cI * (V3[3]) - V3[4]) + P1[3]
+ * (V3[2] - V3[5])))));
+}
+
+void FFV2_5_1(std::complex<double> F2[], std::complex<double> V3[],
+ std::complex<double> COUP1, std::complex<double> COUP2, double M1, double
+ W1, std::complex<double> F1[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ double P1[4];
+ std::complex<double> denom;
+ int i;
+ std::complex<double> Ftmp[6];
+ FFV2_1(F2, V3, COUP1, M1, W1, F1);
+ FFV5_1(F2, V3, COUP2, M1, W1, Ftmp);
+ i = 2;
+ while (i < 6)
+ {
+ F1[i] = F1[i] + Ftmp[i];
+ i++;
+ }
+}
+
+void FFV5_0(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> V3[], std::complex<double> COUP, std::complex<double>
+ & vertex)
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> TMP15;
+ std::complex<double> TMP16;
+ TMP15 = (F1[2] * (F2[4] * (V3[2] + V3[5]) + F2[5] * (V3[3] + cI * (V3[4]))) +
+ F1[3] * (F2[4] * (V3[3] - cI * (V3[4])) + F2[5] * (V3[2] - V3[5])));
+ TMP16 = (F1[4] * (F2[2] * (V3[2] - V3[5]) - F2[3] * (V3[3] + cI * (V3[4]))) +
+ F1[5] * (F2[2] * (+cI * (V3[4]) - V3[3]) + F2[3] * (V3[2] + V3[5])));
+ vertex = COUP * (-1.) * (+cI * (TMP15) + 4. * cI * (TMP16));
+}
+
+
+void FFV1_1(std::complex<double> F2[], std::complex<double> V3[],
+ std::complex<double> COUP, double M1, double W1, std::complex<double> F1[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ double P1[4];
+ std::complex<double> denom;
+ F1[0] = +F2[0] + V3[0];
+ F1[1] = +F2[1] + V3[1];
+ P1[0] = -F1[0].real();
+ P1[1] = -F1[1].real();
+ P1[2] = -F1[1].imag();
+ P1[3] = -F1[0].imag();
+ denom = COUP/((P1[0] * P1[0]) - (P1[1] * P1[1]) - (P1[2] * P1[2]) - (P1[3] *
+ P1[3]) - M1 * (M1 - cI * W1));
+ F1[2] = denom * cI * (F2[2] * (P1[0] * (V3[5] - V3[2]) + (P1[1] * (V3[3] - cI
+ * (V3[4])) + (P1[2] * (V3[4] + cI * (V3[3])) + P1[3] * (V3[5] - V3[2]))))
+ + (F2[3] * (P1[0] * (V3[3] + cI * (V3[4])) + (P1[1] * (-1.) * (V3[2] +
+ V3[5]) + (P1[2] * (-1.) * (+cI * (V3[2] + V3[5])) + P1[3] * (V3[3] + cI *
+ (V3[4]))))) + M1 * (F2[4] * (V3[2] + V3[5]) + F2[5] * (V3[3] + cI *
+ (V3[4])))));
+ F1[3] = denom * (-cI) * (F2[2] * (P1[0] * (+cI * (V3[4]) - V3[3]) + (P1[1] *
+ (V3[2] - V3[5]) + (P1[2] * (-cI * (V3[2]) + cI * (V3[5])) + P1[3] *
+ (V3[3] - cI * (V3[4]))))) + (F2[3] * (P1[0] * (V3[2] + V3[5]) + (P1[1] *
+ (-1.) * (V3[3] + cI * (V3[4])) + (P1[2] * (+cI * (V3[3]) - V3[4]) - P1[3]
+ * (V3[2] + V3[5])))) + M1 * (F2[4] * (+cI * (V3[4]) - V3[3]) + F2[5] *
+ (V3[5] - V3[2]))));
+ F1[4] = denom * (-cI) * (F2[4] * (P1[0] * (V3[2] + V3[5]) + (P1[1] * (+cI *
+ (V3[4]) - V3[3]) + (P1[2] * (-1.) * (V3[4] + cI * (V3[3])) - P1[3] *
+ (V3[2] + V3[5])))) + (F2[5] * (P1[0] * (V3[3] + cI * (V3[4])) + (P1[1] *
+ (V3[5] - V3[2]) + (P1[2] * (-cI * (V3[2]) + cI * (V3[5])) - P1[3] *
+ (V3[3] + cI * (V3[4]))))) + M1 * (F2[2] * (V3[5] - V3[2]) + F2[3] *
+ (V3[3] + cI * (V3[4])))));
+ F1[5] = denom * cI * (F2[4] * (P1[0] * (+cI * (V3[4]) - V3[3]) + (P1[1] *
+ (V3[2] + V3[5]) + (P1[2] * (-1.) * (+cI * (V3[2] + V3[5])) + P1[3] * (+cI
+ * (V3[4]) - V3[3])))) + (F2[5] * (P1[0] * (V3[5] - V3[2]) + (P1[1] *
+ (V3[3] + cI * (V3[4])) + (P1[2] * (V3[4] - cI * (V3[3])) + P1[3] * (V3[5]
+ - V3[2])))) + M1 * (F2[2] * (+cI * (V3[4]) - V3[3]) + F2[3] * (V3[2] +
+ V3[5]))));
+}
+
+
+void FFV4_3(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> COUP, double M3, double W3, std::complex<double> V3[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> denom;
+ std::complex<double> TMP10;
+ double P3[4];
+ double OM3;
+ std::complex<double> TMP14;
+ OM3 = 0.;
+ if (M3 != 0.)
+ OM3 = 1./(M3 * M3);
+ V3[0] = +F1[0] + F2[0];
+ V3[1] = +F1[1] + F2[1];
+ P3[0] = -V3[0].real();
+ P3[1] = -V3[1].real();
+ P3[2] = -V3[1].imag();
+ P3[3] = -V3[0].imag();
+ TMP14 = (F1[4] * (F2[2] * (P3[0] - P3[3]) - F2[3] * (P3[1] + cI * (P3[2]))) +
+ F1[5] * (F2[2] * (+cI * (P3[2]) - P3[1]) + F2[3] * (P3[0] + P3[3])));
+ TMP10 = (F1[2] * (F2[4] * (P3[0] + P3[3]) + F2[5] * (P3[1] + cI * (P3[2]))) +
+ F1[3] * (F2[4] * (P3[1] - cI * (P3[2])) + F2[5] * (P3[0] - P3[3])));
+ denom = COUP/((P3[0] * P3[0]) - (P3[1] * P3[1]) - (P3[2] * P3[2]) - (P3[3] *
+ P3[3]) - M3 * (M3 - cI * W3));
+ V3[2] = denom * (-2. * cI) * (OM3 * - 1./2. * P3[0] * (TMP10 + 2. * (TMP14))
+ + (+1./2. * (F1[2] * F2[4] + F1[3] * F2[5]) + F1[4] * F2[2] + F1[5] *
+ F2[3]));
+ V3[3] = denom * (-2. * cI) * (OM3 * - 1./2. * P3[1] * (TMP10 + 2. * (TMP14))
+ + (-1./2. * (F1[2] * F2[5] + F1[3] * F2[4]) + F1[4] * F2[3] + F1[5] *
+ F2[2]));
+ V3[4] = denom * 2. * cI * (OM3 * 1./2. * P3[2] * (TMP10 + 2. * (TMP14)) +
+ (+1./2. * cI * (F1[2] * F2[5]) - 1./2. * cI * (F1[3] * F2[4]) - cI *
+ (F1[4] * F2[3]) + cI * (F1[5] * F2[2])));
+ V3[5] = denom * 2. * cI * (OM3 * 1./2. * P3[3] * (TMP10 + 2. * (TMP14)) +
+ (+1./2. * (F1[2] * F2[4]) - 1./2. * (F1[3] * F2[5]) - F1[4] * F2[2] +
+ F1[5] * F2[3]));
+}
+
+
+void VVVV1P0_1(std::complex<double> V2[], std::complex<double> V3[],
+ std::complex<double> V4[], std::complex<double> COUP, double M1, double W1,
+ std::complex<double> V1[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> TMP11;
+ double P1[4];
+ std::complex<double> TMP6;
+ std::complex<double> denom;
+ V1[0] = +V2[0] + V3[0] + V4[0];
+ V1[1] = +V2[1] + V3[1] + V4[1];
+ P1[0] = -V1[0].real();
+ P1[1] = -V1[1].real();
+ P1[2] = -V1[1].imag();
+ P1[3] = -V1[0].imag();
+ TMP6 = (V3[2] * V2[2] - V3[3] * V2[3] - V3[4] * V2[4] - V3[5] * V2[5]);
+ TMP11 = (V2[2] * V4[2] - V2[3] * V4[3] - V2[4] * V4[4] - V2[5] * V4[5]);
+ denom = COUP/((P1[0] * P1[0]) - (P1[1] * P1[1]) - (P1[2] * P1[2]) - (P1[3] *
+ P1[3]) - M1 * (M1 - cI * W1));
+ V1[2] = denom * (-cI * (TMP6 * V4[2]) + cI * (V3[2] * TMP11));
+ V1[3] = denom * (-cI * (TMP6 * V4[3]) + cI * (V3[3] * TMP11));
+ V1[4] = denom * (-cI * (TMP6 * V4[4]) + cI * (V3[4] * TMP11));
+ V1[5] = denom * (-cI * (TMP6 * V4[5]) + cI * (V3[5] * TMP11));
+}
+
+
+void VVV1P0_1(std::complex<double> V2[], std::complex<double> V3[],
+ std::complex<double> COUP, double M1, double W1, std::complex<double> V1[])
+{
+ static std::complex<double> cI = std::complex<double> (0., 1.);
+ std::complex<double> TMP2;
+ double P1[4];
+ std::complex<double> TMP0;
+ double P2[4];
+ double P3[4];
+ std::complex<double> TMP6;
+ std::complex<double> TMP5;
+ std::complex<double> TMP4;
+ std::complex<double> denom;
+ P2[0] = V2[0].real();
+ P2[1] = V2[1].real();
+ P2[2] = V2[1].imag();
+ P2[3] = V2[0].imag();
+ P3[0] = V3[0].real();
+ P3[1] = V3[1].real();
+ P3[2] = V3[1].imag();
+ P3[3] = V3[0].imag();
+ V1[0] = +V2[0] + V3[0];
+ V1[1] = +V2[1] + V3[1];
+ P1[0] = -V1[0].real();
+ P1[1] = -V1[1].real();
+ P1[2] = -V1[1].imag();
+ P1[3] = -V1[0].imag();
+ TMP5 = (V2[2] * P3[0] - V2[3] * P3[1] - V2[4] * P3[2] - V2[5] * P3[3]);
+ TMP4 = (P1[0] * V2[2] - P1[1] * V2[3] - P1[2] * V2[4] - P1[3] * V2[5]);
+ TMP6 = (V3[2] * V2[2] - V3[3] * V2[3] - V3[4] * V2[4] - V3[5] * V2[5]);
+ TMP0 = (V3[2] * P1[0] - V3[3] * P1[1] - V3[4] * P1[2] - V3[5] * P1[3]);
+ TMP2 = (V3[2] * P2[0] - V3[3] * P2[1] - V3[4] * P2[2] - V3[5] * P2[3]);
+ denom = COUP/((P1[0] * P1[0]) - (P1[1] * P1[1]) - (P1[2] * P1[2]) - (P1[3] *
+ P1[3]) - M1 * (M1 - cI * W1));
+ V1[2] = denom * (TMP6 * (-cI * (P2[0]) + cI * (P3[0])) + (V2[2] * (-cI *
+ (TMP0) + cI * (TMP2)) + V3[2] * (-cI * (TMP5) + cI * (TMP4))));
+ V1[3] = denom * (TMP6 * (-cI * (P2[1]) + cI * (P3[1])) + (V2[3] * (-cI *
+ (TMP0) + cI * (TMP2)) + V3[3] * (-cI * (TMP5) + cI * (TMP4))));
+ V1[4] = denom * (TMP6 * (-cI * (P2[2]) + cI * (P3[2])) + (V2[4] * (-cI *
+ (TMP0) + cI * (TMP2)) + V3[4] * (-cI * (TMP5) + cI * (TMP4))));
+ V1[5] = denom * (TMP6 * (-cI * (P2[3]) + cI * (P3[3])) + (V2[5] * (-cI *
+ (TMP0) + cI * (TMP2)) + V3[5] * (-cI * (TMP5) + cI * (TMP4))));
+}
+
+
+} // end namespace MG5_sm_COLOREA
+
diff --git a/Shower/Dipole/Colorea/HelAmps_sm.h b/Shower/Dipole/Colorea/HelAmps_sm.h
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/HelAmps_sm.h
@@ -0,0 +1,106 @@
+//==========================================================================
+// This file has been automatically generated for C++ Standalone
+// MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+// By the MadGraph5_aMC@NLO Development Team
+// Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+//==========================================================================
+
+#ifndef HelAmps_sm_H
+#define HelAmps_sm_H
+
+#include <cmath>
+#include <complex>
+
+using namespace std;
+
+namespace MG5_sm_COLOREA
+{
+double Sgn(double e, double f);
+
+void oxxxxx(double p[4], double fmass, int nhel, int nsf, std::complex<double>
+ fo[6]);
+
+void sxxxxx(double p[4], int nss, std::complex<double> sc[3]);
+
+void ixxxxx(double p[4], double fmass, int nhel, int nsf, std::complex<double>
+ fi[6]);
+
+void txxxxx(double p[4], double tmass, int nhel, int nst, std::complex<double>
+ fi[18]);
+
+void vxxxxx(double p[4], double vmass, int nhel, int nsv, std::complex<double>
+ v[6]);
+
+void FFV1P0_3(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> COUP, double M3, double W3, std::complex<double> V3[]);
+
+void FFV2_2(std::complex<double> F1[], std::complex<double> V3[],
+ std::complex<double> COUP, double M2, double W2, std::complex<double> F2[]);
+void FFV2_5_2(std::complex<double> F1[], std::complex<double> V3[],
+ std::complex<double> COUP1, std::complex<double> COUP2, double M2, double
+ W2, std::complex<double> F2[]);
+
+void FFV1_2(std::complex<double> F1[], std::complex<double> V3[],
+ std::complex<double> COUP, double M2, double W2, std::complex<double> F2[]);
+
+void FFV2_0(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> V3[], std::complex<double> COUP, std::complex<double>
+ & vertex);
+void FFV2_5_0(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> V3[], std::complex<double> COUP1, std::complex<double>
+ COUP2, std::complex<double> & vertex);
+
+void FFV5_1(std::complex<double> F2[], std::complex<double> V3[],
+ std::complex<double> COUP, double M1, double W1, std::complex<double> F1[]);
+
+void FFV1_0(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> V3[], std::complex<double> COUP, std::complex<double>
+ & vertex);
+
+void VVVV4P0_1(std::complex<double> V2[], std::complex<double> V3[],
+ std::complex<double> V4[], std::complex<double> COUP, double M1, double W1,
+ std::complex<double> V1[]);
+
+void VVVV3P0_1(std::complex<double> V2[], std::complex<double> V3[],
+ std::complex<double> V4[], std::complex<double> COUP, double M1, double W1,
+ std::complex<double> V1[]);
+
+void VVV1_0(std::complex<double> V1[], std::complex<double> V2[],
+ std::complex<double> V3[], std::complex<double> COUP, std::complex<double>
+ & vertex);
+
+void FFV2_3(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> COUP, double M3, double W3, std::complex<double> V3[]);
+void FFV2_4_3(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> COUP1, std::complex<double> COUP2, double M3, double
+ W3, std::complex<double> V3[]);
+
+void FFV5_2(std::complex<double> F1[], std::complex<double> V3[],
+ std::complex<double> COUP, double M2, double W2, std::complex<double> F2[]);
+
+void FFV2_1(std::complex<double> F2[], std::complex<double> V3[],
+ std::complex<double> COUP, double M1, double W1, std::complex<double> F1[]);
+void FFV2_5_1(std::complex<double> F2[], std::complex<double> V3[],
+ std::complex<double> COUP1, std::complex<double> COUP2, double M1, double
+ W1, std::complex<double> F1[]);
+
+void FFV5_0(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> V3[], std::complex<double> COUP, std::complex<double>
+ & vertex);
+
+void FFV1_1(std::complex<double> F2[], std::complex<double> V3[],
+ std::complex<double> COUP, double M1, double W1, std::complex<double> F1[]);
+
+void FFV4_3(std::complex<double> F1[], std::complex<double> F2[],
+ std::complex<double> COUP, double M3, double W3, std::complex<double> V3[]);
+
+void VVVV1P0_1(std::complex<double> V2[], std::complex<double> V3[],
+ std::complex<double> V4[], std::complex<double> COUP, double M1, double W1,
+ std::complex<double> V1[]);
+
+void VVV1P0_1(std::complex<double> V2[], std::complex<double> V3[],
+ std::complex<double> COUP, double M1, double W1, std::complex<double> V1[]);
+
+} // end namespace MG5_sm_COLOREA
+
+#endif // HelAmps_sm_H
diff --git a/Shower/Dipole/Colorea/Makefile.am b/Shower/Dipole/Colorea/Makefile.am
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/Makefile.am
@@ -0,0 +1,19 @@
+noinst_LTLIBRARIES = libHwDipoleShowerColorea.la
+
+libHwDipoleShowerColorea_la_SOURCES = \
+ Colorea.fh \
+ Colorea.cc \
+ Colorea.h \
+ HelAmps_sm.cc \
+ HelAmps_sm.h \
+ Parameters_sm.cc \
+ Parameters_sm.h \
+ read_slha_COLOREA.cc \
+ read_slha_COLOREA.h \
+ eeuugg.h \
+ eeuugg.cc \
+ eeuuggg.h \
+ eeuuggg.cc \
+ eeuugggg.h \
+ eeuugggg.cc
+
diff --git a/Shower/Dipole/Colorea/Parameters_sm.cc b/Shower/Dipole/Colorea/Parameters_sm.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/Parameters_sm.cc
@@ -0,0 +1,241 @@
+//==========================================================================
+// This file has been automatically generated for C++ by
+// MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+// By the MadGraph5_aMC@NLO Development Team
+// Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+//==========================================================================
+
+#include <iostream>
+#include <iomanip>
+#include "Parameters_sm.h"
+
+// Initialize static instance
+Parameters_sm * Parameters_sm::instance = 0;
+
+// Function to get static instance - only one instance per program
+Parameters_sm * Parameters_sm::getInstance()
+{
+ if (instance == 0)
+ instance = new Parameters_sm();
+
+ return instance;
+}
+
+void Parameters_sm::setIndependentParameters(SLHAReader_COLOREA& slha)
+{
+ // Define "zero"
+ zero = 0;
+ ZERO = 0;
+ // Prepare a vector for indices
+ vector<int> indices(2, 0);
+ mdl_WH = slha.get_block_entry("decay", 25, 6.382339e-03);
+ mdl_WW = slha.get_block_entry("decay", 24, 2.047600e+00);
+ mdl_WZ = slha.get_block_entry("decay", 23, 2.441404e+00);
+ mdl_WT = slha.get_block_entry("decay", 6, 1.491500e+00);
+ mdl_ymtau = slha.get_block_entry("yukawa", 15, 1.777000e+00);
+ mdl_ymt = slha.get_block_entry("yukawa", 6, 1.730000e+02);
+ mdl_ymb = slha.get_block_entry("yukawa", 5, 4.700000e+00);
+ aS = slha.get_block_entry("sminputs", 3, 1.180000e-01);
+ mdl_Gf = slha.get_block_entry("sminputs", 2, 1.166390e-05);
+ aEWM1 = slha.get_block_entry("sminputs", 1, 1.325070e+02);
+ mdl_MH = slha.get_block_entry("mass", 25, 1.250000e+02);
+ mdl_MZ = slha.get_block_entry("mass", 23, 9.118800e+01);
+ mdl_MTA = slha.get_block_entry("mass", 15, 1.777000e+00);
+ mdl_MT = slha.get_block_entry("mass", 6, 1.730000e+02);
+ mdl_MB = slha.get_block_entry("mass", 5, 4.700000e+00);
+ mdl_conjg__CKM3x3 = 1.;
+ mdl_CKM3x3 = 1.;
+ mdl_conjg__CKM1x1 = 1.;
+ mdl_complexi = std::complex<double> (0., 1.);
+ mdl_MZ__exp__2 = ((mdl_MZ) * (mdl_MZ));
+ mdl_MZ__exp__4 = ((mdl_MZ) * (mdl_MZ) * (mdl_MZ) * (mdl_MZ));
+ mdl_sqrt__2 = sqrt(2.);
+ mdl_MH__exp__2 = ((mdl_MH) * (mdl_MH));
+ mdl_aEW = 1./aEWM1;
+ mdl_MW = sqrt(mdl_MZ__exp__2/2. + sqrt(mdl_MZ__exp__4/4. - (mdl_aEW * M_PI *
+ mdl_MZ__exp__2)/(mdl_Gf * mdl_sqrt__2)));
+ mdl_sqrt__aEW = sqrt(mdl_aEW);
+ mdl_ee = 2. * mdl_sqrt__aEW * sqrt(M_PI);
+ mdl_MW__exp__2 = ((mdl_MW) * (mdl_MW));
+ mdl_sw2 = 1. - mdl_MW__exp__2/mdl_MZ__exp__2;
+ mdl_cw = sqrt(1. - mdl_sw2);
+ mdl_sqrt__sw2 = sqrt(mdl_sw2);
+ mdl_sw = mdl_sqrt__sw2;
+ mdl_g1 = mdl_ee/mdl_cw;
+ mdl_gw = mdl_ee/mdl_sw;
+ mdl_vev = (2. * mdl_MW * mdl_sw)/mdl_ee;
+ mdl_vev__exp__2 = ((mdl_vev) * (mdl_vev));
+ mdl_lam = mdl_MH__exp__2/(2. * mdl_vev__exp__2);
+ mdl_yb = (mdl_ymb * mdl_sqrt__2)/mdl_vev;
+ mdl_yt = (mdl_ymt * mdl_sqrt__2)/mdl_vev;
+ mdl_ytau = (mdl_ymtau * mdl_sqrt__2)/mdl_vev;
+ mdl_muH = sqrt(mdl_lam * mdl_vev__exp__2);
+ mdl_I1x33 = mdl_yb * mdl_conjg__CKM3x3;
+ mdl_I2x33 = mdl_yt * mdl_conjg__CKM3x3;
+ mdl_I3x33 = mdl_CKM3x3 * mdl_yt;
+ mdl_I4x33 = mdl_CKM3x3 * mdl_yb;
+ mdl_ee__exp__2 = ((mdl_ee) * (mdl_ee));
+ mdl_sw__exp__2 = ((mdl_sw) * (mdl_sw));
+ mdl_cw__exp__2 = ((mdl_cw) * (mdl_cw));
+}
+void Parameters_sm::setIndependentCouplings()
+{
+ GC_2 = (2. * mdl_ee * mdl_complexi)/3.;
+ GC_3 = -(mdl_ee * mdl_complexi);
+ GC_50 = -(mdl_cw * mdl_ee * mdl_complexi)/(2. * mdl_sw);
+ GC_51 = (mdl_cw * mdl_ee * mdl_complexi)/(2. * mdl_sw);
+ GC_58 = -(mdl_ee * mdl_complexi * mdl_sw)/(6. * mdl_cw);
+ GC_59 = (mdl_ee * mdl_complexi * mdl_sw)/(2. * mdl_cw);
+}
+void Parameters_sm::setDependentParameters()
+{
+ mdl_sqrt__aS = sqrt(aS);
+ G = 2. * mdl_sqrt__aS * sqrt(M_PI);
+ mdl_G__exp__2 = ((G) * (G));
+}
+void Parameters_sm::setDependentCouplings()
+{
+ GC_12 = mdl_complexi * mdl_G__exp__2;
+ GC_11 = mdl_complexi * G;
+ GC_10 = -G;
+}
+
+// Routines for printing out parameters
+void Parameters_sm::printIndependentParameters()
+{
+ cout << "sm model parameters independent of event kinematics:" << endl;
+ cout << setw(20) << "mdl_WH " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_WH << endl;
+ cout << setw(20) << "mdl_WW " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_WW << endl;
+ cout << setw(20) << "mdl_WZ " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_WZ << endl;
+ cout << setw(20) << "mdl_WT " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_WT << endl;
+ cout << setw(20) << "mdl_ymtau " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_ymtau << endl;
+ cout << setw(20) << "mdl_ymt " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_ymt << endl;
+ cout << setw(20) << "mdl_ymb " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_ymb << endl;
+ cout << setw(20) << "aS " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << aS << endl;
+ cout << setw(20) << "mdl_Gf " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_Gf << endl;
+ cout << setw(20) << "aEWM1 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << aEWM1 << endl;
+ cout << setw(20) << "mdl_MH " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_MH << endl;
+ cout << setw(20) << "mdl_MZ " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_MZ << endl;
+ cout << setw(20) << "mdl_MTA " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_MTA << endl;
+ cout << setw(20) << "mdl_MT " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_MT << endl;
+ cout << setw(20) << "mdl_MB " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_MB << endl;
+ cout << setw(20) << "mdl_conjg__CKM3x3 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_conjg__CKM3x3 << endl;
+ cout << setw(20) << "mdl_CKM3x3 " << "= " << setiosflags(ios::scientific)
+ << setw(10) << mdl_CKM3x3 << endl;
+ cout << setw(20) << "mdl_conjg__CKM1x1 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_conjg__CKM1x1 << endl;
+ cout << setw(20) << "mdl_complexi " << "= " << setiosflags(ios::scientific)
+ << setw(10) << mdl_complexi << endl;
+ cout << setw(20) << "mdl_MZ__exp__2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_MZ__exp__2 << endl;
+ cout << setw(20) << "mdl_MZ__exp__4 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_MZ__exp__4 << endl;
+ cout << setw(20) << "mdl_sqrt__2 " << "= " << setiosflags(ios::scientific)
+ << setw(10) << mdl_sqrt__2 << endl;
+ cout << setw(20) << "mdl_MH__exp__2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_MH__exp__2 << endl;
+ cout << setw(20) << "mdl_aEW " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_aEW << endl;
+ cout << setw(20) << "mdl_MW " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_MW << endl;
+ cout << setw(20) << "mdl_sqrt__aEW " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_sqrt__aEW << endl;
+ cout << setw(20) << "mdl_ee " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_ee << endl;
+ cout << setw(20) << "mdl_MW__exp__2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_MW__exp__2 << endl;
+ cout << setw(20) << "mdl_sw2 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_sw2 << endl;
+ cout << setw(20) << "mdl_cw " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_cw << endl;
+ cout << setw(20) << "mdl_sqrt__sw2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_sqrt__sw2 << endl;
+ cout << setw(20) << "mdl_sw " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_sw << endl;
+ cout << setw(20) << "mdl_g1 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_g1 << endl;
+ cout << setw(20) << "mdl_gw " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_gw << endl;
+ cout << setw(20) << "mdl_vev " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_vev << endl;
+ cout << setw(20) << "mdl_vev__exp__2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_vev__exp__2 << endl;
+ cout << setw(20) << "mdl_lam " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_lam << endl;
+ cout << setw(20) << "mdl_yb " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_yb << endl;
+ cout << setw(20) << "mdl_yt " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_yt << endl;
+ cout << setw(20) << "mdl_ytau " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_ytau << endl;
+ cout << setw(20) << "mdl_muH " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_muH << endl;
+ cout << setw(20) << "mdl_I1x33 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_I1x33 << endl;
+ cout << setw(20) << "mdl_I2x33 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_I2x33 << endl;
+ cout << setw(20) << "mdl_I3x33 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_I3x33 << endl;
+ cout << setw(20) << "mdl_I4x33 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << mdl_I4x33 << endl;
+ cout << setw(20) << "mdl_ee__exp__2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_ee__exp__2 << endl;
+ cout << setw(20) << "mdl_sw__exp__2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_sw__exp__2 << endl;
+ cout << setw(20) << "mdl_cw__exp__2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_cw__exp__2 << endl;
+}
+void Parameters_sm::printIndependentCouplings()
+{
+ cout << "sm model couplings independent of event kinematics:" << endl;
+ cout << setw(20) << "GC_2 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_2 << endl;
+ cout << setw(20) << "GC_3 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_3 << endl;
+ cout << setw(20) << "GC_50 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_50 << endl;
+ cout << setw(20) << "GC_51 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_51 << endl;
+ cout << setw(20) << "GC_58 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_58 << endl;
+ cout << setw(20) << "GC_59 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_59 << endl;
+}
+void Parameters_sm::printDependentParameters()
+{
+ cout << "sm model parameters dependent on event kinematics:" << endl;
+ cout << setw(20) << "mdl_sqrt__aS " << "= " << setiosflags(ios::scientific)
+ << setw(10) << mdl_sqrt__aS << endl;
+ cout << setw(20) << "G " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << G << endl;
+ cout << setw(20) << "mdl_G__exp__2 " << "= " <<
+ setiosflags(ios::scientific) << setw(10) << mdl_G__exp__2 << endl;
+}
+void Parameters_sm::printDependentCouplings()
+{
+ cout << "sm model couplings dependent on event kinematics:" << endl;
+ cout << setw(20) << "GC_12 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_12 << endl;
+ cout << setw(20) << "GC_11 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_11 << endl;
+ cout << setw(20) << "GC_10 " << "= " << setiosflags(ios::scientific) <<
+ setw(10) << GC_10 << endl;
+}
+
+
diff --git a/Shower/Dipole/Colorea/Parameters_sm.h b/Shower/Dipole/Colorea/Parameters_sm.h
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/Parameters_sm.h
@@ -0,0 +1,66 @@
+//==========================================================================
+// This file has been automatically generated for C++
+// MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+// By the MadGraph5_aMC@NLO Development Team
+// Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+//==========================================================================
+
+#ifndef Parameters_sm_H
+#define Parameters_sm_H
+
+#include <complex>
+
+#include "read_slha_COLOREA.h"
+using namespace std;
+
+class Parameters_sm
+{
+ public:
+
+ static Parameters_sm * getInstance();
+
+ // Define "zero"
+ double zero, ZERO;
+ // Model parameters independent of aS
+ double mdl_WH, mdl_WW, mdl_WZ, mdl_WT, mdl_ymtau, mdl_ymt, mdl_ymb, aS,
+ mdl_Gf, aEWM1, mdl_MH, mdl_MZ, mdl_MTA, mdl_MT, mdl_MB,
+ mdl_conjg__CKM3x3, mdl_CKM3x3, mdl_conjg__CKM1x1, mdl_MZ__exp__2,
+ mdl_MZ__exp__4, mdl_sqrt__2, mdl_MH__exp__2, mdl_aEW, mdl_MW,
+ mdl_sqrt__aEW, mdl_ee, mdl_MW__exp__2, mdl_sw2, mdl_cw, mdl_sqrt__sw2,
+ mdl_sw, mdl_g1, mdl_gw, mdl_vev, mdl_vev__exp__2, mdl_lam, mdl_yb,
+ mdl_yt, mdl_ytau, mdl_muH, mdl_ee__exp__2, mdl_sw__exp__2,
+ mdl_cw__exp__2;
+ std::complex<double> mdl_complexi, mdl_I1x33, mdl_I2x33, mdl_I3x33,
+ mdl_I4x33;
+ // Model parameters dependent on aS
+ double mdl_sqrt__aS, G, mdl_G__exp__2;
+ // Model couplings independent of aS
+ std::complex<double> GC_2, GC_3, GC_50, GC_51, GC_58, GC_59;
+ // Model couplings dependent on aS
+ std::complex<double> GC_12, GC_11, GC_10;
+
+ // Set parameters that are unchanged during the run
+ void setIndependentParameters(SLHAReader_COLOREA& slha);
+ // Set couplings that are unchanged during the run
+ void setIndependentCouplings();
+ // Set parameters that are changed event by event
+ void setDependentParameters();
+ // Set couplings that are changed event by event
+ void setDependentCouplings();
+
+ // Print parameters that are unchanged during the run
+ void printIndependentParameters();
+ // Print couplings that are unchanged during the run
+ void printIndependentCouplings();
+ // Print parameters that are changed event by event
+ void printDependentParameters();
+ // Print couplings that are changed event by event
+ void printDependentCouplings();
+
+
+ private:
+ static Parameters_sm * instance;
+};
+
+#endif // Parameters_sm_H
+
diff --git a/Shower/Dipole/Colorea/eeuugg.cc b/Shower/Dipole/Colorea/eeuugg.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/eeuugg.cc
@@ -0,0 +1,292 @@
+//==========================================================================
+// This file has been automatically generated for C++ Standalone by
+// MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+// By the MadGraph5_aMC@NLO Development Team
+// Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+//==========================================================================
+// and was then modified by J. Bellm.
+#include "eeuugg.h"
+#include "HelAmps_sm.h"
+#include <iostream>
+
+using namespace MG5_sm_COLOREA;
+
+//==========================================================================
+// Class member functions for calculating the matrix elements for
+// Process: e+ e- > u u~ g g WEIGHTED<=6 @1
+
+//--------------------------------------------------------------------------
+// Initialize process.
+
+vector<int> eeuugg::producePermutation(double r,vector < double * > & momenta){
+
+ setMomenta(momenta);
+ sigmaKin();
+
+ static const int res[2][5] = {
+ {5, 6, 3, 4, 0},
+ {6, 5, 3, 4, 0}};
+
+ double jampsum=0.;
+ for( int i=0;i<2;i++) jampsum+=jamp2[0][i];
+// std::cout<<"\njampsum "<<jampsum<<std::flush;
+ double cur=0.;
+
+ for(int i=0;i<2;i++){
+// std::cout<<"\njamp2[0][i] "<<jamp2[0][i]<<std::flush;
+ cur+=jamp2[0][i];
+ if( cur/jampsum > r )return std::vector<int>(res[i], res[i] + sizeof res[i] / sizeof res[i][0]);
+ }
+ std::cerr<<"\nproducePermutation: Upps.. Something went wrong!!\n"<<std::flush;
+ return std::vector<int>();
+}
+
+
+
+void eeuugg::initProc(string param_card_name)
+{
+ cout<<"\nColorea: Init process eeuugg for rearrangement (arXiv:1801.06113).";
+ // Instantiate the model class and set parameters that stay fixed during run
+ pars = Parameters_sm::getInstance();
+ SLHAReader_COLOREA slha(param_card_name);
+ pars->setIndependentParameters(slha);
+ pars->setIndependentCouplings();
+// pars->printIndependentParameters();
+// pars->printIndependentCouplings();
+ // Set external particle masses for this matrix element
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ jamp2[0] = new double[2];
+}
+
+//--------------------------------------------------------------------------
+// Evaluate |M|^2, part independent of incoming flavour.
+
+void eeuugg::sigmaKin()
+{
+ // Set the parameters which change event by event
+ pars->setDependentParameters();
+ pars->setDependentCouplings();
+ static bool firsttime = true;
+ if (firsttime)
+ {
+// pars->printDependentParameters();
+// pars->printDependentCouplings();
+ firsttime = false;
+ }
+
+ // Reset color flows
+ for(int i = 0; i < 2; i++ )
+ jamp2[0][i] = 0.;
+
+ // Local variables and constants
+ const int ncomb = 64;
+ static bool goodhel[ncomb] = {ncomb * false};
+ static int ntry = 0, sum_hel = 0, ngood = 0;
+ static int igood[ncomb];
+ static int jhel;
+ double t[nprocesses];
+ // Helicities for the process
+ static const int helicities[ncomb][nexternal] = {{-1, -1, -1, -1, -1, -1},
+ {-1, -1, -1, -1, -1, 1}, {-1, -1, -1, -1, 1, -1}, {-1, -1, -1, -1, 1, 1},
+ {-1, -1, -1, 1, -1, -1}, {-1, -1, -1, 1, -1, 1}, {-1, -1, -1, 1, 1, -1},
+ {-1, -1, -1, 1, 1, 1}, {-1, -1, 1, -1, -1, -1}, {-1, -1, 1, -1, -1, 1},
+ {-1, -1, 1, -1, 1, -1}, {-1, -1, 1, -1, 1, 1}, {-1, -1, 1, 1, -1, -1},
+ {-1, -1, 1, 1, -1, 1}, {-1, -1, 1, 1, 1, -1}, {-1, -1, 1, 1, 1, 1}, {-1,
+ 1, -1, -1, -1, -1}, {-1, 1, -1, -1, -1, 1}, {-1, 1, -1, -1, 1, -1}, {-1,
+ 1, -1, -1, 1, 1}, {-1, 1, -1, 1, -1, -1}, {-1, 1, -1, 1, -1, 1}, {-1, 1,
+ -1, 1, 1, -1}, {-1, 1, -1, 1, 1, 1}, {-1, 1, 1, -1, -1, -1}, {-1, 1, 1,
+ -1, -1, 1}, {-1, 1, 1, -1, 1, -1}, {-1, 1, 1, -1, 1, 1}, {-1, 1, 1, 1,
+ -1, -1}, {-1, 1, 1, 1, -1, 1}, {-1, 1, 1, 1, 1, -1}, {-1, 1, 1, 1, 1, 1},
+ {1, -1, -1, -1, -1, -1}, {1, -1, -1, -1, -1, 1}, {1, -1, -1, -1, 1, -1},
+ {1, -1, -1, -1, 1, 1}, {1, -1, -1, 1, -1, -1}, {1, -1, -1, 1, -1, 1}, {1,
+ -1, -1, 1, 1, -1}, {1, -1, -1, 1, 1, 1}, {1, -1, 1, -1, -1, -1}, {1, -1,
+ 1, -1, -1, 1}, {1, -1, 1, -1, 1, -1}, {1, -1, 1, -1, 1, 1}, {1, -1, 1, 1,
+ -1, -1}, {1, -1, 1, 1, -1, 1}, {1, -1, 1, 1, 1, -1}, {1, -1, 1, 1, 1, 1},
+ {1, 1, -1, -1, -1, -1}, {1, 1, -1, -1, -1, 1}, {1, 1, -1, -1, 1, -1}, {1,
+ 1, -1, -1, 1, 1}, {1, 1, -1, 1, -1, -1}, {1, 1, -1, 1, -1, 1}, {1, 1, -1,
+ 1, 1, -1}, {1, 1, -1, 1, 1, 1}, {1, 1, 1, -1, -1, -1}, {1, 1, 1, -1, -1,
+ 1}, {1, 1, 1, -1, 1, -1}, {1, 1, 1, -1, 1, 1}, {1, 1, 1, 1, -1, -1}, {1,
+ 1, 1, 1, -1, 1}, {1, 1, 1, 1, 1, -1}, {1, 1, 1, 1, 1, 1}};
+ // Denominators: spins, colors and identical particles
+ const int denominators[nprocesses] = {8};
+
+ ntry = ntry + 1;
+
+ // Reset the matrix elements
+ for(int i = 0; i < nprocesses; i++ )
+ {
+ matrix_element[i] = 0.;
+ }
+ // Define permutation
+ int perm[nexternal];
+ for(int i = 0; i < nexternal; i++ )
+ {
+ perm[i] = i;
+ }
+
+ if (sum_hel == 0 || ntry < 10)
+ {
+ // Calculate the matrix element for all helicities
+ for(int ihel = 0; ihel < ncomb; ihel++ )
+ {
+ if (goodhel[ihel] || ntry < 2)
+ {
+ calculate_wavefunctions(perm, helicities[ihel]);
+ t[0] = matrix_1_epem_uuxgg();
+
+ double tsum = 0;
+ for(int iproc = 0; iproc < nprocesses; iproc++ )
+ {
+ matrix_element[iproc] += t[iproc];
+ tsum += t[iproc];
+ }
+ // Store which helicities give non-zero result
+ if (tsum != 0. && !goodhel[ihel])
+ {
+ goodhel[ihel] = true;
+ ngood++;
+ igood[ngood] = ihel;
+ }
+ }
+ }
+ jhel = 0;
+ sum_hel = min(sum_hel, ngood);
+ }
+ else
+ {
+ // Only use the "good" helicities
+ for(int j = 0; j < sum_hel; j++ )
+ {
+ jhel++;
+ if (jhel >= ngood)
+ jhel = 0;
+ double hwgt = double(ngood)/double(sum_hel);
+ int ihel = igood[jhel];
+ calculate_wavefunctions(perm, helicities[ihel]);
+ t[0] = matrix_1_epem_uuxgg();
+
+ for(int iproc = 0; iproc < nprocesses; iproc++ )
+ {
+ matrix_element[iproc] += t[iproc] * hwgt;
+ }
+ }
+ }
+
+ for (int i = 0; i < nprocesses; i++ )
+ matrix_element[i] /= denominators[i];
+
+
+
+}
+
+
+//--------------------------------------------------------------------------
+// Evaluate |M|^2 for each subprocess
+
+void eeuugg::calculate_wavefunctions(const int perm[], const int hel[])
+{
+ // Calculate wavefunctions for all processes
+
+
+ // Calculate all wavefunctions
+ oxxxxx(p[perm[0]], mME[0], hel[0], -1, w[0]);
+ ixxxxx(p[perm[1]], mME[1], hel[1], +1, w[1]);
+ oxxxxx(p[perm[2]], mME[2], hel[2], +1, w[2]);
+ ixxxxx(p[perm[3]], mME[3], hel[3], -1, w[3]);
+ vxxxxx(p[perm[4]], mME[4], hel[4], +1, w[4]);
+ vxxxxx(p[perm[5]], mME[5], hel[5], +1, w[5]);
+ FFV1P0_3(w[1], w[0], pars->GC_3, pars->ZERO, pars->ZERO, w[6]);
+ FFV1_1(w[2], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[7]);
+ FFV1_2(w[3], w[6], pars->GC_2, pars->ZERO, pars->ZERO, w[8]);
+ FFV2_4_3(w[1], w[0], pars->GC_50, pars->GC_59, pars->mdl_MZ, pars->mdl_WZ,
+ w[9]);
+ FFV2_5_2(w[3], w[9], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[10]);
+ FFV1_2(w[3], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[11]);
+ FFV1_1(w[2], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[12]);
+ FFV1_2(w[3], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[13]);
+ FFV1_1(w[2], w[6], pars->GC_2, pars->ZERO, pars->ZERO, w[14]);
+ FFV2_5_1(w[2], w[9], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[15]);
+ VVV1P0_1(w[4], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[16]);
+
+ // Calculate all amplitudes
+ // Amplitude(s) for diagram number 0
+ FFV1_0(w[8], w[7], w[5], pars->GC_11, amp[0]);
+ FFV1_0(w[10], w[7], w[5], pars->GC_11, amp[1]);
+ FFV1_0(w[11], w[7], w[6], pars->GC_2, amp[2]);
+ FFV2_5_0(w[11], w[7], w[9], pars->GC_51, pars->GC_58, amp[3]);
+ FFV1_0(w[8], w[12], w[4], pars->GC_11, amp[4]);
+ FFV1_0(w[10], w[12], w[4], pars->GC_11, amp[5]);
+ FFV1_0(w[13], w[12], w[6], pars->GC_2, amp[6]);
+ FFV2_5_0(w[13], w[12], w[9], pars->GC_51, pars->GC_58, amp[7]);
+ FFV1_0(w[13], w[14], w[5], pars->GC_11, amp[8]);
+ FFV1_0(w[13], w[15], w[5], pars->GC_11, amp[9]);
+ FFV1_0(w[11], w[14], w[4], pars->GC_11, amp[10]);
+ FFV1_0(w[11], w[15], w[4], pars->GC_11, amp[11]);
+ FFV1_0(w[3], w[14], w[16], pars->GC_11, amp[12]);
+ FFV1_0(w[8], w[2], w[16], pars->GC_11, amp[13]);
+ FFV1_0(w[3], w[15], w[16], pars->GC_11, amp[14]);
+ FFV1_0(w[10], w[2], w[16], pars->GC_11, amp[15]);
+
+}
+double eeuugg::matrix_1_epem_uuxgg()
+{
+ //int i, j;
+ // Local variables
+ //const int ngraphs = 16;
+ //const int ncolor = 2;
+ std::complex<double> ztemp;
+ std::complex<double> jamp[2];
+ // The color matrix;
+ //static const double denom[ncolor] = {3, 3};
+ //static const double cf[ncolor][ncolor] = {{16, -2}, {-2, 16}};
+
+ // Calculate color flows
+ jamp[0] = +amp[0] + amp[1] + amp[2] + amp[3] + amp[10] + amp[11] -
+ std::complex<double> (0, 1) * amp[12] - std::complex<double> (0, 1) *
+ amp[13] - std::complex<double> (0, 1) * amp[14] - std::complex<double>
+ (0, 1) * amp[15];
+ jamp[1] = +amp[4] + amp[5] + amp[6] + amp[7] + amp[8] + amp[9] +
+ std::complex<double> (0, 1) * amp[12] + std::complex<double> (0, 1) *
+ amp[13] + std::complex<double> (0, 1) * amp[14] + std::complex<double>
+ (0, 1) * amp[15];
+
+ // Store the leading color flows for choice of color
+ for(int i = 0; i < 2; i++ )
+ jamp2[0][i] += real(jamp[i] * conj(jamp[i]));
+
+ return -1.;
+}
+
+
+double eeuugg::get_jamp2(int i)
+{
+ return jamp2[0][i];
+}
+
+int eeuugg::colorstring(int i, int j)
+{
+ static const double res[2][5] = {
+ {5, 6, 3, 4, 0},
+ {6, 5, 3, 4, 0}};
+ return res[i][j];
+}
+
+
+int eeuugg::NCol()
+{
+ const int ncolor = 2;
+ return ncolor;
+}
+
+
+
+
+
+
diff --git a/Shower/Dipole/Colorea/eeuugg.h b/Shower/Dipole/Colorea/eeuugg.h
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/eeuugg.h
@@ -0,0 +1,52 @@
+ //==========================================================================
+ // This file has been automatically generated for C++ Standalone by
+ // MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+ // By the MadGraph5_aMC@NLO Development Team
+ // Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+ //==========================================================================
+ // and was then modified by J. Bellm.
+#ifndef MG5_Sigma_sm_epem_uuxgg_H
+#define MG5_Sigma_sm_epem_uuxgg_H
+#include <complex>
+#include <vector>
+#include "Parameters_sm.h"
+using namespace std;
+class eeuugg
+{
+ public:
+ eeuugg() {
+ initProc("param_card.dat");
+ }
+ // Retrun the prefered gluon order
+ vector<int> producePermutation(double r,vector < double * > & momenta);
+ void setMass(int i,double M){mME[i]=M;}
+ private:
+ ///////// Process Dependent
+ static const int ninitial = 2;
+ static const int nexternal = 6;
+ static const int nprocesses = 1;
+ static const int nwavefuncs = 17;
+ static const int namplitudes = 16;
+ std::complex<double> w[nwavefuncs][18];
+ double matrix_1_epem_uuxgg();
+ ///////// Generic
+ double matrix_element[nprocesses];
+ std::complex<double> amp[namplitudes];
+ double * jamp2[nprocesses];
+ Parameters_sm * pars;
+ vector<double> mME;
+ vector < double * > p;
+ int id1, id2;
+ void initProc(string param_card_name);
+ void sigmaKin();
+ const vector<double> & getMasses() const {return mME;}
+ vector < double * > getMomenta(){return p;}
+ void setMomenta(vector < double * > & momenta){p = momenta;}
+ void setInitial(int inid1, int inid2){id1 = inid1; id2 = inid2;}
+ void calculate_wavefunctions(const int perm[], const int hel[]);
+ // New function
+ double get_jamp2(int i);
+ int colorstring(int i, int j);
+ int NCol();
+};
+#endif // MG5_Sigma_sm_epem_uuxgg_H
diff --git a/Shower/Dipole/Colorea/eeuuggg.cc b/Shower/Dipole/Colorea/eeuuggg.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/eeuuggg.cc
@@ -0,0 +1,532 @@
+//==========================================================================
+// This file has been automatically generated for C++ Standalone by
+// MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+// By the MadGraph5_aMC@NLO Development Team
+// Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+//==========================================================================
+// and was then modified by J. Bellm.
+#include "eeuuggg.h"
+#include "HelAmps_sm.h"
+#include <iostream>
+
+using namespace MG5_sm_COLOREA;
+
+//==========================================================================
+// Class member functions for calculating the matrix elements for
+// Process: e+ e- > u u~ g g g WEIGHTED<=7 @1
+
+//--------------------------------------------------------------------------
+// Initialize process.
+
+vector<int> eeuuggg::producePermutation(double r,vector < double * > & momenta){
+ static bool initialized=false;
+ if (!initialized){
+ initProc("param_card.dat");
+ initialized=true;
+ }
+ setMomenta(momenta);
+ sigmaKin();
+
+ static const int res[6][6] = {
+ {5, 6, 7, 3, 4, 0},
+ {5, 7, 6, 3, 4, 0},
+ {6, 5, 7, 3, 4, 0},
+ {6, 7, 5, 3, 4, 0},
+ {7, 5, 6, 3, 4, 0},
+ {7, 6, 5, 3, 4, 0}};
+
+ double jampsum=0.;
+ for( int i=0;i<6;i++) jampsum+=jamp2[0][i];
+ double cur=0.;
+ for(int i=0;i<6;i++){
+ cur+=jamp2[0][i];
+ if( cur/jampsum > r )return std::vector<int>(res[i], res[i] + sizeof res[i] / sizeof res[i][0]);
+ }
+ //std::cout<<"producePermutation: Upps.. Something went wrong!!";
+ return std::vector<int>();
+}
+
+
+void eeuuggg::initProc(string param_card_name)
+{
+ // Instantiate the model class and set parameters that stay fixed during run
+ cout<<"\nColorea: Init process eeuuggg for rearrangement (arXiv:1801.06113).";
+ pars = Parameters_sm::getInstance();
+ SLHAReader_COLOREA slha(param_card_name);
+ pars->setIndependentParameters(slha);
+ pars->setIndependentCouplings();
+// pars->printIndependentParameters();
+// pars->printIndependentCouplings();
+ // Set external particle masses for this matrix element
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ jamp2[0] = new double[6];
+}
+
+//--------------------------------------------------------------------------
+// Evaluate |M|^2, part independent of incoming flavour.
+
+void eeuuggg::sigmaKin()
+{
+ // Set the parameters which change event by event
+ pars->setDependentParameters();
+ pars->setDependentCouplings();
+ static bool firsttime = true;
+ if (firsttime)
+ {
+// pars->printDependentParameters();
+// pars->printDependentCouplings();
+ firsttime = false;
+ }
+
+ // Reset color flows
+ for(int i = 0; i < 6; i++ )
+ jamp2[0][i] = 0.;
+
+ // Local variables and constants
+ const int ncomb = 128;
+ static bool goodhel[ncomb] = {ncomb * false};
+ static int ntry = 0, sum_hel = 0, ngood = 0;
+ static int igood[ncomb];
+ static int jhel;
+// std::complex<double> * * wfs;
+ double t[nprocesses];
+ // Helicities for the process
+ static const int helicities[ncomb][nexternal] = {{-1, -1, -1, -1, -1, -1,
+ -1}, {-1, -1, -1, -1, -1, -1, 1}, {-1, -1, -1, -1, -1, 1, -1}, {-1, -1,
+ -1, -1, -1, 1, 1}, {-1, -1, -1, -1, 1, -1, -1}, {-1, -1, -1, -1, 1, -1,
+ 1}, {-1, -1, -1, -1, 1, 1, -1}, {-1, -1, -1, -1, 1, 1, 1}, {-1, -1, -1,
+ 1, -1, -1, -1}, {-1, -1, -1, 1, -1, -1, 1}, {-1, -1, -1, 1, -1, 1, -1},
+ {-1, -1, -1, 1, -1, 1, 1}, {-1, -1, -1, 1, 1, -1, -1}, {-1, -1, -1, 1, 1,
+ -1, 1}, {-1, -1, -1, 1, 1, 1, -1}, {-1, -1, -1, 1, 1, 1, 1}, {-1, -1, 1,
+ -1, -1, -1, -1}, {-1, -1, 1, -1, -1, -1, 1}, {-1, -1, 1, -1, -1, 1, -1},
+ {-1, -1, 1, -1, -1, 1, 1}, {-1, -1, 1, -1, 1, -1, -1}, {-1, -1, 1, -1, 1,
+ -1, 1}, {-1, -1, 1, -1, 1, 1, -1}, {-1, -1, 1, -1, 1, 1, 1}, {-1, -1, 1,
+ 1, -1, -1, -1}, {-1, -1, 1, 1, -1, -1, 1}, {-1, -1, 1, 1, -1, 1, -1},
+ {-1, -1, 1, 1, -1, 1, 1}, {-1, -1, 1, 1, 1, -1, -1}, {-1, -1, 1, 1, 1,
+ -1, 1}, {-1, -1, 1, 1, 1, 1, -1}, {-1, -1, 1, 1, 1, 1, 1}, {-1, 1, -1,
+ -1, -1, -1, -1}, {-1, 1, -1, -1, -1, -1, 1}, {-1, 1, -1, -1, -1, 1, -1},
+ {-1, 1, -1, -1, -1, 1, 1}, {-1, 1, -1, -1, 1, -1, -1}, {-1, 1, -1, -1, 1,
+ -1, 1}, {-1, 1, -1, -1, 1, 1, -1}, {-1, 1, -1, -1, 1, 1, 1}, {-1, 1, -1,
+ 1, -1, -1, -1}, {-1, 1, -1, 1, -1, -1, 1}, {-1, 1, -1, 1, -1, 1, -1},
+ {-1, 1, -1, 1, -1, 1, 1}, {-1, 1, -1, 1, 1, -1, -1}, {-1, 1, -1, 1, 1,
+ -1, 1}, {-1, 1, -1, 1, 1, 1, -1}, {-1, 1, -1, 1, 1, 1, 1}, {-1, 1, 1, -1,
+ -1, -1, -1}, {-1, 1, 1, -1, -1, -1, 1}, {-1, 1, 1, -1, -1, 1, -1}, {-1,
+ 1, 1, -1, -1, 1, 1}, {-1, 1, 1, -1, 1, -1, -1}, {-1, 1, 1, -1, 1, -1, 1},
+ {-1, 1, 1, -1, 1, 1, -1}, {-1, 1, 1, -1, 1, 1, 1}, {-1, 1, 1, 1, -1, -1,
+ -1}, {-1, 1, 1, 1, -1, -1, 1}, {-1, 1, 1, 1, -1, 1, -1}, {-1, 1, 1, 1,
+ -1, 1, 1}, {-1, 1, 1, 1, 1, -1, -1}, {-1, 1, 1, 1, 1, -1, 1}, {-1, 1, 1,
+ 1, 1, 1, -1}, {-1, 1, 1, 1, 1, 1, 1}, {1, -1, -1, -1, -1, -1, -1}, {1,
+ -1, -1, -1, -1, -1, 1}, {1, -1, -1, -1, -1, 1, -1}, {1, -1, -1, -1, -1,
+ 1, 1}, {1, -1, -1, -1, 1, -1, -1}, {1, -1, -1, -1, 1, -1, 1}, {1, -1, -1,
+ -1, 1, 1, -1}, {1, -1, -1, -1, 1, 1, 1}, {1, -1, -1, 1, -1, -1, -1}, {1,
+ -1, -1, 1, -1, -1, 1}, {1, -1, -1, 1, -1, 1, -1}, {1, -1, -1, 1, -1, 1,
+ 1}, {1, -1, -1, 1, 1, -1, -1}, {1, -1, -1, 1, 1, -1, 1}, {1, -1, -1, 1,
+ 1, 1, -1}, {1, -1, -1, 1, 1, 1, 1}, {1, -1, 1, -1, -1, -1, -1}, {1, -1,
+ 1, -1, -1, -1, 1}, {1, -1, 1, -1, -1, 1, -1}, {1, -1, 1, -1, -1, 1, 1},
+ {1, -1, 1, -1, 1, -1, -1}, {1, -1, 1, -1, 1, -1, 1}, {1, -1, 1, -1, 1, 1,
+ -1}, {1, -1, 1, -1, 1, 1, 1}, {1, -1, 1, 1, -1, -1, -1}, {1, -1, 1, 1,
+ -1, -1, 1}, {1, -1, 1, 1, -1, 1, -1}, {1, -1, 1, 1, -1, 1, 1}, {1, -1, 1,
+ 1, 1, -1, -1}, {1, -1, 1, 1, 1, -1, 1}, {1, -1, 1, 1, 1, 1, -1}, {1, -1,
+ 1, 1, 1, 1, 1}, {1, 1, -1, -1, -1, -1, -1}, {1, 1, -1, -1, -1, -1, 1},
+ {1, 1, -1, -1, -1, 1, -1}, {1, 1, -1, -1, -1, 1, 1}, {1, 1, -1, -1, 1,
+ -1, -1}, {1, 1, -1, -1, 1, -1, 1}, {1, 1, -1, -1, 1, 1, -1}, {1, 1, -1,
+ -1, 1, 1, 1}, {1, 1, -1, 1, -1, -1, -1}, {1, 1, -1, 1, -1, -1, 1}, {1, 1,
+ -1, 1, -1, 1, -1}, {1, 1, -1, 1, -1, 1, 1}, {1, 1, -1, 1, 1, -1, -1}, {1,
+ 1, -1, 1, 1, -1, 1}, {1, 1, -1, 1, 1, 1, -1}, {1, 1, -1, 1, 1, 1, 1}, {1,
+ 1, 1, -1, -1, -1, -1}, {1, 1, 1, -1, -1, -1, 1}, {1, 1, 1, -1, -1, 1,
+ -1}, {1, 1, 1, -1, -1, 1, 1}, {1, 1, 1, -1, 1, -1, -1}, {1, 1, 1, -1, 1,
+ -1, 1}, {1, 1, 1, -1, 1, 1, -1}, {1, 1, 1, -1, 1, 1, 1}, {1, 1, 1, 1, -1,
+ -1, -1}, {1, 1, 1, 1, -1, -1, 1}, {1, 1, 1, 1, -1, 1, -1}, {1, 1, 1, 1,
+ -1, 1, 1}, {1, 1, 1, 1, 1, -1, -1}, {1, 1, 1, 1, 1, -1, 1}, {1, 1, 1, 1,
+ 1, 1, -1}, {1, 1, 1, 1, 1, 1, 1}};
+ // Denominators: spins, colors and identical particles
+ const int denominators[nprocesses] = {24};
+
+ ntry = ntry + 1;
+
+ // Reset the matrix elements
+ for(int i = 0; i < nprocesses; i++ )
+ {
+ matrix_element[i] = 0.;
+ }
+ // Define permutation
+ int perm[nexternal];
+ for(int i = 0; i < nexternal; i++ )
+ {
+ perm[i] = i;
+ }
+
+ if (sum_hel == 0 || ntry < 10)
+ {
+ // Calculate the matrix element for all helicities
+ for(int ihel = 0; ihel < ncomb; ihel++ )
+ {
+ if (goodhel[ihel] || ntry < 2)
+ {
+ calculate_wavefunctions(perm, helicities[ihel]);
+ t[0] = matrix_1_epem_uuxggg();
+
+ double tsum = 0;
+ for(int iproc = 0; iproc < nprocesses; iproc++ )
+ {
+ matrix_element[iproc] += t[iproc];
+ tsum += t[iproc];
+ }
+ // Store which helicities give non-zero result
+ if (tsum != 0. && !goodhel[ihel])
+ {
+ goodhel[ihel] = true;
+ ngood++;
+ igood[ngood] = ihel;
+ }
+ }
+ }
+ jhel = 0;
+ sum_hel = min(sum_hel, ngood);
+ }
+ else
+ {
+ // Only use the "good" helicities
+ for(int j = 0; j < sum_hel; j++ )
+ {
+ jhel++;
+ if (jhel >= ngood)
+ jhel = 0;
+ double hwgt = double(ngood)/double(sum_hel);
+ int ihel = igood[jhel];
+ calculate_wavefunctions(perm, helicities[ihel]);
+ t[0] = matrix_1_epem_uuxggg();
+
+ for(int iproc = 0; iproc < nprocesses; iproc++ )
+ {
+ matrix_element[iproc] += t[iproc] * hwgt;
+ }
+ }
+ }
+
+ for (int i = 0; i < nprocesses; i++ )
+ matrix_element[i] /= denominators[i];
+
+
+
+}
+
+
+//==========================================================================
+// Private class member functions
+
+//--------------------------------------------------------------------------
+// Evaluate |M|^2 for each subprocess
+
+void eeuuggg::calculate_wavefunctions(const int perm[], const int hel[])
+{
+ // Calculate wavefunctions for all processes
+// int i;//, j;
+
+ // Calculate all wavefunctions
+ oxxxxx(p[perm[0]], mME[0], hel[0], -1, w[0]);
+ ixxxxx(p[perm[1]], mME[1], hel[1], +1, w[1]);
+ oxxxxx(p[perm[2]], mME[2], hel[2], +1, w[2]);
+ ixxxxx(p[perm[3]], mME[3], hel[3], -1, w[3]);
+ vxxxxx(p[perm[4]], mME[4], hel[4], +1, w[4]);
+ vxxxxx(p[perm[5]], mME[5], hel[5], +1, w[5]);
+ vxxxxx(p[perm[6]], mME[6], hel[6], +1, w[6]);
+ FFV1P0_3(w[1], w[0], pars->GC_3, pars->ZERO, pars->ZERO, w[7]);
+ FFV1_1(w[2], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[8]);
+ FFV1_2(w[3], w[7], pars->GC_2, pars->ZERO, pars->ZERO, w[9]);
+ FFV1_1(w[8], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[10]);
+ FFV1_1(w[8], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[11]);
+ FFV2_4_3(w[1], w[0], pars->GC_50, pars->GC_59, pars->mdl_MZ, pars->mdl_WZ,
+ w[12]);
+ FFV2_5_2(w[3], w[12], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[13]);
+ FFV1_2(w[3], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[14]);
+ FFV1_1(w[8], w[7], pars->GC_2, pars->ZERO, pars->ZERO, w[15]);
+ FFV1_2(w[14], w[7], pars->GC_2, pars->ZERO, pars->ZERO, w[16]);
+ FFV2_5_1(w[8], w[12], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[17]);
+ FFV2_5_2(w[14], w[12], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[18]);
+ FFV1_2(w[3], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[19]);
+ FFV1_2(w[19], w[7], pars->GC_2, pars->ZERO, pars->ZERO, w[20]);
+ FFV2_5_2(w[19], w[12], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[21]);
+ VVV1P0_1(w[5], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[22]);
+ FFV1_1(w[2], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[23]);
+ FFV1_1(w[23], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[24]);
+ FFV1_1(w[23], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[25]);
+ FFV1_2(w[3], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[26]);
+ FFV1_1(w[23], w[7], pars->GC_2, pars->ZERO, pars->ZERO, w[27]);
+ FFV1_2(w[26], w[7], pars->GC_2, pars->ZERO, pars->ZERO, w[28]);
+ FFV2_5_1(w[23], w[12], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[29]);
+ FFV2_5_2(w[26], w[12], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[30]);
+ VVV1P0_1(w[4], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[31]);
+ FFV1_1(w[2], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[32]);
+ FFV1_1(w[32], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[33]);
+ FFV1_1(w[32], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[34]);
+ FFV1_1(w[32], w[7], pars->GC_2, pars->ZERO, pars->ZERO, w[35]);
+ FFV2_5_1(w[32], w[12], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[36]);
+ VVV1P0_1(w[4], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[37]);
+ FFV1_1(w[2], w[7], pars->GC_2, pars->ZERO, pars->ZERO, w[38]);
+ FFV1_2(w[26], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[39]);
+ FFV1_2(w[26], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[40]);
+ FFV2_5_1(w[2], w[12], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[41]);
+ FFV1_2(w[14], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[42]);
+ FFV1_2(w[14], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[43]);
+ FFV1_2(w[19], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[44]);
+ FFV1_2(w[19], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[45]);
+ FFV1_2(w[3], w[37], pars->GC_11, pars->ZERO, pars->ZERO, w[46]);
+ VVV1P0_1(w[37], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[47]);
+ FFV1_1(w[2], w[37], pars->GC_11, pars->ZERO, pars->ZERO, w[48]);
+ FFV1_2(w[3], w[31], pars->GC_11, pars->ZERO, pars->ZERO, w[49]);
+ VVV1P0_1(w[31], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[50]);
+ FFV1_1(w[2], w[31], pars->GC_11, pars->ZERO, pars->ZERO, w[51]);
+ FFV1_2(w[3], w[22], pars->GC_11, pars->ZERO, pars->ZERO, w[52]);
+ VVV1P0_1(w[4], w[22], pars->GC_10, pars->ZERO, pars->ZERO, w[53]);
+ FFV1_1(w[2], w[22], pars->GC_11, pars->ZERO, pars->ZERO, w[54]);
+ VVVV1P0_1(w[4], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[55]);
+ VVVV3P0_1(w[4], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[56]);
+ VVVV4P0_1(w[4], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[57]);
+
+ // Calculate all amplitudes
+ // Amplitude(s) for diagram number 0
+ FFV1_0(w[9], w[10], w[6], pars->GC_11, amp[0]);
+ FFV1_0(w[9], w[11], w[5], pars->GC_11, amp[1]);
+ FFV1_0(w[13], w[10], w[6], pars->GC_11, amp[2]);
+ FFV1_0(w[13], w[11], w[5], pars->GC_11, amp[3]);
+ FFV1_0(w[14], w[15], w[6], pars->GC_11, amp[4]);
+ FFV1_0(w[16], w[8], w[6], pars->GC_11, amp[5]);
+ FFV1_0(w[14], w[17], w[6], pars->GC_11, amp[6]);
+ FFV1_0(w[18], w[8], w[6], pars->GC_11, amp[7]);
+ FFV1_0(w[19], w[15], w[5], pars->GC_11, amp[8]);
+ FFV1_0(w[20], w[8], w[5], pars->GC_11, amp[9]);
+ FFV1_0(w[19], w[17], w[5], pars->GC_11, amp[10]);
+ FFV1_0(w[21], w[8], w[5], pars->GC_11, amp[11]);
+ FFV1_0(w[3], w[15], w[22], pars->GC_11, amp[12]);
+ FFV1_0(w[9], w[8], w[22], pars->GC_11, amp[13]);
+ FFV1_0(w[3], w[17], w[22], pars->GC_11, amp[14]);
+ FFV1_0(w[13], w[8], w[22], pars->GC_11, amp[15]);
+ FFV1_0(w[9], w[24], w[6], pars->GC_11, amp[16]);
+ FFV1_0(w[9], w[25], w[4], pars->GC_11, amp[17]);
+ FFV1_0(w[13], w[24], w[6], pars->GC_11, amp[18]);
+ FFV1_0(w[13], w[25], w[4], pars->GC_11, amp[19]);
+ FFV1_0(w[26], w[27], w[6], pars->GC_11, amp[20]);
+ FFV1_0(w[28], w[23], w[6], pars->GC_11, amp[21]);
+ FFV1_0(w[26], w[29], w[6], pars->GC_11, amp[22]);
+ FFV1_0(w[30], w[23], w[6], pars->GC_11, amp[23]);
+ FFV1_0(w[19], w[27], w[4], pars->GC_11, amp[24]);
+ FFV1_0(w[20], w[23], w[4], pars->GC_11, amp[25]);
+ FFV1_0(w[19], w[29], w[4], pars->GC_11, amp[26]);
+ FFV1_0(w[21], w[23], w[4], pars->GC_11, amp[27]);
+ FFV1_0(w[3], w[27], w[31], pars->GC_11, amp[28]);
+ FFV1_0(w[9], w[23], w[31], pars->GC_11, amp[29]);
+ FFV1_0(w[3], w[29], w[31], pars->GC_11, amp[30]);
+ FFV1_0(w[13], w[23], w[31], pars->GC_11, amp[31]);
+ FFV1_0(w[9], w[33], w[5], pars->GC_11, amp[32]);
+ FFV1_0(w[9], w[34], w[4], pars->GC_11, amp[33]);
+ FFV1_0(w[13], w[33], w[5], pars->GC_11, amp[34]);
+ FFV1_0(w[13], w[34], w[4], pars->GC_11, amp[35]);
+ FFV1_0(w[26], w[35], w[5], pars->GC_11, amp[36]);
+ FFV1_0(w[28], w[32], w[5], pars->GC_11, amp[37]);
+ FFV1_0(w[26], w[36], w[5], pars->GC_11, amp[38]);
+ FFV1_0(w[30], w[32], w[5], pars->GC_11, amp[39]);
+ FFV1_0(w[14], w[35], w[4], pars->GC_11, amp[40]);
+ FFV1_0(w[16], w[32], w[4], pars->GC_11, amp[41]);
+ FFV1_0(w[14], w[36], w[4], pars->GC_11, amp[42]);
+ FFV1_0(w[18], w[32], w[4], pars->GC_11, amp[43]);
+ FFV1_0(w[3], w[35], w[37], pars->GC_11, amp[44]);
+ FFV1_0(w[9], w[32], w[37], pars->GC_11, amp[45]);
+ FFV1_0(w[3], w[36], w[37], pars->GC_11, amp[46]);
+ FFV1_0(w[13], w[32], w[37], pars->GC_11, amp[47]);
+ FFV1_0(w[39], w[38], w[6], pars->GC_11, amp[48]);
+ FFV1_0(w[40], w[38], w[5], pars->GC_11, amp[49]);
+ FFV1_0(w[39], w[41], w[6], pars->GC_11, amp[50]);
+ FFV1_0(w[40], w[41], w[5], pars->GC_11, amp[51]);
+ FFV1_0(w[26], w[38], w[22], pars->GC_11, amp[52]);
+ FFV1_0(w[28], w[2], w[22], pars->GC_11, amp[53]);
+ FFV1_0(w[26], w[41], w[22], pars->GC_11, amp[54]);
+ FFV1_0(w[30], w[2], w[22], pars->GC_11, amp[55]);
+ FFV1_0(w[42], w[38], w[6], pars->GC_11, amp[56]);
+ FFV1_0(w[43], w[38], w[4], pars->GC_11, amp[57]);
+ FFV1_0(w[42], w[41], w[6], pars->GC_11, amp[58]);
+ FFV1_0(w[43], w[41], w[4], pars->GC_11, amp[59]);
+ FFV1_0(w[14], w[38], w[31], pars->GC_11, amp[60]);
+ FFV1_0(w[16], w[2], w[31], pars->GC_11, amp[61]);
+ FFV1_0(w[14], w[41], w[31], pars->GC_11, amp[62]);
+ FFV1_0(w[18], w[2], w[31], pars->GC_11, amp[63]);
+ FFV1_0(w[44], w[38], w[5], pars->GC_11, amp[64]);
+ FFV1_0(w[45], w[38], w[4], pars->GC_11, amp[65]);
+ FFV1_0(w[44], w[41], w[5], pars->GC_11, amp[66]);
+ FFV1_0(w[45], w[41], w[4], pars->GC_11, amp[67]);
+ FFV1_0(w[19], w[38], w[37], pars->GC_11, amp[68]);
+ FFV1_0(w[20], w[2], w[37], pars->GC_11, amp[69]);
+ FFV1_0(w[19], w[41], w[37], pars->GC_11, amp[70]);
+ FFV1_0(w[21], w[2], w[37], pars->GC_11, amp[71]);
+ FFV1_0(w[46], w[38], w[6], pars->GC_11, amp[72]);
+ FFV1_0(w[3], w[38], w[47], pars->GC_11, amp[73]);
+ FFV1_0(w[9], w[48], w[6], pars->GC_11, amp[74]);
+ FFV1_0(w[9], w[2], w[47], pars->GC_11, amp[75]);
+ FFV1_0(w[46], w[41], w[6], pars->GC_11, amp[76]);
+ FFV1_0(w[3], w[41], w[47], pars->GC_11, amp[77]);
+ FFV1_0(w[13], w[48], w[6], pars->GC_11, amp[78]);
+ FFV1_0(w[13], w[2], w[47], pars->GC_11, amp[79]);
+ FFV1_0(w[49], w[38], w[5], pars->GC_11, amp[80]);
+ FFV1_0(w[3], w[38], w[50], pars->GC_11, amp[81]);
+ FFV1_0(w[9], w[51], w[5], pars->GC_11, amp[82]);
+ FFV1_0(w[9], w[2], w[50], pars->GC_11, amp[83]);
+ FFV1_0(w[49], w[41], w[5], pars->GC_11, amp[84]);
+ FFV1_0(w[3], w[41], w[50], pars->GC_11, amp[85]);
+ FFV1_0(w[13], w[51], w[5], pars->GC_11, amp[86]);
+ FFV1_0(w[13], w[2], w[50], pars->GC_11, amp[87]);
+ FFV1_0(w[52], w[38], w[4], pars->GC_11, amp[88]);
+ FFV1_0(w[3], w[38], w[53], pars->GC_11, amp[89]);
+ FFV1_0(w[9], w[54], w[4], pars->GC_11, amp[90]);
+ FFV1_0(w[9], w[2], w[53], pars->GC_11, amp[91]);
+ FFV1_0(w[52], w[41], w[4], pars->GC_11, amp[92]);
+ FFV1_0(w[3], w[41], w[53], pars->GC_11, amp[93]);
+ FFV1_0(w[13], w[54], w[4], pars->GC_11, amp[94]);
+ FFV1_0(w[13], w[2], w[53], pars->GC_11, amp[95]);
+ FFV1_0(w[3], w[38], w[55], pars->GC_11, amp[96]);
+ FFV1_0(w[3], w[38], w[56], pars->GC_11, amp[97]);
+ FFV1_0(w[3], w[38], w[57], pars->GC_11, amp[98]);
+ FFV1_0(w[9], w[2], w[55], pars->GC_11, amp[99]);
+ FFV1_0(w[9], w[2], w[56], pars->GC_11, amp[100]);
+ FFV1_0(w[9], w[2], w[57], pars->GC_11, amp[101]);
+ FFV1_0(w[3], w[41], w[55], pars->GC_11, amp[102]);
+ FFV1_0(w[3], w[41], w[56], pars->GC_11, amp[103]);
+ FFV1_0(w[3], w[41], w[57], pars->GC_11, amp[104]);
+ FFV1_0(w[13], w[2], w[55], pars->GC_11, amp[105]);
+ FFV1_0(w[13], w[2], w[56], pars->GC_11, amp[106]);
+ FFV1_0(w[13], w[2], w[57], pars->GC_11, amp[107]);
+
+}
+double eeuuggg::matrix_1_epem_uuxggg()
+{
+ int i;//, j;
+ // Local variables
+// const int ngraphs = 108;
+ const int ncolor = 6;
+ std::complex<double> ztemp;
+ std::complex<double> jamp[ncolor];
+ // The color matrix;
+// static const double denom[ncolor] = {9, 9, 9, 9, 9, 9};
+// static const double cf[ncolor][ncolor] = {{64, -8, -8, 1, 1, 10}, {-8, 64, 1,
+// 10, -8, 1}, {-8, 1, 64, -8, 10, 1}, {1, 10, -8, 64, 1, -8}, {1, -8, 10,
+// 1, 64, -8}, {10, 1, 1, -8, -8, 64}};
+
+ // Calculate color flows
+ jamp[0] = +amp[0] + amp[2] + amp[8] + amp[9] + amp[10] + amp[11] -
+ std::complex<double> (0, 1) * amp[12] - std::complex<double> (0, 1) *
+ amp[13] - std::complex<double> (0, 1) * amp[14] - std::complex<double>
+ (0, 1) * amp[15] + amp[65] + amp[67] - std::complex<double> (0, 1) *
+ amp[68] - std::complex<double> (0, 1) * amp[69] - std::complex<double>
+ (0, 1) * amp[70] - std::complex<double> (0, 1) * amp[71] - amp[73] -
+ std::complex<double> (0, 1) * amp[74] - amp[75] - amp[77] -
+ std::complex<double> (0, 1) * amp[78] - amp[79] - std::complex<double>
+ (0, 1) * amp[88] - amp[89] - amp[91] - std::complex<double> (0, 1) *
+ amp[92] - amp[93] - amp[95] + amp[98] - amp[96] + amp[101] - amp[99] +
+ amp[104] - amp[102] + amp[107] - amp[105];
+ jamp[1] = +amp[1] + amp[3] + amp[4] + amp[5] + amp[6] + amp[7] +
+ std::complex<double> (0, 1) * amp[12] + std::complex<double> (0, 1) *
+ amp[13] + std::complex<double> (0, 1) * amp[14] + std::complex<double>
+ (0, 1) * amp[15] + amp[57] + amp[59] - std::complex<double> (0, 1) *
+ amp[60] - std::complex<double> (0, 1) * amp[61] - std::complex<double>
+ (0, 1) * amp[62] - std::complex<double> (0, 1) * amp[63] - amp[81] -
+ std::complex<double> (0, 1) * amp[82] - amp[83] - amp[85] -
+ std::complex<double> (0, 1) * amp[86] - amp[87] + std::complex<double>
+ (0, 1) * amp[88] + amp[89] + amp[91] + std::complex<double> (0, 1) *
+ amp[92] + amp[93] + amp[95] + amp[96] + amp[97] + amp[99] + amp[100] +
+ amp[102] + amp[103] + amp[105] + amp[106];
+ jamp[2] = +amp[16] + amp[18] + amp[24] + amp[25] + amp[26] + amp[27] -
+ std::complex<double> (0, 1) * amp[28] - std::complex<double> (0, 1) *
+ amp[29] - std::complex<double> (0, 1) * amp[30] - std::complex<double>
+ (0, 1) * amp[31] + amp[64] + amp[66] + std::complex<double> (0, 1) *
+ amp[68] + std::complex<double> (0, 1) * amp[69] + std::complex<double>
+ (0, 1) * amp[70] + std::complex<double> (0, 1) * amp[71] + amp[73] +
+ std::complex<double> (0, 1) * amp[74] + amp[75] + amp[77] +
+ std::complex<double> (0, 1) * amp[78] + amp[79] - std::complex<double>
+ (0, 1) * amp[80] + amp[81] + amp[83] - std::complex<double> (0, 1) *
+ amp[84] + amp[85] + amp[87] - amp[98] - amp[97] - amp[101] - amp[100] -
+ amp[104] - amp[103] - amp[107] - amp[106];
+ jamp[3] = +amp[17] + amp[19] + amp[20] + amp[21] + amp[22] + amp[23] +
+ std::complex<double> (0, 1) * amp[28] + std::complex<double> (0, 1) *
+ amp[29] + std::complex<double> (0, 1) * amp[30] + std::complex<double>
+ (0, 1) * amp[31] + amp[49] + amp[51] - std::complex<double> (0, 1) *
+ amp[52] - std::complex<double> (0, 1) * amp[53] - std::complex<double>
+ (0, 1) * amp[54] - std::complex<double> (0, 1) * amp[55] +
+ std::complex<double> (0, 1) * amp[80] - amp[81] - amp[83] +
+ std::complex<double> (0, 1) * amp[84] - amp[85] - amp[87] + amp[89] -
+ std::complex<double> (0, 1) * amp[90] + amp[91] + amp[93] -
+ std::complex<double> (0, 1) * amp[94] + amp[95] + amp[96] + amp[97] +
+ amp[99] + amp[100] + amp[102] + amp[103] + amp[105] + amp[106];
+ jamp[4] = +amp[32] + amp[34] + amp[40] + amp[41] + amp[42] + amp[43] -
+ std::complex<double> (0, 1) * amp[44] - std::complex<double> (0, 1) *
+ amp[45] - std::complex<double> (0, 1) * amp[46] - std::complex<double>
+ (0, 1) * amp[47] + amp[56] + amp[58] + std::complex<double> (0, 1) *
+ amp[60] + std::complex<double> (0, 1) * amp[61] + std::complex<double>
+ (0, 1) * amp[62] + std::complex<double> (0, 1) * amp[63] -
+ std::complex<double> (0, 1) * amp[72] + amp[73] + amp[75] -
+ std::complex<double> (0, 1) * amp[76] + amp[77] + amp[79] + amp[81] +
+ std::complex<double> (0, 1) * amp[82] + amp[83] + amp[85] +
+ std::complex<double> (0, 1) * amp[86] + amp[87] - amp[98] - amp[97] -
+ amp[101] - amp[100] - amp[104] - amp[103] - amp[107] - amp[106];
+ jamp[5] = +amp[33] + amp[35] + amp[36] + amp[37] + amp[38] + amp[39] +
+ std::complex<double> (0, 1) * amp[44] + std::complex<double> (0, 1) *
+ amp[45] + std::complex<double> (0, 1) * amp[46] + std::complex<double>
+ (0, 1) * amp[47] + amp[48] + amp[50] + std::complex<double> (0, 1) *
+ amp[52] + std::complex<double> (0, 1) * amp[53] + std::complex<double>
+ (0, 1) * amp[54] + std::complex<double> (0, 1) * amp[55] +
+ std::complex<double> (0, 1) * amp[72] - amp[73] - amp[75] +
+ std::complex<double> (0, 1) * amp[76] - amp[77] - amp[79] - amp[89] +
+ std::complex<double> (0, 1) * amp[90] - amp[91] - amp[93] +
+ std::complex<double> (0, 1) * amp[94] - amp[95] + amp[98] - amp[96] +
+ amp[101] - amp[99] + amp[104] - amp[102] + amp[107] - amp[105];
+
+
+
+ // Store the leading color flows for choice of color
+ for(i = 0; i < ncolor; i++ )
+ jamp2[0][i] += real(jamp[i] * conj(jamp[i]));
+
+ return -1.;
+}
+
+
+double eeuuggg::get_jamp2(int i)
+{
+ return jamp2[0][i];
+}
+
+int eeuuggg::colorstring(int i, int j)
+{
+ static const double res[6][6] = {
+ {5, 6, 7, 3, 4, 0},
+ {5, 7, 6, 3, 4, 0},
+ {6, 5, 7, 3, 4, 0},
+ {6, 7, 5, 3, 4, 0},
+ {7, 5, 6, 3, 4, 0},
+ {7, 6, 5, 3, 4, 0}};
+ return res[i][j];
+}
+
+
+int eeuuggg::NCol()
+{
+ const int ncolor = 6;
+ return ncolor;
+}
+
+
+
+
+
diff --git a/Shower/Dipole/Colorea/eeuuggg.h b/Shower/Dipole/Colorea/eeuuggg.h
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/eeuuggg.h
@@ -0,0 +1,52 @@
+ //==========================================================================
+ // This file has been automatically generated for C++ Standalone by
+ // MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+ // By the MadGraph5_aMC@NLO Development Team
+ // Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+ //==========================================================================
+ // and was then modified by J. Bellm.
+#ifndef MG5_Sigma_sm_epem_uuxggg_H
+#define MG5_Sigma_sm_epem_uuxggg_H
+#include <complex>
+#include <vector>
+#include "Parameters_sm.h"
+using namespace std;
+class eeuuggg
+{
+ public:
+ eeuuggg() {
+ initProc("param_card.dat");
+ }
+ // Retrun the prefered gluon order
+ vector<int> producePermutation(double r,vector < double * > & momenta);
+ void setMass(int i,double M){mME[i]=M;}
+ private:
+ ///////// Process Dependent
+ static const int ninitial = 2;
+ static const int nexternal = 7;
+ static const int nprocesses = 1;
+ static const int nwavefuncs = 58;
+ static const int namplitudes = 108;
+ std::complex<double> w[nwavefuncs][18];
+ double matrix_1_epem_uuxggg();
+ ///////// Generic
+ double matrix_element[nprocesses];
+ std::complex<double> amp[namplitudes];
+ double * jamp2[nprocesses];
+ Parameters_sm * pars;
+ vector<double> mME;
+ vector < double * > p;
+ int id1, id2;
+ void initProc(string param_card_name);
+ void sigmaKin();
+ const vector<double> & getMasses() const {return mME;}
+ vector < double * > getMomenta(){return p;}
+ void setMomenta(vector < double * > & momenta){p = momenta;}
+ void setInitial(int inid1, int inid2){id1 = inid1; id2 = inid2;}
+ void calculate_wavefunctions(const int perm[], const int hel[]);
+ // New function
+ double get_jamp2(int i);
+ int colorstring(int i, int j);
+ int NCol();
+};
+#endif // MG5_Sigma_sm_epem_uuxggg_H
diff --git a/Shower/Dipole/Colorea/eeuugggg.cc b/Shower/Dipole/Colorea/eeuugggg.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/eeuugggg.cc
@@ -0,0 +1,3120 @@
+//==========================================================================
+// This file has been automatically generated for C++ Standalone by
+// MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+// By the MadGraph5_aMC@NLO Development Team
+// Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+//==========================================================================
+// and was then modified by J. Bellm.
+#include "eeuugggg.h"
+#include "HelAmps_sm.h"
+#include <iostream>
+
+using namespace MG5_sm_COLOREA;
+
+//==========================================================================
+// Class member functions for calculating the matrix elements for
+// Process: e+ e- > u u~ g g g g WEIGHTED<=8 @1
+
+//--------------------------------------------------------------------------
+// Initialize process.
+
+vector<int> eeuugggg::producePermutation(double r,vector < double * > & momenta){
+ static bool initialized=false;
+ if (!initialized){
+ initProc("param_card.dat");
+ initialized=true;
+ }
+ setMomenta(momenta);
+ sigmaKin();
+
+
+ static const int res[24][8] = {
+ {5, 6, 7, 8, 3, 4, 0, 0},
+ {5, 6, 8, 7, 3, 4, 0, 0},
+ {5, 7, 6, 8, 3, 4, 0, 0},
+ {5, 7, 8, 6, 3, 4, 0, 0},
+ {5, 8, 6, 7, 3, 4, 0, 0},
+ {5, 8, 7, 6, 3, 4, 0, 0},
+ {6, 5, 7, 8, 3, 4, 0, 0},
+ {6, 5, 8, 7, 3, 4, 0, 0},
+ {6, 7, 5, 8, 3, 4, 0, 0},
+ {6, 7, 8, 5, 3, 4, 0, 0},
+ {6, 8, 5, 7, 3, 4, 0, 0},
+ {6, 8, 7, 5, 3, 4, 0, 0},
+ {7, 5, 6, 8, 3, 4, 0, 0},
+ {7, 5, 8, 6, 3, 4, 0, 0},
+ {7, 6, 5, 8, 3, 4, 0, 0},
+ {7, 6, 8, 5, 3, 4, 0, 0},
+ {7, 8, 5, 6, 3, 4, 0, 0},
+ {7, 8, 6, 5, 3, 4, 0, 0},
+ {8, 5, 6, 7, 3, 4, 0, 0},
+ {8, 5, 7, 6, 3, 4, 0, 0},
+ {8, 6, 5, 7, 3, 4, 0, 0},
+ {8, 6, 7, 5, 3, 4, 0, 0},
+ {8, 7, 5, 6, 3, 4, 0, 0},
+ {8, 7, 6, 5, 3, 4, 0, 0}};
+
+ double jampsum=0.;
+ for( int i=0;i<24;i++) jampsum+=jamp2[0][i];
+ double cur=0.;
+ for(int i=0;i<24;i++){
+ cur+=jamp2[0][i];
+ if( cur/jampsum > r )return std::vector<int>(res[i], res[i] + sizeof res[i] / sizeof res[i][0]);
+ }
+ //std::cout<<"producePermutation: Upps.. Something went wrong!!";
+ return std::vector<int>();
+}
+
+
+
+void eeuugggg::initProc(string param_card_name)
+{
+ cout<<"\nColorea: Init process eeuugggg for rearrangement (arXiv:1801.06113).";
+ // Instantiate the model class and set parameters that stay fixed during run
+ pars = Parameters_sm::getInstance();
+ SLHAReader_COLOREA slha(param_card_name);
+ pars->setIndependentParameters(slha);
+ pars->setIndependentCouplings();
+// pars->printIndependentParameters();
+// pars->printIndependentCouplings();
+ // Set external particle masses for this matrix element
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ mME.push_back(pars->ZERO);
+ jamp2[0] = new double[24];
+}
+
+//--------------------------------------------------------------------------
+// Evaluate |M|^2, part independent of incoming flavour.
+
+void eeuugggg::sigmaKin()
+{
+ // Set the parameters which change event by event
+ pars->setDependentParameters();
+ pars->setDependentCouplings();
+ static bool firsttime = true;
+ if (firsttime)
+ {
+// pars->printDependentParameters();
+// pars->printDependentCouplings();
+ firsttime = false;
+ }
+
+ // Reset color flows
+ for(int i = 0; i < 24; i++ )
+ jamp2[0][i] = 0.;
+
+ // Local variables and constants
+ const int ncomb = 256;
+ static bool goodhel[ncomb] = {ncomb * false};
+ static int ntry = 0, sum_hel = 0, ngood = 0;
+ static int igood[ncomb];
+ static int jhel;
+// std::complex<double> * * wfs;
+ double t[nprocesses];
+ // Helicities for the process
+ static const int helicities[ncomb][nexternal] = {{-1, -1, -1, -1, -1, -1, -1,
+ -1}, {-1, -1, -1, -1, -1, -1, -1, 1}, {-1, -1, -1, -1, -1, -1, 1, -1},
+ {-1, -1, -1, -1, -1, -1, 1, 1}, {-1, -1, -1, -1, -1, 1, -1, -1}, {-1, -1,
+ -1, -1, -1, 1, -1, 1}, {-1, -1, -1, -1, -1, 1, 1, -1}, {-1, -1, -1, -1,
+ -1, 1, 1, 1}, {-1, -1, -1, -1, 1, -1, -1, -1}, {-1, -1, -1, -1, 1, -1,
+ -1, 1}, {-1, -1, -1, -1, 1, -1, 1, -1}, {-1, -1, -1, -1, 1, -1, 1, 1},
+ {-1, -1, -1, -1, 1, 1, -1, -1}, {-1, -1, -1, -1, 1, 1, -1, 1}, {-1, -1,
+ -1, -1, 1, 1, 1, -1}, {-1, -1, -1, -1, 1, 1, 1, 1}, {-1, -1, -1, 1, -1,
+ -1, -1, -1}, {-1, -1, -1, 1, -1, -1, -1, 1}, {-1, -1, -1, 1, -1, -1, 1,
+ -1}, {-1, -1, -1, 1, -1, -1, 1, 1}, {-1, -1, -1, 1, -1, 1, -1, -1}, {-1,
+ -1, -1, 1, -1, 1, -1, 1}, {-1, -1, -1, 1, -1, 1, 1, -1}, {-1, -1, -1, 1,
+ -1, 1, 1, 1}, {-1, -1, -1, 1, 1, -1, -1, -1}, {-1, -1, -1, 1, 1, -1, -1,
+ 1}, {-1, -1, -1, 1, 1, -1, 1, -1}, {-1, -1, -1, 1, 1, -1, 1, 1}, {-1, -1,
+ -1, 1, 1, 1, -1, -1}, {-1, -1, -1, 1, 1, 1, -1, 1}, {-1, -1, -1, 1, 1, 1,
+ 1, -1}, {-1, -1, -1, 1, 1, 1, 1, 1}, {-1, -1, 1, -1, -1, -1, -1, -1},
+ {-1, -1, 1, -1, -1, -1, -1, 1}, {-1, -1, 1, -1, -1, -1, 1, -1}, {-1, -1,
+ 1, -1, -1, -1, 1, 1}, {-1, -1, 1, -1, -1, 1, -1, -1}, {-1, -1, 1, -1, -1,
+ 1, -1, 1}, {-1, -1, 1, -1, -1, 1, 1, -1}, {-1, -1, 1, -1, -1, 1, 1, 1},
+ {-1, -1, 1, -1, 1, -1, -1, -1}, {-1, -1, 1, -1, 1, -1, -1, 1}, {-1, -1,
+ 1, -1, 1, -1, 1, -1}, {-1, -1, 1, -1, 1, -1, 1, 1}, {-1, -1, 1, -1, 1, 1,
+ -1, -1}, {-1, -1, 1, -1, 1, 1, -1, 1}, {-1, -1, 1, -1, 1, 1, 1, -1}, {-1,
+ -1, 1, -1, 1, 1, 1, 1}, {-1, -1, 1, 1, -1, -1, -1, -1}, {-1, -1, 1, 1,
+ -1, -1, -1, 1}, {-1, -1, 1, 1, -1, -1, 1, -1}, {-1, -1, 1, 1, -1, -1, 1,
+ 1}, {-1, -1, 1, 1, -1, 1, -1, -1}, {-1, -1, 1, 1, -1, 1, -1, 1}, {-1, -1,
+ 1, 1, -1, 1, 1, -1}, {-1, -1, 1, 1, -1, 1, 1, 1}, {-1, -1, 1, 1, 1, -1,
+ -1, -1}, {-1, -1, 1, 1, 1, -1, -1, 1}, {-1, -1, 1, 1, 1, -1, 1, -1}, {-1,
+ -1, 1, 1, 1, -1, 1, 1}, {-1, -1, 1, 1, 1, 1, -1, -1}, {-1, -1, 1, 1, 1,
+ 1, -1, 1}, {-1, -1, 1, 1, 1, 1, 1, -1}, {-1, -1, 1, 1, 1, 1, 1, 1}, {-1,
+ 1, -1, -1, -1, -1, -1, -1}, {-1, 1, -1, -1, -1, -1, -1, 1}, {-1, 1, -1,
+ -1, -1, -1, 1, -1}, {-1, 1, -1, -1, -1, -1, 1, 1}, {-1, 1, -1, -1, -1, 1,
+ -1, -1}, {-1, 1, -1, -1, -1, 1, -1, 1}, {-1, 1, -1, -1, -1, 1, 1, -1},
+ {-1, 1, -1, -1, -1, 1, 1, 1}, {-1, 1, -1, -1, 1, -1, -1, -1}, {-1, 1, -1,
+ -1, 1, -1, -1, 1}, {-1, 1, -1, -1, 1, -1, 1, -1}, {-1, 1, -1, -1, 1, -1,
+ 1, 1}, {-1, 1, -1, -1, 1, 1, -1, -1}, {-1, 1, -1, -1, 1, 1, -1, 1}, {-1,
+ 1, -1, -1, 1, 1, 1, -1}, {-1, 1, -1, -1, 1, 1, 1, 1}, {-1, 1, -1, 1, -1,
+ -1, -1, -1}, {-1, 1, -1, 1, -1, -1, -1, 1}, {-1, 1, -1, 1, -1, -1, 1,
+ -1}, {-1, 1, -1, 1, -1, -1, 1, 1}, {-1, 1, -1, 1, -1, 1, -1, -1}, {-1, 1,
+ -1, 1, -1, 1, -1, 1}, {-1, 1, -1, 1, -1, 1, 1, -1}, {-1, 1, -1, 1, -1, 1,
+ 1, 1}, {-1, 1, -1, 1, 1, -1, -1, -1}, {-1, 1, -1, 1, 1, -1, -1, 1}, {-1,
+ 1, -1, 1, 1, -1, 1, -1}, {-1, 1, -1, 1, 1, -1, 1, 1}, {-1, 1, -1, 1, 1,
+ 1, -1, -1}, {-1, 1, -1, 1, 1, 1, -1, 1}, {-1, 1, -1, 1, 1, 1, 1, -1},
+ {-1, 1, -1, 1, 1, 1, 1, 1}, {-1, 1, 1, -1, -1, -1, -1, -1}, {-1, 1, 1,
+ -1, -1, -1, -1, 1}, {-1, 1, 1, -1, -1, -1, 1, -1}, {-1, 1, 1, -1, -1, -1,
+ 1, 1}, {-1, 1, 1, -1, -1, 1, -1, -1}, {-1, 1, 1, -1, -1, 1, -1, 1}, {-1,
+ 1, 1, -1, -1, 1, 1, -1}, {-1, 1, 1, -1, -1, 1, 1, 1}, {-1, 1, 1, -1, 1,
+ -1, -1, -1}, {-1, 1, 1, -1, 1, -1, -1, 1}, {-1, 1, 1, -1, 1, -1, 1, -1},
+ {-1, 1, 1, -1, 1, -1, 1, 1}, {-1, 1, 1, -1, 1, 1, -1, -1}, {-1, 1, 1, -1,
+ 1, 1, -1, 1}, {-1, 1, 1, -1, 1, 1, 1, -1}, {-1, 1, 1, -1, 1, 1, 1, 1},
+ {-1, 1, 1, 1, -1, -1, -1, -1}, {-1, 1, 1, 1, -1, -1, -1, 1}, {-1, 1, 1,
+ 1, -1, -1, 1, -1}, {-1, 1, 1, 1, -1, -1, 1, 1}, {-1, 1, 1, 1, -1, 1, -1,
+ -1}, {-1, 1, 1, 1, -1, 1, -1, 1}, {-1, 1, 1, 1, -1, 1, 1, -1}, {-1, 1, 1,
+ 1, -1, 1, 1, 1}, {-1, 1, 1, 1, 1, -1, -1, -1}, {-1, 1, 1, 1, 1, -1, -1,
+ 1}, {-1, 1, 1, 1, 1, -1, 1, -1}, {-1, 1, 1, 1, 1, -1, 1, 1}, {-1, 1, 1,
+ 1, 1, 1, -1, -1}, {-1, 1, 1, 1, 1, 1, -1, 1}, {-1, 1, 1, 1, 1, 1, 1, -1},
+ {-1, 1, 1, 1, 1, 1, 1, 1}, {1, -1, -1, -1, -1, -1, -1, -1}, {1, -1, -1,
+ -1, -1, -1, -1, 1}, {1, -1, -1, -1, -1, -1, 1, -1}, {1, -1, -1, -1, -1,
+ -1, 1, 1}, {1, -1, -1, -1, -1, 1, -1, -1}, {1, -1, -1, -1, -1, 1, -1, 1},
+ {1, -1, -1, -1, -1, 1, 1, -1}, {1, -1, -1, -1, -1, 1, 1, 1}, {1, -1, -1,
+ -1, 1, -1, -1, -1}, {1, -1, -1, -1, 1, -1, -1, 1}, {1, -1, -1, -1, 1, -1,
+ 1, -1}, {1, -1, -1, -1, 1, -1, 1, 1}, {1, -1, -1, -1, 1, 1, -1, -1}, {1,
+ -1, -1, -1, 1, 1, -1, 1}, {1, -1, -1, -1, 1, 1, 1, -1}, {1, -1, -1, -1,
+ 1, 1, 1, 1}, {1, -1, -1, 1, -1, -1, -1, -1}, {1, -1, -1, 1, -1, -1, -1,
+ 1}, {1, -1, -1, 1, -1, -1, 1, -1}, {1, -1, -1, 1, -1, -1, 1, 1}, {1, -1,
+ -1, 1, -1, 1, -1, -1}, {1, -1, -1, 1, -1, 1, -1, 1}, {1, -1, -1, 1, -1,
+ 1, 1, -1}, {1, -1, -1, 1, -1, 1, 1, 1}, {1, -1, -1, 1, 1, -1, -1, -1},
+ {1, -1, -1, 1, 1, -1, -1, 1}, {1, -1, -1, 1, 1, -1, 1, -1}, {1, -1, -1,
+ 1, 1, -1, 1, 1}, {1, -1, -1, 1, 1, 1, -1, -1}, {1, -1, -1, 1, 1, 1, -1,
+ 1}, {1, -1, -1, 1, 1, 1, 1, -1}, {1, -1, -1, 1, 1, 1, 1, 1}, {1, -1, 1,
+ -1, -1, -1, -1, -1}, {1, -1, 1, -1, -1, -1, -1, 1}, {1, -1, 1, -1, -1,
+ -1, 1, -1}, {1, -1, 1, -1, -1, -1, 1, 1}, {1, -1, 1, -1, -1, 1, -1, -1},
+ {1, -1, 1, -1, -1, 1, -1, 1}, {1, -1, 1, -1, -1, 1, 1, -1}, {1, -1, 1,
+ -1, -1, 1, 1, 1}, {1, -1, 1, -1, 1, -1, -1, -1}, {1, -1, 1, -1, 1, -1,
+ -1, 1}, {1, -1, 1, -1, 1, -1, 1, -1}, {1, -1, 1, -1, 1, -1, 1, 1}, {1,
+ -1, 1, -1, 1, 1, -1, -1}, {1, -1, 1, -1, 1, 1, -1, 1}, {1, -1, 1, -1, 1,
+ 1, 1, -1}, {1, -1, 1, -1, 1, 1, 1, 1}, {1, -1, 1, 1, -1, -1, -1, -1}, {1,
+ -1, 1, 1, -1, -1, -1, 1}, {1, -1, 1, 1, -1, -1, 1, -1}, {1, -1, 1, 1, -1,
+ -1, 1, 1}, {1, -1, 1, 1, -1, 1, -1, -1}, {1, -1, 1, 1, -1, 1, -1, 1}, {1,
+ -1, 1, 1, -1, 1, 1, -1}, {1, -1, 1, 1, -1, 1, 1, 1}, {1, -1, 1, 1, 1, -1,
+ -1, -1}, {1, -1, 1, 1, 1, -1, -1, 1}, {1, -1, 1, 1, 1, -1, 1, -1}, {1,
+ -1, 1, 1, 1, -1, 1, 1}, {1, -1, 1, 1, 1, 1, -1, -1}, {1, -1, 1, 1, 1, 1,
+ -1, 1}, {1, -1, 1, 1, 1, 1, 1, -1}, {1, -1, 1, 1, 1, 1, 1, 1}, {1, 1, -1,
+ -1, -1, -1, -1, -1}, {1, 1, -1, -1, -1, -1, -1, 1}, {1, 1, -1, -1, -1,
+ -1, 1, -1}, {1, 1, -1, -1, -1, -1, 1, 1}, {1, 1, -1, -1, -1, 1, -1, -1},
+ {1, 1, -1, -1, -1, 1, -1, 1}, {1, 1, -1, -1, -1, 1, 1, -1}, {1, 1, -1,
+ -1, -1, 1, 1, 1}, {1, 1, -1, -1, 1, -1, -1, -1}, {1, 1, -1, -1, 1, -1,
+ -1, 1}, {1, 1, -1, -1, 1, -1, 1, -1}, {1, 1, -1, -1, 1, -1, 1, 1}, {1, 1,
+ -1, -1, 1, 1, -1, -1}, {1, 1, -1, -1, 1, 1, -1, 1}, {1, 1, -1, -1, 1, 1,
+ 1, -1}, {1, 1, -1, -1, 1, 1, 1, 1}, {1, 1, -1, 1, -1, -1, -1, -1}, {1, 1,
+ -1, 1, -1, -1, -1, 1}, {1, 1, -1, 1, -1, -1, 1, -1}, {1, 1, -1, 1, -1,
+ -1, 1, 1}, {1, 1, -1, 1, -1, 1, -1, -1}, {1, 1, -1, 1, -1, 1, -1, 1}, {1,
+ 1, -1, 1, -1, 1, 1, -1}, {1, 1, -1, 1, -1, 1, 1, 1}, {1, 1, -1, 1, 1, -1,
+ -1, -1}, {1, 1, -1, 1, 1, -1, -1, 1}, {1, 1, -1, 1, 1, -1, 1, -1}, {1, 1,
+ -1, 1, 1, -1, 1, 1}, {1, 1, -1, 1, 1, 1, -1, -1}, {1, 1, -1, 1, 1, 1, -1,
+ 1}, {1, 1, -1, 1, 1, 1, 1, -1}, {1, 1, -1, 1, 1, 1, 1, 1}, {1, 1, 1, -1,
+ -1, -1, -1, -1}, {1, 1, 1, -1, -1, -1, -1, 1}, {1, 1, 1, -1, -1, -1, 1,
+ -1}, {1, 1, 1, -1, -1, -1, 1, 1}, {1, 1, 1, -1, -1, 1, -1, -1}, {1, 1, 1,
+ -1, -1, 1, -1, 1}, {1, 1, 1, -1, -1, 1, 1, -1}, {1, 1, 1, -1, -1, 1, 1,
+ 1}, {1, 1, 1, -1, 1, -1, -1, -1}, {1, 1, 1, -1, 1, -1, -1, 1}, {1, 1, 1,
+ -1, 1, -1, 1, -1}, {1, 1, 1, -1, 1, -1, 1, 1}, {1, 1, 1, -1, 1, 1, -1,
+ -1}, {1, 1, 1, -1, 1, 1, -1, 1}, {1, 1, 1, -1, 1, 1, 1, -1}, {1, 1, 1,
+ -1, 1, 1, 1, 1}, {1, 1, 1, 1, -1, -1, -1, -1}, {1, 1, 1, 1, -1, -1, -1,
+ 1}, {1, 1, 1, 1, -1, -1, 1, -1}, {1, 1, 1, 1, -1, -1, 1, 1}, {1, 1, 1, 1,
+ -1, 1, -1, -1}, {1, 1, 1, 1, -1, 1, -1, 1}, {1, 1, 1, 1, -1, 1, 1, -1},
+ {1, 1, 1, 1, -1, 1, 1, 1}, {1, 1, 1, 1, 1, -1, -1, -1}, {1, 1, 1, 1, 1,
+ -1, -1, 1}, {1, 1, 1, 1, 1, -1, 1, -1}, {1, 1, 1, 1, 1, -1, 1, 1}, {1, 1,
+ 1, 1, 1, 1, -1, -1}, {1, 1, 1, 1, 1, 1, -1, 1}, {1, 1, 1, 1, 1, 1, 1,
+ -1}, {1, 1, 1, 1, 1, 1, 1, 1}};
+ // Denominators: spins, colors and identical particles
+ const int denominators[nprocesses] = {96};
+
+ ntry = ntry + 1;
+
+ // Reset the matrix elements
+ for(int i = 0; i < nprocesses; i++ )
+ {
+ matrix_element[i] = 0.;
+ }
+ // Define permutation
+ int perm[nexternal];
+ for(int i = 0; i < nexternal; i++ )
+ {
+ perm[i] = i;
+ }
+
+ if (sum_hel == 0 || ntry < 10)
+ {
+ // Calculate the matrix element for all helicities
+ for(int ihel = 0; ihel < ncomb; ihel++ )
+ {
+ if (goodhel[ihel] || ntry < 2)
+ {
+ calculate_wavefunctions(perm, helicities[ihel]);
+ t[0] = matrix_1_epem_uuxgggg();
+
+ double tsum = 0;
+ for(int iproc = 0; iproc < nprocesses; iproc++ )
+ {
+ matrix_element[iproc] += t[iproc];
+ tsum += t[iproc];
+ }
+ // Store which helicities give non-zero result
+ if (tsum != 0. && !goodhel[ihel])
+ {
+ goodhel[ihel] = true;
+ ngood++;
+ igood[ngood] = ihel;
+ }
+ }
+ }
+ jhel = 0;
+ sum_hel = min(sum_hel, ngood);
+ }
+ else
+ {
+ // Only use the "good" helicities
+ for(int j = 0; j < sum_hel; j++ )
+ {
+ jhel++;
+ if (jhel >= ngood)
+ jhel = 0;
+ double hwgt = double(ngood)/double(sum_hel);
+ int ihel = igood[jhel];
+ calculate_wavefunctions(perm, helicities[ihel]);
+ t[0] = matrix_1_epem_uuxgggg();
+
+ for(int iproc = 0; iproc < nprocesses; iproc++ )
+ {
+ matrix_element[iproc] += t[iproc] * hwgt;
+ }
+ }
+ }
+
+ for (int i = 0; i < nprocesses; i++ )
+ matrix_element[i] /= denominators[i];
+
+
+
+}
+
+
+//--------------------------------------------------------------------------
+// Evaluate |M|^2 for each subprocess
+
+void eeuugggg::calculate_wavefunctions(const int perm[], const int hel[])
+{
+
+ // Calculate all wavefunctions
+ oxxxxx(p[perm[0]], mME[0], hel[0], -1, w[0]);
+ ixxxxx(p[perm[1]], mME[1], hel[1], +1, w[1]);
+ oxxxxx(p[perm[2]], mME[2], hel[2], +1, w[2]);
+ ixxxxx(p[perm[3]], mME[3], hel[3], -1, w[3]);
+ vxxxxx(p[perm[4]], mME[4], hel[4], +1, w[4]);
+ vxxxxx(p[perm[5]], mME[5], hel[5], +1, w[5]);
+ vxxxxx(p[perm[6]], mME[6], hel[6], +1, w[6]);
+ vxxxxx(p[perm[7]], mME[7], hel[7], +1, w[7]);
+ FFV1P0_3(w[1], w[0], pars->GC_3, pars->ZERO, pars->ZERO, w[8]);
+ FFV1_1(w[2], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[9]);
+ FFV1_2(w[3], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[10]);
+ FFV1_1(w[9], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[11]);
+ FFV1_2(w[10], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[12]);
+ FFV1_2(w[10], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[13]);
+ FFV1_1(w[9], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[14]);
+ FFV1_2(w[10], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[15]);
+ FFV1_1(w[9], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[16]);
+ FFV2_4_3(w[1], w[0], pars->GC_50, pars->GC_59, pars->mdl_MZ, pars->mdl_WZ,
+ w[17]);
+ FFV2_5_2(w[3], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[18]);
+ FFV1_2(w[18], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[19]);
+ FFV1_2(w[18], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[20]);
+ FFV1_2(w[18], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[21]);
+ FFV1_2(w[3], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[22]);
+ FFV1_1(w[9], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[23]);
+ FFV1_2(w[22], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[24]);
+ FFV1_2(w[22], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[25]);
+ FFV1_2(w[22], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[26]);
+ FFV2_5_1(w[9], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[27]);
+ FFV2_5_2(w[22], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[28]);
+ VVV1P0_1(w[6], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[29]);
+ FFV1_2(w[3], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[30]);
+ FFV1_2(w[30], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[31]);
+ FFV1_2(w[30], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[32]);
+ FFV1_2(w[30], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[33]);
+ FFV2_5_2(w[30], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[34]);
+ VVV1P0_1(w[5], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[35]);
+ FFV1_2(w[3], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[36]);
+ FFV1_2(w[36], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[37]);
+ FFV1_2(w[36], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[38]);
+ FFV1_2(w[36], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[39]);
+ FFV2_5_2(w[36], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[40]);
+ VVV1P0_1(w[5], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[41]);
+ FFV1_2(w[3], w[41], pars->GC_11, pars->ZERO, pars->ZERO, w[42]);
+ VVV1P0_1(w[41], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[43]);
+ FFV1_1(w[9], w[41], pars->GC_11, pars->ZERO, pars->ZERO, w[44]);
+ FFV1_2(w[3], w[35], pars->GC_11, pars->ZERO, pars->ZERO, w[45]);
+ VVV1P0_1(w[35], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[46]);
+ FFV1_1(w[9], w[35], pars->GC_11, pars->ZERO, pars->ZERO, w[47]);
+ FFV1_2(w[3], w[29], pars->GC_11, pars->ZERO, pars->ZERO, w[48]);
+ VVV1P0_1(w[5], w[29], pars->GC_10, pars->ZERO, pars->ZERO, w[49]);
+ FFV1_1(w[9], w[29], pars->GC_11, pars->ZERO, pars->ZERO, w[50]);
+ VVVV1P0_1(w[5], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[51]);
+ VVVV3P0_1(w[5], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[52]);
+ VVVV4P0_1(w[5], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[53]);
+ FFV1_1(w[2], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[54]);
+ FFV1_1(w[54], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[55]);
+ FFV1_1(w[54], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[56]);
+ FFV1_2(w[10], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[57]);
+ FFV1_1(w[54], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[58]);
+ FFV1_2(w[18], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[59]);
+ FFV1_2(w[3], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[60]);
+ FFV1_1(w[54], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[61]);
+ FFV1_2(w[60], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[62]);
+ FFV1_2(w[60], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[63]);
+ FFV1_2(w[60], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[64]);
+ FFV2_5_1(w[54], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[65]);
+ FFV2_5_2(w[60], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[66]);
+ FFV1_2(w[30], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[67]);
+ VVV1P0_1(w[4], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[68]);
+ FFV1_2(w[36], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[69]);
+ VVV1P0_1(w[4], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[70]);
+ FFV1_2(w[3], w[70], pars->GC_11, pars->ZERO, pars->ZERO, w[71]);
+ VVV1P0_1(w[70], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[72]);
+ FFV1_1(w[54], w[70], pars->GC_11, pars->ZERO, pars->ZERO, w[73]);
+ FFV1_2(w[3], w[68], pars->GC_11, pars->ZERO, pars->ZERO, w[74]);
+ VVV1P0_1(w[68], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[75]);
+ FFV1_1(w[54], w[68], pars->GC_11, pars->ZERO, pars->ZERO, w[76]);
+ VVV1P0_1(w[4], w[29], pars->GC_10, pars->ZERO, pars->ZERO, w[77]);
+ FFV1_1(w[54], w[29], pars->GC_11, pars->ZERO, pars->ZERO, w[78]);
+ VVVV1P0_1(w[4], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[79]);
+ VVVV3P0_1(w[4], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[80]);
+ VVVV4P0_1(w[4], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[81]);
+ FFV1_1(w[2], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[82]);
+ FFV1_1(w[82], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[83]);
+ FFV1_1(w[82], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[84]);
+ FFV1_1(w[82], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[85]);
+ FFV1_1(w[82], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[86]);
+ FFV1_2(w[60], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[87]);
+ FFV2_5_1(w[82], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[88]);
+ FFV1_2(w[22], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[89]);
+ VVV1P0_1(w[4], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[90]);
+ FFV1_2(w[3], w[90], pars->GC_11, pars->ZERO, pars->ZERO, w[91]);
+ VVV1P0_1(w[90], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[92]);
+ FFV1_1(w[82], w[90], pars->GC_11, pars->ZERO, pars->ZERO, w[93]);
+ VVV1P0_1(w[68], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[94]);
+ FFV1_1(w[82], w[68], pars->GC_11, pars->ZERO, pars->ZERO, w[95]);
+ VVV1P0_1(w[4], w[35], pars->GC_10, pars->ZERO, pars->ZERO, w[96]);
+ FFV1_1(w[82], w[35], pars->GC_11, pars->ZERO, pars->ZERO, w[97]);
+ VVVV1P0_1(w[4], w[5], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[98]);
+ VVVV3P0_1(w[4], w[5], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[99]);
+ VVVV4P0_1(w[4], w[5], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[100]);
+ FFV1_1(w[2], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[101]);
+ FFV1_1(w[101], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[102]);
+ FFV1_1(w[101], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[103]);
+ FFV1_1(w[101], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[104]);
+ FFV1_1(w[101], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[105]);
+ FFV2_5_1(w[101], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[106]);
+ VVV1P0_1(w[90], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[107]);
+ FFV1_1(w[101], w[90], pars->GC_11, pars->ZERO, pars->ZERO, w[108]);
+ VVV1P0_1(w[70], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[109]);
+ FFV1_1(w[101], w[70], pars->GC_11, pars->ZERO, pars->ZERO, w[110]);
+ VVV1P0_1(w[4], w[41], pars->GC_10, pars->ZERO, pars->ZERO, w[111]);
+ FFV1_1(w[101], w[41], pars->GC_11, pars->ZERO, pars->ZERO, w[112]);
+ VVVV1P0_1(w[4], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[113]);
+ VVVV3P0_1(w[4], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[114]);
+ VVVV4P0_1(w[4], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[115]);
+ FFV1_1(w[2], w[8], pars->GC_2, pars->ZERO, pars->ZERO, w[116]);
+ FFV1_1(w[116], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[117]);
+ FFV1_1(w[116], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[118]);
+ FFV1_1(w[116], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[119]);
+ FFV2_5_1(w[2], w[17], pars->GC_51, pars->GC_58, pars->ZERO, pars->ZERO,
+ w[120]);
+ FFV1_1(w[120], w[6], pars->GC_11, pars->ZERO, pars->ZERO, w[121]);
+ FFV1_1(w[120], w[7], pars->GC_11, pars->ZERO, pars->ZERO, w[122]);
+ FFV1_1(w[120], w[5], pars->GC_11, pars->ZERO, pars->ZERO, w[123]);
+ FFV1_2(w[60], w[41], pars->GC_11, pars->ZERO, pars->ZERO, w[124]);
+ FFV1_1(w[2], w[41], pars->GC_11, pars->ZERO, pars->ZERO, w[125]);
+ FFV1_2(w[60], w[35], pars->GC_11, pars->ZERO, pars->ZERO, w[126]);
+ FFV1_1(w[2], w[35], pars->GC_11, pars->ZERO, pars->ZERO, w[127]);
+ FFV1_2(w[60], w[29], pars->GC_11, pars->ZERO, pars->ZERO, w[128]);
+ FFV1_1(w[2], w[29], pars->GC_11, pars->ZERO, pars->ZERO, w[129]);
+ FFV1_1(w[116], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[130]);
+ FFV1_1(w[120], w[4], pars->GC_11, pars->ZERO, pars->ZERO, w[131]);
+ FFV1_2(w[22], w[70], pars->GC_11, pars->ZERO, pars->ZERO, w[132]);
+ FFV1_1(w[2], w[70], pars->GC_11, pars->ZERO, pars->ZERO, w[133]);
+ FFV1_2(w[22], w[68], pars->GC_11, pars->ZERO, pars->ZERO, w[134]);
+ FFV1_1(w[2], w[68], pars->GC_11, pars->ZERO, pars->ZERO, w[135]);
+ FFV1_2(w[22], w[29], pars->GC_11, pars->ZERO, pars->ZERO, w[136]);
+ FFV1_2(w[30], w[90], pars->GC_11, pars->ZERO, pars->ZERO, w[137]);
+ FFV1_1(w[2], w[90], pars->GC_11, pars->ZERO, pars->ZERO, w[138]);
+ FFV1_2(w[30], w[68], pars->GC_11, pars->ZERO, pars->ZERO, w[139]);
+ FFV1_2(w[30], w[35], pars->GC_11, pars->ZERO, pars->ZERO, w[140]);
+ FFV1_2(w[36], w[90], pars->GC_11, pars->ZERO, pars->ZERO, w[141]);
+ FFV1_2(w[36], w[70], pars->GC_11, pars->ZERO, pars->ZERO, w[142]);
+ FFV1_2(w[36], w[41], pars->GC_11, pars->ZERO, pars->ZERO, w[143]);
+ FFV1P0_3(w[3], w[116], pars->GC_11, pars->ZERO, pars->ZERO, w[144]);
+ VVVV1P0_1(w[90], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[145]);
+ VVVV3P0_1(w[90], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[146]);
+ VVVV4P0_1(w[90], w[6], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[147]);
+ FFV1P0_3(w[10], w[2], pars->GC_11, pars->ZERO, pars->ZERO, w[148]);
+ FFV1P0_3(w[3], w[120], pars->GC_11, pars->ZERO, pars->ZERO, w[149]);
+ FFV1P0_3(w[18], w[2], pars->GC_11, pars->ZERO, pars->ZERO, w[150]);
+ VVV1P0_1(w[90], w[29], pars->GC_10, pars->ZERO, pars->ZERO, w[151]);
+ VVVV1P0_1(w[70], w[5], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[152]);
+ VVVV3P0_1(w[70], w[5], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[153]);
+ VVVV4P0_1(w[70], w[5], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[154]);
+ VVV1P0_1(w[70], w[35], pars->GC_10, pars->ZERO, pars->ZERO, w[155]);
+ VVVV1P0_1(w[68], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[156]);
+ VVVV3P0_1(w[68], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[157]);
+ VVVV4P0_1(w[68], w[5], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[158]);
+ VVV1P0_1(w[68], w[41], pars->GC_10, pars->ZERO, pars->ZERO, w[159]);
+ VVVV1P0_1(w[4], w[41], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[160]);
+ VVVV3P0_1(w[4], w[41], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[161]);
+ VVVV4P0_1(w[4], w[41], w[7], pars->GC_12, pars->ZERO, pars->ZERO, w[162]);
+ VVVV1P0_1(w[4], w[35], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[163]);
+ VVVV3P0_1(w[4], w[35], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[164]);
+ VVVV4P0_1(w[4], w[35], w[6], pars->GC_12, pars->ZERO, pars->ZERO, w[165]);
+ VVVV1P0_1(w[4], w[5], w[29], pars->GC_12, pars->ZERO, pars->ZERO, w[166]);
+ VVVV3P0_1(w[4], w[5], w[29], pars->GC_12, pars->ZERO, pars->ZERO, w[167]);
+ VVVV4P0_1(w[4], w[5], w[29], pars->GC_12, pars->ZERO, pars->ZERO, w[168]);
+ FFV1_2(w[3], w[113], pars->GC_11, pars->ZERO, pars->ZERO, w[169]);
+ FFV1_2(w[3], w[114], pars->GC_11, pars->ZERO, pars->ZERO, w[170]);
+ FFV1_2(w[3], w[115], pars->GC_11, pars->ZERO, pars->ZERO, w[171]);
+ VVV1P0_1(w[113], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[172]);
+ VVV1P0_1(w[114], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[173]);
+ VVV1P0_1(w[115], w[7], pars->GC_10, pars->ZERO, pars->ZERO, w[174]);
+ FFV1_1(w[2], w[113], pars->GC_11, pars->ZERO, pars->ZERO, w[175]);
+ FFV1_1(w[2], w[114], pars->GC_11, pars->ZERO, pars->ZERO, w[176]);
+ FFV1_1(w[2], w[115], pars->GC_11, pars->ZERO, pars->ZERO, w[177]);
+ FFV1_2(w[3], w[98], pars->GC_11, pars->ZERO, pars->ZERO, w[178]);
+ FFV1_2(w[3], w[99], pars->GC_11, pars->ZERO, pars->ZERO, w[179]);
+ FFV1_2(w[3], w[100], pars->GC_11, pars->ZERO, pars->ZERO, w[180]);
+ VVV1P0_1(w[98], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[181]);
+ VVV1P0_1(w[99], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[182]);
+ VVV1P0_1(w[100], w[6], pars->GC_10, pars->ZERO, pars->ZERO, w[183]);
+ FFV1_1(w[2], w[98], pars->GC_11, pars->ZERO, pars->ZERO, w[184]);
+ FFV1_1(w[2], w[99], pars->GC_11, pars->ZERO, pars->ZERO, w[185]);
+ FFV1_1(w[2], w[100], pars->GC_11, pars->ZERO, pars->ZERO, w[186]);
+ FFV1_2(w[3], w[79], pars->GC_11, pars->ZERO, pars->ZERO, w[187]);
+ FFV1_2(w[3], w[80], pars->GC_11, pars->ZERO, pars->ZERO, w[188]);
+ FFV1_2(w[3], w[81], pars->GC_11, pars->ZERO, pars->ZERO, w[189]);
+ VVV1P0_1(w[79], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[190]);
+ VVV1P0_1(w[80], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[191]);
+ VVV1P0_1(w[81], w[5], pars->GC_10, pars->ZERO, pars->ZERO, w[192]);
+ FFV1_1(w[2], w[79], pars->GC_11, pars->ZERO, pars->ZERO, w[193]);
+ FFV1_1(w[2], w[80], pars->GC_11, pars->ZERO, pars->ZERO, w[194]);
+ FFV1_1(w[2], w[81], pars->GC_11, pars->ZERO, pars->ZERO, w[195]);
+ FFV1_2(w[3], w[51], pars->GC_11, pars->ZERO, pars->ZERO, w[196]);
+ FFV1_2(w[3], w[52], pars->GC_11, pars->ZERO, pars->ZERO, w[197]);
+ FFV1_2(w[3], w[53], pars->GC_11, pars->ZERO, pars->ZERO, w[198]);
+ VVV1P0_1(w[4], w[51], pars->GC_10, pars->ZERO, pars->ZERO, w[199]);
+ VVV1P0_1(w[4], w[52], pars->GC_10, pars->ZERO, pars->ZERO, w[200]);
+ VVV1P0_1(w[4], w[53], pars->GC_10, pars->ZERO, pars->ZERO, w[201]);
+ FFV1_1(w[2], w[51], pars->GC_11, pars->ZERO, pars->ZERO, w[202]);
+ FFV1_1(w[2], w[52], pars->GC_11, pars->ZERO, pars->ZERO, w[203]);
+ FFV1_1(w[2], w[53], pars->GC_11, pars->ZERO, pars->ZERO, w[204]);
+
+ // Calculate all amplitudes
+ // Amplitude(s) for diagram number 0
+ FFV1_0(w[12], w[11], w[7], pars->GC_11, amp[0]);
+ FFV1_0(w[13], w[11], w[6], pars->GC_11, amp[1]);
+ FFV1_0(w[15], w[14], w[7], pars->GC_11, amp[2]);
+ FFV1_0(w[13], w[14], w[5], pars->GC_11, amp[3]);
+ FFV1_0(w[15], w[16], w[6], pars->GC_11, amp[4]);
+ FFV1_0(w[12], w[16], w[5], pars->GC_11, amp[5]);
+ FFV1_0(w[19], w[11], w[7], pars->GC_11, amp[6]);
+ FFV1_0(w[20], w[11], w[6], pars->GC_11, amp[7]);
+ FFV1_0(w[21], w[14], w[7], pars->GC_11, amp[8]);
+ FFV1_0(w[20], w[14], w[5], pars->GC_11, amp[9]);
+ FFV1_0(w[21], w[16], w[6], pars->GC_11, amp[10]);
+ FFV1_0(w[19], w[16], w[5], pars->GC_11, amp[11]);
+ FFV1_0(w[24], w[23], w[7], pars->GC_11, amp[12]);
+ FFV1_0(w[25], w[23], w[6], pars->GC_11, amp[13]);
+ FFV1_0(w[26], w[14], w[7], pars->GC_11, amp[14]);
+ FFV1_0(w[26], w[16], w[6], pars->GC_11, amp[15]);
+ FFV1_0(w[25], w[14], w[8], pars->GC_2, amp[16]);
+ FFV1_0(w[24], w[16], w[8], pars->GC_2, amp[17]);
+ FFV1_0(w[24], w[27], w[7], pars->GC_11, amp[18]);
+ FFV1_0(w[25], w[27], w[6], pars->GC_11, amp[19]);
+ FFV1_0(w[28], w[14], w[7], pars->GC_11, amp[20]);
+ FFV1_0(w[28], w[16], w[6], pars->GC_11, amp[21]);
+ FFV2_5_0(w[25], w[14], w[17], pars->GC_51, pars->GC_58, amp[22]);
+ FFV2_5_0(w[24], w[16], w[17], pars->GC_51, pars->GC_58, amp[23]);
+ FFV1_0(w[22], w[23], w[29], pars->GC_11, amp[24]);
+ FFV1_0(w[26], w[9], w[29], pars->GC_11, amp[25]);
+ FFV1_0(w[22], w[27], w[29], pars->GC_11, amp[26]);
+ FFV1_0(w[28], w[9], w[29], pars->GC_11, amp[27]);
+ FFV1_0(w[31], w[23], w[7], pars->GC_11, amp[28]);
+ FFV1_0(w[32], w[23], w[5], pars->GC_11, amp[29]);
+ FFV1_0(w[33], w[11], w[7], pars->GC_11, amp[30]);
+ FFV1_0(w[33], w[16], w[5], pars->GC_11, amp[31]);
+ FFV1_0(w[32], w[11], w[8], pars->GC_2, amp[32]);
+ FFV1_0(w[31], w[16], w[8], pars->GC_2, amp[33]);
+ FFV1_0(w[31], w[27], w[7], pars->GC_11, amp[34]);
+ FFV1_0(w[32], w[27], w[5], pars->GC_11, amp[35]);
+ FFV1_0(w[34], w[11], w[7], pars->GC_11, amp[36]);
+ FFV1_0(w[34], w[16], w[5], pars->GC_11, amp[37]);
+ FFV2_5_0(w[32], w[11], w[17], pars->GC_51, pars->GC_58, amp[38]);
+ FFV2_5_0(w[31], w[16], w[17], pars->GC_51, pars->GC_58, amp[39]);
+ FFV1_0(w[30], w[23], w[35], pars->GC_11, amp[40]);
+ FFV1_0(w[33], w[9], w[35], pars->GC_11, amp[41]);
+ FFV1_0(w[30], w[27], w[35], pars->GC_11, amp[42]);
+ FFV1_0(w[34], w[9], w[35], pars->GC_11, amp[43]);
+ FFV1_0(w[37], w[23], w[6], pars->GC_11, amp[44]);
+ FFV1_0(w[38], w[23], w[5], pars->GC_11, amp[45]);
+ FFV1_0(w[39], w[11], w[6], pars->GC_11, amp[46]);
+ FFV1_0(w[39], w[14], w[5], pars->GC_11, amp[47]);
+ FFV1_0(w[38], w[11], w[8], pars->GC_2, amp[48]);
+ FFV1_0(w[37], w[14], w[8], pars->GC_2, amp[49]);
+ FFV1_0(w[37], w[27], w[6], pars->GC_11, amp[50]);
+ FFV1_0(w[38], w[27], w[5], pars->GC_11, amp[51]);
+ FFV1_0(w[40], w[11], w[6], pars->GC_11, amp[52]);
+ FFV1_0(w[40], w[14], w[5], pars->GC_11, amp[53]);
+ FFV2_5_0(w[38], w[11], w[17], pars->GC_51, pars->GC_58, amp[54]);
+ FFV2_5_0(w[37], w[14], w[17], pars->GC_51, pars->GC_58, amp[55]);
+ FFV1_0(w[36], w[23], w[41], pars->GC_11, amp[56]);
+ FFV1_0(w[39], w[9], w[41], pars->GC_11, amp[57]);
+ FFV1_0(w[36], w[27], w[41], pars->GC_11, amp[58]);
+ FFV1_0(w[40], w[9], w[41], pars->GC_11, amp[59]);
+ FFV1_0(w[42], w[23], w[7], pars->GC_11, amp[60]);
+ FFV1_0(w[3], w[23], w[43], pars->GC_11, amp[61]);
+ FFV1_0(w[10], w[44], w[7], pars->GC_11, amp[62]);
+ FFV1_0(w[10], w[16], w[41], pars->GC_11, amp[63]);
+ FFV1_0(w[10], w[9], w[43], pars->GC_11, amp[64]);
+ FFV1_0(w[42], w[16], w[8], pars->GC_2, amp[65]);
+ FFV1_0(w[42], w[27], w[7], pars->GC_11, amp[66]);
+ FFV1_0(w[3], w[27], w[43], pars->GC_11, amp[67]);
+ FFV1_0(w[18], w[44], w[7], pars->GC_11, amp[68]);
+ FFV1_0(w[18], w[16], w[41], pars->GC_11, amp[69]);
+ FFV1_0(w[18], w[9], w[43], pars->GC_11, amp[70]);
+ FFV2_5_0(w[42], w[16], w[17], pars->GC_51, pars->GC_58, amp[71]);
+ FFV1_0(w[45], w[23], w[6], pars->GC_11, amp[72]);
+ FFV1_0(w[3], w[23], w[46], pars->GC_11, amp[73]);
+ FFV1_0(w[10], w[47], w[6], pars->GC_11, amp[74]);
+ FFV1_0(w[10], w[14], w[35], pars->GC_11, amp[75]);
+ FFV1_0(w[10], w[9], w[46], pars->GC_11, amp[76]);
+ FFV1_0(w[45], w[14], w[8], pars->GC_2, amp[77]);
+ FFV1_0(w[45], w[27], w[6], pars->GC_11, amp[78]);
+ FFV1_0(w[3], w[27], w[46], pars->GC_11, amp[79]);
+ FFV1_0(w[18], w[47], w[6], pars->GC_11, amp[80]);
+ FFV1_0(w[18], w[14], w[35], pars->GC_11, amp[81]);
+ FFV1_0(w[18], w[9], w[46], pars->GC_11, amp[82]);
+ FFV2_5_0(w[45], w[14], w[17], pars->GC_51, pars->GC_58, amp[83]);
+ FFV1_0(w[48], w[23], w[5], pars->GC_11, amp[84]);
+ FFV1_0(w[3], w[23], w[49], pars->GC_11, amp[85]);
+ FFV1_0(w[10], w[11], w[29], pars->GC_11, amp[86]);
+ FFV1_0(w[10], w[50], w[5], pars->GC_11, amp[87]);
+ FFV1_0(w[10], w[9], w[49], pars->GC_11, amp[88]);
+ FFV1_0(w[48], w[11], w[8], pars->GC_2, amp[89]);
+ FFV1_0(w[48], w[27], w[5], pars->GC_11, amp[90]);
+ FFV1_0(w[3], w[27], w[49], pars->GC_11, amp[91]);
+ FFV1_0(w[18], w[11], w[29], pars->GC_11, amp[92]);
+ FFV1_0(w[18], w[50], w[5], pars->GC_11, amp[93]);
+ FFV1_0(w[18], w[9], w[49], pars->GC_11, amp[94]);
+ FFV2_5_0(w[48], w[11], w[17], pars->GC_51, pars->GC_58, amp[95]);
+ FFV1_0(w[3], w[23], w[51], pars->GC_11, amp[96]);
+ FFV1_0(w[3], w[23], w[52], pars->GC_11, amp[97]);
+ FFV1_0(w[3], w[23], w[53], pars->GC_11, amp[98]);
+ FFV1_0(w[10], w[9], w[51], pars->GC_11, amp[99]);
+ FFV1_0(w[10], w[9], w[52], pars->GC_11, amp[100]);
+ FFV1_0(w[10], w[9], w[53], pars->GC_11, amp[101]);
+ FFV1_0(w[3], w[27], w[51], pars->GC_11, amp[102]);
+ FFV1_0(w[3], w[27], w[52], pars->GC_11, amp[103]);
+ FFV1_0(w[3], w[27], w[53], pars->GC_11, amp[104]);
+ FFV1_0(w[18], w[9], w[51], pars->GC_11, amp[105]);
+ FFV1_0(w[18], w[9], w[52], pars->GC_11, amp[106]);
+ FFV1_0(w[18], w[9], w[53], pars->GC_11, amp[107]);
+ FFV1_0(w[12], w[55], w[7], pars->GC_11, amp[108]);
+ FFV1_0(w[13], w[55], w[6], pars->GC_11, amp[109]);
+ FFV1_0(w[57], w[56], w[7], pars->GC_11, amp[110]);
+ FFV1_0(w[13], w[56], w[4], pars->GC_11, amp[111]);
+ FFV1_0(w[57], w[58], w[6], pars->GC_11, amp[112]);
+ FFV1_0(w[12], w[58], w[4], pars->GC_11, amp[113]);
+ FFV1_0(w[19], w[55], w[7], pars->GC_11, amp[114]);
+ FFV1_0(w[20], w[55], w[6], pars->GC_11, amp[115]);
+ FFV1_0(w[59], w[56], w[7], pars->GC_11, amp[116]);
+ FFV1_0(w[20], w[56], w[4], pars->GC_11, amp[117]);
+ FFV1_0(w[59], w[58], w[6], pars->GC_11, amp[118]);
+ FFV1_0(w[19], w[58], w[4], pars->GC_11, amp[119]);
+ FFV1_0(w[62], w[61], w[7], pars->GC_11, amp[120]);
+ FFV1_0(w[63], w[61], w[6], pars->GC_11, amp[121]);
+ FFV1_0(w[64], w[56], w[7], pars->GC_11, amp[122]);
+ FFV1_0(w[64], w[58], w[6], pars->GC_11, amp[123]);
+ FFV1_0(w[63], w[56], w[8], pars->GC_2, amp[124]);
+ FFV1_0(w[62], w[58], w[8], pars->GC_2, amp[125]);
+ FFV1_0(w[62], w[65], w[7], pars->GC_11, amp[126]);
+ FFV1_0(w[63], w[65], w[6], pars->GC_11, amp[127]);
+ FFV1_0(w[66], w[56], w[7], pars->GC_11, amp[128]);
+ FFV1_0(w[66], w[58], w[6], pars->GC_11, amp[129]);
+ FFV2_5_0(w[63], w[56], w[17], pars->GC_51, pars->GC_58, amp[130]);
+ FFV2_5_0(w[62], w[58], w[17], pars->GC_51, pars->GC_58, amp[131]);
+ FFV1_0(w[60], w[61], w[29], pars->GC_11, amp[132]);
+ FFV1_0(w[64], w[54], w[29], pars->GC_11, amp[133]);
+ FFV1_0(w[60], w[65], w[29], pars->GC_11, amp[134]);
+ FFV1_0(w[66], w[54], w[29], pars->GC_11, amp[135]);
+ FFV1_0(w[67], w[61], w[7], pars->GC_11, amp[136]);
+ FFV1_0(w[32], w[61], w[4], pars->GC_11, amp[137]);
+ FFV1_0(w[33], w[55], w[7], pars->GC_11, amp[138]);
+ FFV1_0(w[33], w[58], w[4], pars->GC_11, amp[139]);
+ FFV1_0(w[32], w[55], w[8], pars->GC_2, amp[140]);
+ FFV1_0(w[67], w[58], w[8], pars->GC_2, amp[141]);
+ FFV1_0(w[67], w[65], w[7], pars->GC_11, amp[142]);
+ FFV1_0(w[32], w[65], w[4], pars->GC_11, amp[143]);
+ FFV1_0(w[34], w[55], w[7], pars->GC_11, amp[144]);
+ FFV1_0(w[34], w[58], w[4], pars->GC_11, amp[145]);
+ FFV2_5_0(w[32], w[55], w[17], pars->GC_51, pars->GC_58, amp[146]);
+ FFV2_5_0(w[67], w[58], w[17], pars->GC_51, pars->GC_58, amp[147]);
+ FFV1_0(w[30], w[61], w[68], pars->GC_11, amp[148]);
+ FFV1_0(w[33], w[54], w[68], pars->GC_11, amp[149]);
+ FFV1_0(w[30], w[65], w[68], pars->GC_11, amp[150]);
+ FFV1_0(w[34], w[54], w[68], pars->GC_11, amp[151]);
+ FFV1_0(w[69], w[61], w[6], pars->GC_11, amp[152]);
+ FFV1_0(w[38], w[61], w[4], pars->GC_11, amp[153]);
+ FFV1_0(w[39], w[55], w[6], pars->GC_11, amp[154]);
+ FFV1_0(w[39], w[56], w[4], pars->GC_11, amp[155]);
+ FFV1_0(w[38], w[55], w[8], pars->GC_2, amp[156]);
+ FFV1_0(w[69], w[56], w[8], pars->GC_2, amp[157]);
+ FFV1_0(w[69], w[65], w[6], pars->GC_11, amp[158]);
+ FFV1_0(w[38], w[65], w[4], pars->GC_11, amp[159]);
+ FFV1_0(w[40], w[55], w[6], pars->GC_11, amp[160]);
+ FFV1_0(w[40], w[56], w[4], pars->GC_11, amp[161]);
+ FFV2_5_0(w[38], w[55], w[17], pars->GC_51, pars->GC_58, amp[162]);
+ FFV2_5_0(w[69], w[56], w[17], pars->GC_51, pars->GC_58, amp[163]);
+ FFV1_0(w[36], w[61], w[70], pars->GC_11, amp[164]);
+ FFV1_0(w[39], w[54], w[70], pars->GC_11, amp[165]);
+ FFV1_0(w[36], w[65], w[70], pars->GC_11, amp[166]);
+ FFV1_0(w[40], w[54], w[70], pars->GC_11, amp[167]);
+ FFV1_0(w[71], w[61], w[7], pars->GC_11, amp[168]);
+ FFV1_0(w[3], w[61], w[72], pars->GC_11, amp[169]);
+ FFV1_0(w[10], w[73], w[7], pars->GC_11, amp[170]);
+ FFV1_0(w[10], w[58], w[70], pars->GC_11, amp[171]);
+ FFV1_0(w[10], w[54], w[72], pars->GC_11, amp[172]);
+ FFV1_0(w[71], w[58], w[8], pars->GC_2, amp[173]);
+ FFV1_0(w[71], w[65], w[7], pars->GC_11, amp[174]);
+ FFV1_0(w[3], w[65], w[72], pars->GC_11, amp[175]);
+ FFV1_0(w[18], w[73], w[7], pars->GC_11, amp[176]);
+ FFV1_0(w[18], w[58], w[70], pars->GC_11, amp[177]);
+ FFV1_0(w[18], w[54], w[72], pars->GC_11, amp[178]);
+ FFV2_5_0(w[71], w[58], w[17], pars->GC_51, pars->GC_58, amp[179]);
+ FFV1_0(w[74], w[61], w[6], pars->GC_11, amp[180]);
+ FFV1_0(w[3], w[61], w[75], pars->GC_11, amp[181]);
+ FFV1_0(w[10], w[76], w[6], pars->GC_11, amp[182]);
+ FFV1_0(w[10], w[56], w[68], pars->GC_11, amp[183]);
+ FFV1_0(w[10], w[54], w[75], pars->GC_11, amp[184]);
+ FFV1_0(w[74], w[56], w[8], pars->GC_2, amp[185]);
+ FFV1_0(w[74], w[65], w[6], pars->GC_11, amp[186]);
+ FFV1_0(w[3], w[65], w[75], pars->GC_11, amp[187]);
+ FFV1_0(w[18], w[76], w[6], pars->GC_11, amp[188]);
+ FFV1_0(w[18], w[56], w[68], pars->GC_11, amp[189]);
+ FFV1_0(w[18], w[54], w[75], pars->GC_11, amp[190]);
+ FFV2_5_0(w[74], w[56], w[17], pars->GC_51, pars->GC_58, amp[191]);
+ FFV1_0(w[48], w[61], w[4], pars->GC_11, amp[192]);
+ FFV1_0(w[3], w[61], w[77], pars->GC_11, amp[193]);
+ FFV1_0(w[10], w[55], w[29], pars->GC_11, amp[194]);
+ FFV1_0(w[10], w[78], w[4], pars->GC_11, amp[195]);
+ FFV1_0(w[10], w[54], w[77], pars->GC_11, amp[196]);
+ FFV1_0(w[48], w[55], w[8], pars->GC_2, amp[197]);
+ FFV1_0(w[48], w[65], w[4], pars->GC_11, amp[198]);
+ FFV1_0(w[3], w[65], w[77], pars->GC_11, amp[199]);
+ FFV1_0(w[18], w[55], w[29], pars->GC_11, amp[200]);
+ FFV1_0(w[18], w[78], w[4], pars->GC_11, amp[201]);
+ FFV1_0(w[18], w[54], w[77], pars->GC_11, amp[202]);
+ FFV2_5_0(w[48], w[55], w[17], pars->GC_51, pars->GC_58, amp[203]);
+ FFV1_0(w[3], w[61], w[79], pars->GC_11, amp[204]);
+ FFV1_0(w[3], w[61], w[80], pars->GC_11, amp[205]);
+ FFV1_0(w[3], w[61], w[81], pars->GC_11, amp[206]);
+ FFV1_0(w[10], w[54], w[79], pars->GC_11, amp[207]);
+ FFV1_0(w[10], w[54], w[80], pars->GC_11, amp[208]);
+ FFV1_0(w[10], w[54], w[81], pars->GC_11, amp[209]);
+ FFV1_0(w[3], w[65], w[79], pars->GC_11, amp[210]);
+ FFV1_0(w[3], w[65], w[80], pars->GC_11, amp[211]);
+ FFV1_0(w[3], w[65], w[81], pars->GC_11, amp[212]);
+ FFV1_0(w[18], w[54], w[79], pars->GC_11, amp[213]);
+ FFV1_0(w[18], w[54], w[80], pars->GC_11, amp[214]);
+ FFV1_0(w[18], w[54], w[81], pars->GC_11, amp[215]);
+ FFV1_0(w[15], w[83], w[7], pars->GC_11, amp[216]);
+ FFV1_0(w[13], w[83], w[5], pars->GC_11, amp[217]);
+ FFV1_0(w[57], w[84], w[7], pars->GC_11, amp[218]);
+ FFV1_0(w[13], w[84], w[4], pars->GC_11, amp[219]);
+ FFV1_0(w[57], w[85], w[5], pars->GC_11, amp[220]);
+ FFV1_0(w[15], w[85], w[4], pars->GC_11, amp[221]);
+ FFV1_0(w[21], w[83], w[7], pars->GC_11, amp[222]);
+ FFV1_0(w[20], w[83], w[5], pars->GC_11, amp[223]);
+ FFV1_0(w[59], w[84], w[7], pars->GC_11, amp[224]);
+ FFV1_0(w[20], w[84], w[4], pars->GC_11, amp[225]);
+ FFV1_0(w[59], w[85], w[5], pars->GC_11, amp[226]);
+ FFV1_0(w[21], w[85], w[4], pars->GC_11, amp[227]);
+ FFV1_0(w[87], w[86], w[7], pars->GC_11, amp[228]);
+ FFV1_0(w[63], w[86], w[5], pars->GC_11, amp[229]);
+ FFV1_0(w[64], w[84], w[7], pars->GC_11, amp[230]);
+ FFV1_0(w[64], w[85], w[5], pars->GC_11, amp[231]);
+ FFV1_0(w[63], w[84], w[8], pars->GC_2, amp[232]);
+ FFV1_0(w[87], w[85], w[8], pars->GC_2, amp[233]);
+ FFV1_0(w[87], w[88], w[7], pars->GC_11, amp[234]);
+ FFV1_0(w[63], w[88], w[5], pars->GC_11, amp[235]);
+ FFV1_0(w[66], w[84], w[7], pars->GC_11, amp[236]);
+ FFV1_0(w[66], w[85], w[5], pars->GC_11, amp[237]);
+ FFV2_5_0(w[63], w[84], w[17], pars->GC_51, pars->GC_58, amp[238]);
+ FFV2_5_0(w[87], w[85], w[17], pars->GC_51, pars->GC_58, amp[239]);
+ FFV1_0(w[60], w[86], w[35], pars->GC_11, amp[240]);
+ FFV1_0(w[64], w[82], w[35], pars->GC_11, amp[241]);
+ FFV1_0(w[60], w[88], w[35], pars->GC_11, amp[242]);
+ FFV1_0(w[66], w[82], w[35], pars->GC_11, amp[243]);
+ FFV1_0(w[89], w[86], w[7], pars->GC_11, amp[244]);
+ FFV1_0(w[25], w[86], w[4], pars->GC_11, amp[245]);
+ FFV1_0(w[26], w[83], w[7], pars->GC_11, amp[246]);
+ FFV1_0(w[26], w[85], w[4], pars->GC_11, amp[247]);
+ FFV1_0(w[25], w[83], w[8], pars->GC_2, amp[248]);
+ FFV1_0(w[89], w[85], w[8], pars->GC_2, amp[249]);
+ FFV1_0(w[89], w[88], w[7], pars->GC_11, amp[250]);
+ FFV1_0(w[25], w[88], w[4], pars->GC_11, amp[251]);
+ FFV1_0(w[28], w[83], w[7], pars->GC_11, amp[252]);
+ FFV1_0(w[28], w[85], w[4], pars->GC_11, amp[253]);
+ FFV2_5_0(w[25], w[83], w[17], pars->GC_51, pars->GC_58, amp[254]);
+ FFV2_5_0(w[89], w[85], w[17], pars->GC_51, pars->GC_58, amp[255]);
+ FFV1_0(w[22], w[86], w[68], pars->GC_11, amp[256]);
+ FFV1_0(w[26], w[82], w[68], pars->GC_11, amp[257]);
+ FFV1_0(w[22], w[88], w[68], pars->GC_11, amp[258]);
+ FFV1_0(w[28], w[82], w[68], pars->GC_11, amp[259]);
+ FFV1_0(w[69], w[86], w[5], pars->GC_11, amp[260]);
+ FFV1_0(w[37], w[86], w[4], pars->GC_11, amp[261]);
+ FFV1_0(w[39], w[83], w[5], pars->GC_11, amp[262]);
+ FFV1_0(w[39], w[84], w[4], pars->GC_11, amp[263]);
+ FFV1_0(w[37], w[83], w[8], pars->GC_2, amp[264]);
+ FFV1_0(w[69], w[84], w[8], pars->GC_2, amp[265]);
+ FFV1_0(w[69], w[88], w[5], pars->GC_11, amp[266]);
+ FFV1_0(w[37], w[88], w[4], pars->GC_11, amp[267]);
+ FFV1_0(w[40], w[83], w[5], pars->GC_11, amp[268]);
+ FFV1_0(w[40], w[84], w[4], pars->GC_11, amp[269]);
+ FFV2_5_0(w[37], w[83], w[17], pars->GC_51, pars->GC_58, amp[270]);
+ FFV2_5_0(w[69], w[84], w[17], pars->GC_51, pars->GC_58, amp[271]);
+ FFV1_0(w[36], w[86], w[90], pars->GC_11, amp[272]);
+ FFV1_0(w[39], w[82], w[90], pars->GC_11, amp[273]);
+ FFV1_0(w[36], w[88], w[90], pars->GC_11, amp[274]);
+ FFV1_0(w[40], w[82], w[90], pars->GC_11, amp[275]);
+ FFV1_0(w[91], w[86], w[7], pars->GC_11, amp[276]);
+ FFV1_0(w[3], w[86], w[92], pars->GC_11, amp[277]);
+ FFV1_0(w[10], w[93], w[7], pars->GC_11, amp[278]);
+ FFV1_0(w[10], w[85], w[90], pars->GC_11, amp[279]);
+ FFV1_0(w[10], w[82], w[92], pars->GC_11, amp[280]);
+ FFV1_0(w[91], w[85], w[8], pars->GC_2, amp[281]);
+ FFV1_0(w[91], w[88], w[7], pars->GC_11, amp[282]);
+ FFV1_0(w[3], w[88], w[92], pars->GC_11, amp[283]);
+ FFV1_0(w[18], w[93], w[7], pars->GC_11, amp[284]);
+ FFV1_0(w[18], w[85], w[90], pars->GC_11, amp[285]);
+ FFV1_0(w[18], w[82], w[92], pars->GC_11, amp[286]);
+ FFV2_5_0(w[91], w[85], w[17], pars->GC_51, pars->GC_58, amp[287]);
+ FFV1_0(w[74], w[86], w[5], pars->GC_11, amp[288]);
+ FFV1_0(w[3], w[86], w[94], pars->GC_11, amp[289]);
+ FFV1_0(w[10], w[95], w[5], pars->GC_11, amp[290]);
+ FFV1_0(w[10], w[84], w[68], pars->GC_11, amp[291]);
+ FFV1_0(w[10], w[82], w[94], pars->GC_11, amp[292]);
+ FFV1_0(w[74], w[84], w[8], pars->GC_2, amp[293]);
+ FFV1_0(w[74], w[88], w[5], pars->GC_11, amp[294]);
+ FFV1_0(w[3], w[88], w[94], pars->GC_11, amp[295]);
+ FFV1_0(w[18], w[95], w[5], pars->GC_11, amp[296]);
+ FFV1_0(w[18], w[84], w[68], pars->GC_11, amp[297]);
+ FFV1_0(w[18], w[82], w[94], pars->GC_11, amp[298]);
+ FFV2_5_0(w[74], w[84], w[17], pars->GC_51, pars->GC_58, amp[299]);
+ FFV1_0(w[45], w[86], w[4], pars->GC_11, amp[300]);
+ FFV1_0(w[3], w[86], w[96], pars->GC_11, amp[301]);
+ FFV1_0(w[10], w[83], w[35], pars->GC_11, amp[302]);
+ FFV1_0(w[10], w[97], w[4], pars->GC_11, amp[303]);
+ FFV1_0(w[10], w[82], w[96], pars->GC_11, amp[304]);
+ FFV1_0(w[45], w[83], w[8], pars->GC_2, amp[305]);
+ FFV1_0(w[45], w[88], w[4], pars->GC_11, amp[306]);
+ FFV1_0(w[3], w[88], w[96], pars->GC_11, amp[307]);
+ FFV1_0(w[18], w[83], w[35], pars->GC_11, amp[308]);
+ FFV1_0(w[18], w[97], w[4], pars->GC_11, amp[309]);
+ FFV1_0(w[18], w[82], w[96], pars->GC_11, amp[310]);
+ FFV2_5_0(w[45], w[83], w[17], pars->GC_51, pars->GC_58, amp[311]);
+ FFV1_0(w[3], w[86], w[98], pars->GC_11, amp[312]);
+ FFV1_0(w[3], w[86], w[99], pars->GC_11, amp[313]);
+ FFV1_0(w[3], w[86], w[100], pars->GC_11, amp[314]);
+ FFV1_0(w[10], w[82], w[98], pars->GC_11, amp[315]);
+ FFV1_0(w[10], w[82], w[99], pars->GC_11, amp[316]);
+ FFV1_0(w[10], w[82], w[100], pars->GC_11, amp[317]);
+ FFV1_0(w[3], w[88], w[98], pars->GC_11, amp[318]);
+ FFV1_0(w[3], w[88], w[99], pars->GC_11, amp[319]);
+ FFV1_0(w[3], w[88], w[100], pars->GC_11, amp[320]);
+ FFV1_0(w[18], w[82], w[98], pars->GC_11, amp[321]);
+ FFV1_0(w[18], w[82], w[99], pars->GC_11, amp[322]);
+ FFV1_0(w[18], w[82], w[100], pars->GC_11, amp[323]);
+ FFV1_0(w[15], w[102], w[6], pars->GC_11, amp[324]);
+ FFV1_0(w[12], w[102], w[5], pars->GC_11, amp[325]);
+ FFV1_0(w[57], w[103], w[6], pars->GC_11, amp[326]);
+ FFV1_0(w[12], w[103], w[4], pars->GC_11, amp[327]);
+ FFV1_0(w[57], w[104], w[5], pars->GC_11, amp[328]);
+ FFV1_0(w[15], w[104], w[4], pars->GC_11, amp[329]);
+ FFV1_0(w[21], w[102], w[6], pars->GC_11, amp[330]);
+ FFV1_0(w[19], w[102], w[5], pars->GC_11, amp[331]);
+ FFV1_0(w[59], w[103], w[6], pars->GC_11, amp[332]);
+ FFV1_0(w[19], w[103], w[4], pars->GC_11, amp[333]);
+ FFV1_0(w[59], w[104], w[5], pars->GC_11, amp[334]);
+ FFV1_0(w[21], w[104], w[4], pars->GC_11, amp[335]);
+ FFV1_0(w[87], w[105], w[6], pars->GC_11, amp[336]);
+ FFV1_0(w[62], w[105], w[5], pars->GC_11, amp[337]);
+ FFV1_0(w[64], w[103], w[6], pars->GC_11, amp[338]);
+ FFV1_0(w[64], w[104], w[5], pars->GC_11, amp[339]);
+ FFV1_0(w[62], w[103], w[8], pars->GC_2, amp[340]);
+ FFV1_0(w[87], w[104], w[8], pars->GC_2, amp[341]);
+ FFV1_0(w[87], w[106], w[6], pars->GC_11, amp[342]);
+ FFV1_0(w[62], w[106], w[5], pars->GC_11, amp[343]);
+ FFV1_0(w[66], w[103], w[6], pars->GC_11, amp[344]);
+ FFV1_0(w[66], w[104], w[5], pars->GC_11, amp[345]);
+ FFV2_5_0(w[62], w[103], w[17], pars->GC_51, pars->GC_58, amp[346]);
+ FFV2_5_0(w[87], w[104], w[17], pars->GC_51, pars->GC_58, amp[347]);
+ FFV1_0(w[60], w[105], w[41], pars->GC_11, amp[348]);
+ FFV1_0(w[64], w[101], w[41], pars->GC_11, amp[349]);
+ FFV1_0(w[60], w[106], w[41], pars->GC_11, amp[350]);
+ FFV1_0(w[66], w[101], w[41], pars->GC_11, amp[351]);
+ FFV1_0(w[89], w[105], w[6], pars->GC_11, amp[352]);
+ FFV1_0(w[24], w[105], w[4], pars->GC_11, amp[353]);
+ FFV1_0(w[26], w[102], w[6], pars->GC_11, amp[354]);
+ FFV1_0(w[26], w[104], w[4], pars->GC_11, amp[355]);
+ FFV1_0(w[24], w[102], w[8], pars->GC_2, amp[356]);
+ FFV1_0(w[89], w[104], w[8], pars->GC_2, amp[357]);
+ FFV1_0(w[89], w[106], w[6], pars->GC_11, amp[358]);
+ FFV1_0(w[24], w[106], w[4], pars->GC_11, amp[359]);
+ FFV1_0(w[28], w[102], w[6], pars->GC_11, amp[360]);
+ FFV1_0(w[28], w[104], w[4], pars->GC_11, amp[361]);
+ FFV2_5_0(w[24], w[102], w[17], pars->GC_51, pars->GC_58, amp[362]);
+ FFV2_5_0(w[89], w[104], w[17], pars->GC_51, pars->GC_58, amp[363]);
+ FFV1_0(w[22], w[105], w[70], pars->GC_11, amp[364]);
+ FFV1_0(w[26], w[101], w[70], pars->GC_11, amp[365]);
+ FFV1_0(w[22], w[106], w[70], pars->GC_11, amp[366]);
+ FFV1_0(w[28], w[101], w[70], pars->GC_11, amp[367]);
+ FFV1_0(w[67], w[105], w[5], pars->GC_11, amp[368]);
+ FFV1_0(w[31], w[105], w[4], pars->GC_11, amp[369]);
+ FFV1_0(w[33], w[102], w[5], pars->GC_11, amp[370]);
+ FFV1_0(w[33], w[103], w[4], pars->GC_11, amp[371]);
+ FFV1_0(w[31], w[102], w[8], pars->GC_2, amp[372]);
+ FFV1_0(w[67], w[103], w[8], pars->GC_2, amp[373]);
+ FFV1_0(w[67], w[106], w[5], pars->GC_11, amp[374]);
+ FFV1_0(w[31], w[106], w[4], pars->GC_11, amp[375]);
+ FFV1_0(w[34], w[102], w[5], pars->GC_11, amp[376]);
+ FFV1_0(w[34], w[103], w[4], pars->GC_11, amp[377]);
+ FFV2_5_0(w[31], w[102], w[17], pars->GC_51, pars->GC_58, amp[378]);
+ FFV2_5_0(w[67], w[103], w[17], pars->GC_51, pars->GC_58, amp[379]);
+ FFV1_0(w[30], w[105], w[90], pars->GC_11, amp[380]);
+ FFV1_0(w[33], w[101], w[90], pars->GC_11, amp[381]);
+ FFV1_0(w[30], w[106], w[90], pars->GC_11, amp[382]);
+ FFV1_0(w[34], w[101], w[90], pars->GC_11, amp[383]);
+ FFV1_0(w[91], w[105], w[6], pars->GC_11, amp[384]);
+ FFV1_0(w[3], w[105], w[107], pars->GC_11, amp[385]);
+ FFV1_0(w[10], w[108], w[6], pars->GC_11, amp[386]);
+ FFV1_0(w[10], w[104], w[90], pars->GC_11, amp[387]);
+ FFV1_0(w[10], w[101], w[107], pars->GC_11, amp[388]);
+ FFV1_0(w[91], w[104], w[8], pars->GC_2, amp[389]);
+ FFV1_0(w[91], w[106], w[6], pars->GC_11, amp[390]);
+ FFV1_0(w[3], w[106], w[107], pars->GC_11, amp[391]);
+ FFV1_0(w[18], w[108], w[6], pars->GC_11, amp[392]);
+ FFV1_0(w[18], w[104], w[90], pars->GC_11, amp[393]);
+ FFV1_0(w[18], w[101], w[107], pars->GC_11, amp[394]);
+ FFV2_5_0(w[91], w[104], w[17], pars->GC_51, pars->GC_58, amp[395]);
+ FFV1_0(w[71], w[105], w[5], pars->GC_11, amp[396]);
+ FFV1_0(w[3], w[105], w[109], pars->GC_11, amp[397]);
+ FFV1_0(w[10], w[110], w[5], pars->GC_11, amp[398]);
+ FFV1_0(w[10], w[103], w[70], pars->GC_11, amp[399]);
+ FFV1_0(w[10], w[101], w[109], pars->GC_11, amp[400]);
+ FFV1_0(w[71], w[103], w[8], pars->GC_2, amp[401]);
+ FFV1_0(w[71], w[106], w[5], pars->GC_11, amp[402]);
+ FFV1_0(w[3], w[106], w[109], pars->GC_11, amp[403]);
+ FFV1_0(w[18], w[110], w[5], pars->GC_11, amp[404]);
+ FFV1_0(w[18], w[103], w[70], pars->GC_11, amp[405]);
+ FFV1_0(w[18], w[101], w[109], pars->GC_11, amp[406]);
+ FFV2_5_0(w[71], w[103], w[17], pars->GC_51, pars->GC_58, amp[407]);
+ FFV1_0(w[42], w[105], w[4], pars->GC_11, amp[408]);
+ FFV1_0(w[3], w[105], w[111], pars->GC_11, amp[409]);
+ FFV1_0(w[10], w[102], w[41], pars->GC_11, amp[410]);
+ FFV1_0(w[10], w[112], w[4], pars->GC_11, amp[411]);
+ FFV1_0(w[10], w[101], w[111], pars->GC_11, amp[412]);
+ FFV1_0(w[42], w[102], w[8], pars->GC_2, amp[413]);
+ FFV1_0(w[42], w[106], w[4], pars->GC_11, amp[414]);
+ FFV1_0(w[3], w[106], w[111], pars->GC_11, amp[415]);
+ FFV1_0(w[18], w[102], w[41], pars->GC_11, amp[416]);
+ FFV1_0(w[18], w[112], w[4], pars->GC_11, amp[417]);
+ FFV1_0(w[18], w[101], w[111], pars->GC_11, amp[418]);
+ FFV2_5_0(w[42], w[102], w[17], pars->GC_51, pars->GC_58, amp[419]);
+ FFV1_0(w[3], w[105], w[113], pars->GC_11, amp[420]);
+ FFV1_0(w[3], w[105], w[114], pars->GC_11, amp[421]);
+ FFV1_0(w[3], w[105], w[115], pars->GC_11, amp[422]);
+ FFV1_0(w[10], w[101], w[113], pars->GC_11, amp[423]);
+ FFV1_0(w[10], w[101], w[114], pars->GC_11, amp[424]);
+ FFV1_0(w[10], w[101], w[115], pars->GC_11, amp[425]);
+ FFV1_0(w[3], w[106], w[113], pars->GC_11, amp[426]);
+ FFV1_0(w[3], w[106], w[114], pars->GC_11, amp[427]);
+ FFV1_0(w[3], w[106], w[115], pars->GC_11, amp[428]);
+ FFV1_0(w[18], w[101], w[113], pars->GC_11, amp[429]);
+ FFV1_0(w[18], w[101], w[114], pars->GC_11, amp[430]);
+ FFV1_0(w[18], w[101], w[115], pars->GC_11, amp[431]);
+ FFV1_0(w[87], w[117], w[7], pars->GC_11, amp[432]);
+ FFV1_0(w[87], w[118], w[6], pars->GC_11, amp[433]);
+ FFV1_0(w[62], w[119], w[7], pars->GC_11, amp[434]);
+ FFV1_0(w[62], w[118], w[5], pars->GC_11, amp[435]);
+ FFV1_0(w[63], w[119], w[6], pars->GC_11, amp[436]);
+ FFV1_0(w[63], w[117], w[5], pars->GC_11, amp[437]);
+ FFV1_0(w[87], w[121], w[7], pars->GC_11, amp[438]);
+ FFV1_0(w[87], w[122], w[6], pars->GC_11, amp[439]);
+ FFV1_0(w[62], w[123], w[7], pars->GC_11, amp[440]);
+ FFV1_0(w[62], w[122], w[5], pars->GC_11, amp[441]);
+ FFV1_0(w[63], w[123], w[6], pars->GC_11, amp[442]);
+ FFV1_0(w[63], w[121], w[5], pars->GC_11, amp[443]);
+ FFV1_0(w[124], w[116], w[7], pars->GC_11, amp[444]);
+ FFV1_0(w[63], w[116], w[41], pars->GC_11, amp[445]);
+ FFV1_0(w[60], w[116], w[43], pars->GC_11, amp[446]);
+ FFV1_0(w[64], w[125], w[7], pars->GC_11, amp[447]);
+ FFV1_0(w[64], w[2], w[43], pars->GC_11, amp[448]);
+ FFV1_0(w[63], w[125], w[8], pars->GC_2, amp[449]);
+ FFV1_0(w[124], w[120], w[7], pars->GC_11, amp[450]);
+ FFV1_0(w[63], w[120], w[41], pars->GC_11, amp[451]);
+ FFV1_0(w[60], w[120], w[43], pars->GC_11, amp[452]);
+ FFV1_0(w[66], w[125], w[7], pars->GC_11, amp[453]);
+ FFV1_0(w[66], w[2], w[43], pars->GC_11, amp[454]);
+ FFV2_5_0(w[63], w[125], w[17], pars->GC_51, pars->GC_58, amp[455]);
+ FFV1_0(w[126], w[116], w[6], pars->GC_11, amp[456]);
+ FFV1_0(w[62], w[116], w[35], pars->GC_11, amp[457]);
+ FFV1_0(w[60], w[116], w[46], pars->GC_11, amp[458]);
+ FFV1_0(w[64], w[127], w[6], pars->GC_11, amp[459]);
+ FFV1_0(w[64], w[2], w[46], pars->GC_11, amp[460]);
+ FFV1_0(w[62], w[127], w[8], pars->GC_2, amp[461]);
+ FFV1_0(w[126], w[120], w[6], pars->GC_11, amp[462]);
+ FFV1_0(w[62], w[120], w[35], pars->GC_11, amp[463]);
+ FFV1_0(w[60], w[120], w[46], pars->GC_11, amp[464]);
+ FFV1_0(w[66], w[127], w[6], pars->GC_11, amp[465]);
+ FFV1_0(w[66], w[2], w[46], pars->GC_11, amp[466]);
+ FFV2_5_0(w[62], w[127], w[17], pars->GC_51, pars->GC_58, amp[467]);
+ FFV1_0(w[87], w[116], w[29], pars->GC_11, amp[468]);
+ FFV1_0(w[128], w[116], w[5], pars->GC_11, amp[469]);
+ FFV1_0(w[60], w[116], w[49], pars->GC_11, amp[470]);
+ FFV1_0(w[64], w[129], w[5], pars->GC_11, amp[471]);
+ FFV1_0(w[64], w[2], w[49], pars->GC_11, amp[472]);
+ FFV1_0(w[87], w[129], w[8], pars->GC_2, amp[473]);
+ FFV1_0(w[87], w[120], w[29], pars->GC_11, amp[474]);
+ FFV1_0(w[128], w[120], w[5], pars->GC_11, amp[475]);
+ FFV1_0(w[60], w[120], w[49], pars->GC_11, amp[476]);
+ FFV1_0(w[66], w[129], w[5], pars->GC_11, amp[477]);
+ FFV1_0(w[66], w[2], w[49], pars->GC_11, amp[478]);
+ FFV2_5_0(w[87], w[129], w[17], pars->GC_51, pars->GC_58, amp[479]);
+ FFV1_0(w[60], w[116], w[51], pars->GC_11, amp[480]);
+ FFV1_0(w[60], w[116], w[52], pars->GC_11, amp[481]);
+ FFV1_0(w[60], w[116], w[53], pars->GC_11, amp[482]);
+ FFV1_0(w[64], w[2], w[51], pars->GC_11, amp[483]);
+ FFV1_0(w[64], w[2], w[52], pars->GC_11, amp[484]);
+ FFV1_0(w[64], w[2], w[53], pars->GC_11, amp[485]);
+ FFV1_0(w[60], w[120], w[51], pars->GC_11, amp[486]);
+ FFV1_0(w[60], w[120], w[52], pars->GC_11, amp[487]);
+ FFV1_0(w[60], w[120], w[53], pars->GC_11, amp[488]);
+ FFV1_0(w[66], w[2], w[51], pars->GC_11, amp[489]);
+ FFV1_0(w[66], w[2], w[52], pars->GC_11, amp[490]);
+ FFV1_0(w[66], w[2], w[53], pars->GC_11, amp[491]);
+ FFV1_0(w[89], w[117], w[7], pars->GC_11, amp[492]);
+ FFV1_0(w[89], w[118], w[6], pars->GC_11, amp[493]);
+ FFV1_0(w[24], w[130], w[7], pars->GC_11, amp[494]);
+ FFV1_0(w[24], w[118], w[4], pars->GC_11, amp[495]);
+ FFV1_0(w[25], w[130], w[6], pars->GC_11, amp[496]);
+ FFV1_0(w[25], w[117], w[4], pars->GC_11, amp[497]);
+ FFV1_0(w[89], w[121], w[7], pars->GC_11, amp[498]);
+ FFV1_0(w[89], w[122], w[6], pars->GC_11, amp[499]);
+ FFV1_0(w[24], w[131], w[7], pars->GC_11, amp[500]);
+ FFV1_0(w[24], w[122], w[4], pars->GC_11, amp[501]);
+ FFV1_0(w[25], w[131], w[6], pars->GC_11, amp[502]);
+ FFV1_0(w[25], w[121], w[4], pars->GC_11, amp[503]);
+ FFV1_0(w[132], w[116], w[7], pars->GC_11, amp[504]);
+ FFV1_0(w[25], w[116], w[70], pars->GC_11, amp[505]);
+ FFV1_0(w[22], w[116], w[72], pars->GC_11, amp[506]);
+ FFV1_0(w[26], w[133], w[7], pars->GC_11, amp[507]);
+ FFV1_0(w[26], w[2], w[72], pars->GC_11, amp[508]);
+ FFV1_0(w[25], w[133], w[8], pars->GC_2, amp[509]);
+ FFV1_0(w[132], w[120], w[7], pars->GC_11, amp[510]);
+ FFV1_0(w[25], w[120], w[70], pars->GC_11, amp[511]);
+ FFV1_0(w[22], w[120], w[72], pars->GC_11, amp[512]);
+ FFV1_0(w[28], w[133], w[7], pars->GC_11, amp[513]);
+ FFV1_0(w[28], w[2], w[72], pars->GC_11, amp[514]);
+ FFV2_5_0(w[25], w[133], w[17], pars->GC_51, pars->GC_58, amp[515]);
+ FFV1_0(w[134], w[116], w[6], pars->GC_11, amp[516]);
+ FFV1_0(w[24], w[116], w[68], pars->GC_11, amp[517]);
+ FFV1_0(w[22], w[116], w[75], pars->GC_11, amp[518]);
+ FFV1_0(w[26], w[135], w[6], pars->GC_11, amp[519]);
+ FFV1_0(w[26], w[2], w[75], pars->GC_11, amp[520]);
+ FFV1_0(w[24], w[135], w[8], pars->GC_2, amp[521]);
+ FFV1_0(w[134], w[120], w[6], pars->GC_11, amp[522]);
+ FFV1_0(w[24], w[120], w[68], pars->GC_11, amp[523]);
+ FFV1_0(w[22], w[120], w[75], pars->GC_11, amp[524]);
+ FFV1_0(w[28], w[135], w[6], pars->GC_11, amp[525]);
+ FFV1_0(w[28], w[2], w[75], pars->GC_11, amp[526]);
+ FFV2_5_0(w[24], w[135], w[17], pars->GC_51, pars->GC_58, amp[527]);
+ FFV1_0(w[89], w[116], w[29], pars->GC_11, amp[528]);
+ FFV1_0(w[136], w[116], w[4], pars->GC_11, amp[529]);
+ FFV1_0(w[22], w[116], w[77], pars->GC_11, amp[530]);
+ FFV1_0(w[26], w[129], w[4], pars->GC_11, amp[531]);
+ FFV1_0(w[26], w[2], w[77], pars->GC_11, amp[532]);
+ FFV1_0(w[89], w[129], w[8], pars->GC_2, amp[533]);
+ FFV1_0(w[89], w[120], w[29], pars->GC_11, amp[534]);
+ FFV1_0(w[136], w[120], w[4], pars->GC_11, amp[535]);
+ FFV1_0(w[22], w[120], w[77], pars->GC_11, amp[536]);
+ FFV1_0(w[28], w[129], w[4], pars->GC_11, amp[537]);
+ FFV1_0(w[28], w[2], w[77], pars->GC_11, amp[538]);
+ FFV2_5_0(w[89], w[129], w[17], pars->GC_51, pars->GC_58, amp[539]);
+ FFV1_0(w[22], w[116], w[79], pars->GC_11, amp[540]);
+ FFV1_0(w[22], w[116], w[80], pars->GC_11, amp[541]);
+ FFV1_0(w[22], w[116], w[81], pars->GC_11, amp[542]);
+ FFV1_0(w[26], w[2], w[79], pars->GC_11, amp[543]);
+ FFV1_0(w[26], w[2], w[80], pars->GC_11, amp[544]);
+ FFV1_0(w[26], w[2], w[81], pars->GC_11, amp[545]);
+ FFV1_0(w[22], w[120], w[79], pars->GC_11, amp[546]);
+ FFV1_0(w[22], w[120], w[80], pars->GC_11, amp[547]);
+ FFV1_0(w[22], w[120], w[81], pars->GC_11, amp[548]);
+ FFV1_0(w[28], w[2], w[79], pars->GC_11, amp[549]);
+ FFV1_0(w[28], w[2], w[80], pars->GC_11, amp[550]);
+ FFV1_0(w[28], w[2], w[81], pars->GC_11, amp[551]);
+ FFV1_0(w[67], w[119], w[7], pars->GC_11, amp[552]);
+ FFV1_0(w[67], w[118], w[5], pars->GC_11, amp[553]);
+ FFV1_0(w[31], w[130], w[7], pars->GC_11, amp[554]);
+ FFV1_0(w[31], w[118], w[4], pars->GC_11, amp[555]);
+ FFV1_0(w[32], w[130], w[5], pars->GC_11, amp[556]);
+ FFV1_0(w[32], w[119], w[4], pars->GC_11, amp[557]);
+ FFV1_0(w[67], w[123], w[7], pars->GC_11, amp[558]);
+ FFV1_0(w[67], w[122], w[5], pars->GC_11, amp[559]);
+ FFV1_0(w[31], w[131], w[7], pars->GC_11, amp[560]);
+ FFV1_0(w[31], w[122], w[4], pars->GC_11, amp[561]);
+ FFV1_0(w[32], w[131], w[5], pars->GC_11, amp[562]);
+ FFV1_0(w[32], w[123], w[4], pars->GC_11, amp[563]);
+ FFV1_0(w[137], w[116], w[7], pars->GC_11, amp[564]);
+ FFV1_0(w[32], w[116], w[90], pars->GC_11, amp[565]);
+ FFV1_0(w[30], w[116], w[92], pars->GC_11, amp[566]);
+ FFV1_0(w[33], w[138], w[7], pars->GC_11, amp[567]);
+ FFV1_0(w[33], w[2], w[92], pars->GC_11, amp[568]);
+ FFV1_0(w[32], w[138], w[8], pars->GC_2, amp[569]);
+ FFV1_0(w[137], w[120], w[7], pars->GC_11, amp[570]);
+ FFV1_0(w[32], w[120], w[90], pars->GC_11, amp[571]);
+ FFV1_0(w[30], w[120], w[92], pars->GC_11, amp[572]);
+ FFV1_0(w[34], w[138], w[7], pars->GC_11, amp[573]);
+ FFV1_0(w[34], w[2], w[92], pars->GC_11, amp[574]);
+ FFV2_5_0(w[32], w[138], w[17], pars->GC_51, pars->GC_58, amp[575]);
+ FFV1_0(w[139], w[116], w[5], pars->GC_11, amp[576]);
+ FFV1_0(w[31], w[116], w[68], pars->GC_11, amp[577]);
+ FFV1_0(w[30], w[116], w[94], pars->GC_11, amp[578]);
+ FFV1_0(w[33], w[135], w[5], pars->GC_11, amp[579]);
+ FFV1_0(w[33], w[2], w[94], pars->GC_11, amp[580]);
+ FFV1_0(w[31], w[135], w[8], pars->GC_2, amp[581]);
+ FFV1_0(w[139], w[120], w[5], pars->GC_11, amp[582]);
+ FFV1_0(w[31], w[120], w[68], pars->GC_11, amp[583]);
+ FFV1_0(w[30], w[120], w[94], pars->GC_11, amp[584]);
+ FFV1_0(w[34], w[135], w[5], pars->GC_11, amp[585]);
+ FFV1_0(w[34], w[2], w[94], pars->GC_11, amp[586]);
+ FFV2_5_0(w[31], w[135], w[17], pars->GC_51, pars->GC_58, amp[587]);
+ FFV1_0(w[67], w[116], w[35], pars->GC_11, amp[588]);
+ FFV1_0(w[140], w[116], w[4], pars->GC_11, amp[589]);
+ FFV1_0(w[30], w[116], w[96], pars->GC_11, amp[590]);
+ FFV1_0(w[33], w[127], w[4], pars->GC_11, amp[591]);
+ FFV1_0(w[33], w[2], w[96], pars->GC_11, amp[592]);
+ FFV1_0(w[67], w[127], w[8], pars->GC_2, amp[593]);
+ FFV1_0(w[67], w[120], w[35], pars->GC_11, amp[594]);
+ FFV1_0(w[140], w[120], w[4], pars->GC_11, amp[595]);
+ FFV1_0(w[30], w[120], w[96], pars->GC_11, amp[596]);
+ FFV1_0(w[34], w[127], w[4], pars->GC_11, amp[597]);
+ FFV1_0(w[34], w[2], w[96], pars->GC_11, amp[598]);
+ FFV2_5_0(w[67], w[127], w[17], pars->GC_51, pars->GC_58, amp[599]);
+ FFV1_0(w[30], w[116], w[98], pars->GC_11, amp[600]);
+ FFV1_0(w[30], w[116], w[99], pars->GC_11, amp[601]);
+ FFV1_0(w[30], w[116], w[100], pars->GC_11, amp[602]);
+ FFV1_0(w[33], w[2], w[98], pars->GC_11, amp[603]);
+ FFV1_0(w[33], w[2], w[99], pars->GC_11, amp[604]);
+ FFV1_0(w[33], w[2], w[100], pars->GC_11, amp[605]);
+ FFV1_0(w[30], w[120], w[98], pars->GC_11, amp[606]);
+ FFV1_0(w[30], w[120], w[99], pars->GC_11, amp[607]);
+ FFV1_0(w[30], w[120], w[100], pars->GC_11, amp[608]);
+ FFV1_0(w[34], w[2], w[98], pars->GC_11, amp[609]);
+ FFV1_0(w[34], w[2], w[99], pars->GC_11, amp[610]);
+ FFV1_0(w[34], w[2], w[100], pars->GC_11, amp[611]);
+ FFV1_0(w[69], w[119], w[6], pars->GC_11, amp[612]);
+ FFV1_0(w[69], w[117], w[5], pars->GC_11, amp[613]);
+ FFV1_0(w[37], w[130], w[6], pars->GC_11, amp[614]);
+ FFV1_0(w[37], w[117], w[4], pars->GC_11, amp[615]);
+ FFV1_0(w[38], w[130], w[5], pars->GC_11, amp[616]);
+ FFV1_0(w[38], w[119], w[4], pars->GC_11, amp[617]);
+ FFV1_0(w[69], w[123], w[6], pars->GC_11, amp[618]);
+ FFV1_0(w[69], w[121], w[5], pars->GC_11, amp[619]);
+ FFV1_0(w[37], w[131], w[6], pars->GC_11, amp[620]);
+ FFV1_0(w[37], w[121], w[4], pars->GC_11, amp[621]);
+ FFV1_0(w[38], w[131], w[5], pars->GC_11, amp[622]);
+ FFV1_0(w[38], w[123], w[4], pars->GC_11, amp[623]);
+ FFV1_0(w[141], w[116], w[6], pars->GC_11, amp[624]);
+ FFV1_0(w[38], w[116], w[90], pars->GC_11, amp[625]);
+ FFV1_0(w[36], w[116], w[107], pars->GC_11, amp[626]);
+ FFV1_0(w[39], w[138], w[6], pars->GC_11, amp[627]);
+ FFV1_0(w[39], w[2], w[107], pars->GC_11, amp[628]);
+ FFV1_0(w[38], w[138], w[8], pars->GC_2, amp[629]);
+ FFV1_0(w[141], w[120], w[6], pars->GC_11, amp[630]);
+ FFV1_0(w[38], w[120], w[90], pars->GC_11, amp[631]);
+ FFV1_0(w[36], w[120], w[107], pars->GC_11, amp[632]);
+ FFV1_0(w[40], w[138], w[6], pars->GC_11, amp[633]);
+ FFV1_0(w[40], w[2], w[107], pars->GC_11, amp[634]);
+ FFV2_5_0(w[38], w[138], w[17], pars->GC_51, pars->GC_58, amp[635]);
+ FFV1_0(w[142], w[116], w[5], pars->GC_11, amp[636]);
+ FFV1_0(w[37], w[116], w[70], pars->GC_11, amp[637]);
+ FFV1_0(w[36], w[116], w[109], pars->GC_11, amp[638]);
+ FFV1_0(w[39], w[133], w[5], pars->GC_11, amp[639]);
+ FFV1_0(w[39], w[2], w[109], pars->GC_11, amp[640]);
+ FFV1_0(w[37], w[133], w[8], pars->GC_2, amp[641]);
+ FFV1_0(w[142], w[120], w[5], pars->GC_11, amp[642]);
+ FFV1_0(w[37], w[120], w[70], pars->GC_11, amp[643]);
+ FFV1_0(w[36], w[120], w[109], pars->GC_11, amp[644]);
+ FFV1_0(w[40], w[133], w[5], pars->GC_11, amp[645]);
+ FFV1_0(w[40], w[2], w[109], pars->GC_11, amp[646]);
+ FFV2_5_0(w[37], w[133], w[17], pars->GC_51, pars->GC_58, amp[647]);
+ FFV1_0(w[69], w[116], w[41], pars->GC_11, amp[648]);
+ FFV1_0(w[143], w[116], w[4], pars->GC_11, amp[649]);
+ FFV1_0(w[36], w[116], w[111], pars->GC_11, amp[650]);
+ FFV1_0(w[39], w[125], w[4], pars->GC_11, amp[651]);
+ FFV1_0(w[39], w[2], w[111], pars->GC_11, amp[652]);
+ FFV1_0(w[69], w[125], w[8], pars->GC_2, amp[653]);
+ FFV1_0(w[69], w[120], w[41], pars->GC_11, amp[654]);
+ FFV1_0(w[143], w[120], w[4], pars->GC_11, amp[655]);
+ FFV1_0(w[36], w[120], w[111], pars->GC_11, amp[656]);
+ FFV1_0(w[40], w[125], w[4], pars->GC_11, amp[657]);
+ FFV1_0(w[40], w[2], w[111], pars->GC_11, amp[658]);
+ FFV2_5_0(w[69], w[125], w[17], pars->GC_51, pars->GC_58, amp[659]);
+ FFV1_0(w[36], w[116], w[113], pars->GC_11, amp[660]);
+ FFV1_0(w[36], w[116], w[114], pars->GC_11, amp[661]);
+ FFV1_0(w[36], w[116], w[115], pars->GC_11, amp[662]);
+ FFV1_0(w[39], w[2], w[113], pars->GC_11, amp[663]);
+ FFV1_0(w[39], w[2], w[114], pars->GC_11, amp[664]);
+ FFV1_0(w[39], w[2], w[115], pars->GC_11, amp[665]);
+ FFV1_0(w[36], w[120], w[113], pars->GC_11, amp[666]);
+ FFV1_0(w[36], w[120], w[114], pars->GC_11, amp[667]);
+ FFV1_0(w[36], w[120], w[115], pars->GC_11, amp[668]);
+ FFV1_0(w[40], w[2], w[113], pars->GC_11, amp[669]);
+ FFV1_0(w[40], w[2], w[114], pars->GC_11, amp[670]);
+ FFV1_0(w[40], w[2], w[115], pars->GC_11, amp[671]);
+ FFV1_0(w[91], w[117], w[7], pars->GC_11, amp[672]);
+ FFV1_0(w[91], w[118], w[6], pars->GC_11, amp[673]);
+ VVV1_0(w[107], w[7], w[144], pars->GC_10, amp[674]);
+ FFV1_0(w[3], w[118], w[107], pars->GC_11, amp[675]);
+ VVV1_0(w[92], w[6], w[144], pars->GC_10, amp[676]);
+ FFV1_0(w[3], w[117], w[92], pars->GC_11, amp[677]);
+ FFV1_0(w[3], w[116], w[145], pars->GC_11, amp[678]);
+ FFV1_0(w[3], w[116], w[146], pars->GC_11, amp[679]);
+ FFV1_0(w[3], w[116], w[147], pars->GC_11, amp[680]);
+ FFV1_0(w[12], w[138], w[7], pars->GC_11, amp[681]);
+ FFV1_0(w[13], w[138], w[6], pars->GC_11, amp[682]);
+ VVV1_0(w[107], w[7], w[148], pars->GC_10, amp[683]);
+ FFV1_0(w[13], w[2], w[107], pars->GC_11, amp[684]);
+ VVV1_0(w[92], w[6], w[148], pars->GC_10, amp[685]);
+ FFV1_0(w[12], w[2], w[92], pars->GC_11, amp[686]);
+ FFV1_0(w[10], w[2], w[145], pars->GC_11, amp[687]);
+ FFV1_0(w[10], w[2], w[146], pars->GC_11, amp[688]);
+ FFV1_0(w[10], w[2], w[147], pars->GC_11, amp[689]);
+ FFV1_0(w[91], w[121], w[7], pars->GC_11, amp[690]);
+ FFV1_0(w[91], w[122], w[6], pars->GC_11, amp[691]);
+ VVV1_0(w[107], w[7], w[149], pars->GC_10, amp[692]);
+ FFV1_0(w[3], w[122], w[107], pars->GC_11, amp[693]);
+ VVV1_0(w[92], w[6], w[149], pars->GC_10, amp[694]);
+ FFV1_0(w[3], w[121], w[92], pars->GC_11, amp[695]);
+ FFV1_0(w[3], w[120], w[145], pars->GC_11, amp[696]);
+ FFV1_0(w[3], w[120], w[146], pars->GC_11, amp[697]);
+ FFV1_0(w[3], w[120], w[147], pars->GC_11, amp[698]);
+ FFV1_0(w[19], w[138], w[7], pars->GC_11, amp[699]);
+ FFV1_0(w[20], w[138], w[6], pars->GC_11, amp[700]);
+ VVV1_0(w[107], w[7], w[150], pars->GC_10, amp[701]);
+ FFV1_0(w[20], w[2], w[107], pars->GC_11, amp[702]);
+ VVV1_0(w[92], w[6], w[150], pars->GC_10, amp[703]);
+ FFV1_0(w[19], w[2], w[92], pars->GC_11, amp[704]);
+ FFV1_0(w[18], w[2], w[145], pars->GC_11, amp[705]);
+ FFV1_0(w[18], w[2], w[146], pars->GC_11, amp[706]);
+ FFV1_0(w[18], w[2], w[147], pars->GC_11, amp[707]);
+ FFV1_0(w[91], w[116], w[29], pars->GC_11, amp[708]);
+ FFV1_0(w[48], w[116], w[90], pars->GC_11, amp[709]);
+ FFV1_0(w[3], w[116], w[151], pars->GC_11, amp[710]);
+ FFV1_0(w[10], w[138], w[29], pars->GC_11, amp[711]);
+ FFV1_0(w[10], w[129], w[90], pars->GC_11, amp[712]);
+ FFV1_0(w[10], w[2], w[151], pars->GC_11, amp[713]);
+ FFV1_0(w[48], w[138], w[8], pars->GC_2, amp[714]);
+ FFV1_0(w[91], w[129], w[8], pars->GC_2, amp[715]);
+ FFV1_0(w[91], w[120], w[29], pars->GC_11, amp[716]);
+ FFV1_0(w[48], w[120], w[90], pars->GC_11, amp[717]);
+ FFV1_0(w[3], w[120], w[151], pars->GC_11, amp[718]);
+ FFV1_0(w[18], w[138], w[29], pars->GC_11, amp[719]);
+ FFV1_0(w[18], w[129], w[90], pars->GC_11, amp[720]);
+ FFV1_0(w[18], w[2], w[151], pars->GC_11, amp[721]);
+ FFV2_5_0(w[48], w[138], w[17], pars->GC_51, pars->GC_58, amp[722]);
+ FFV2_5_0(w[91], w[129], w[17], pars->GC_51, pars->GC_58, amp[723]);
+ FFV1_0(w[71], w[119], w[7], pars->GC_11, amp[724]);
+ FFV1_0(w[71], w[118], w[5], pars->GC_11, amp[725]);
+ VVV1_0(w[109], w[7], w[144], pars->GC_10, amp[726]);
+ FFV1_0(w[3], w[118], w[109], pars->GC_11, amp[727]);
+ VVV1_0(w[72], w[5], w[144], pars->GC_10, amp[728]);
+ FFV1_0(w[3], w[119], w[72], pars->GC_11, amp[729]);
+ FFV1_0(w[3], w[116], w[152], pars->GC_11, amp[730]);
+ FFV1_0(w[3], w[116], w[153], pars->GC_11, amp[731]);
+ FFV1_0(w[3], w[116], w[154], pars->GC_11, amp[732]);
+ FFV1_0(w[15], w[133], w[7], pars->GC_11, amp[733]);
+ FFV1_0(w[13], w[133], w[5], pars->GC_11, amp[734]);
+ VVV1_0(w[109], w[7], w[148], pars->GC_10, amp[735]);
+ FFV1_0(w[13], w[2], w[109], pars->GC_11, amp[736]);
+ VVV1_0(w[72], w[5], w[148], pars->GC_10, amp[737]);
+ FFV1_0(w[15], w[2], w[72], pars->GC_11, amp[738]);
+ FFV1_0(w[10], w[2], w[152], pars->GC_11, amp[739]);
+ FFV1_0(w[10], w[2], w[153], pars->GC_11, amp[740]);
+ FFV1_0(w[10], w[2], w[154], pars->GC_11, amp[741]);
+ FFV1_0(w[71], w[123], w[7], pars->GC_11, amp[742]);
+ FFV1_0(w[71], w[122], w[5], pars->GC_11, amp[743]);
+ VVV1_0(w[109], w[7], w[149], pars->GC_10, amp[744]);
+ FFV1_0(w[3], w[122], w[109], pars->GC_11, amp[745]);
+ VVV1_0(w[72], w[5], w[149], pars->GC_10, amp[746]);
+ FFV1_0(w[3], w[123], w[72], pars->GC_11, amp[747]);
+ FFV1_0(w[3], w[120], w[152], pars->GC_11, amp[748]);
+ FFV1_0(w[3], w[120], w[153], pars->GC_11, amp[749]);
+ FFV1_0(w[3], w[120], w[154], pars->GC_11, amp[750]);
+ FFV1_0(w[21], w[133], w[7], pars->GC_11, amp[751]);
+ FFV1_0(w[20], w[133], w[5], pars->GC_11, amp[752]);
+ VVV1_0(w[109], w[7], w[150], pars->GC_10, amp[753]);
+ FFV1_0(w[20], w[2], w[109], pars->GC_11, amp[754]);
+ VVV1_0(w[72], w[5], w[150], pars->GC_10, amp[755]);
+ FFV1_0(w[21], w[2], w[72], pars->GC_11, amp[756]);
+ FFV1_0(w[18], w[2], w[152], pars->GC_11, amp[757]);
+ FFV1_0(w[18], w[2], w[153], pars->GC_11, amp[758]);
+ FFV1_0(w[18], w[2], w[154], pars->GC_11, amp[759]);
+ FFV1_0(w[71], w[116], w[35], pars->GC_11, amp[760]);
+ FFV1_0(w[45], w[116], w[70], pars->GC_11, amp[761]);
+ FFV1_0(w[3], w[116], w[155], pars->GC_11, amp[762]);
+ FFV1_0(w[10], w[133], w[35], pars->GC_11, amp[763]);
+ FFV1_0(w[10], w[127], w[70], pars->GC_11, amp[764]);
+ FFV1_0(w[10], w[2], w[155], pars->GC_11, amp[765]);
+ FFV1_0(w[45], w[133], w[8], pars->GC_2, amp[766]);
+ FFV1_0(w[71], w[127], w[8], pars->GC_2, amp[767]);
+ FFV1_0(w[71], w[120], w[35], pars->GC_11, amp[768]);
+ FFV1_0(w[45], w[120], w[70], pars->GC_11, amp[769]);
+ FFV1_0(w[3], w[120], w[155], pars->GC_11, amp[770]);
+ FFV1_0(w[18], w[133], w[35], pars->GC_11, amp[771]);
+ FFV1_0(w[18], w[127], w[70], pars->GC_11, amp[772]);
+ FFV1_0(w[18], w[2], w[155], pars->GC_11, amp[773]);
+ FFV2_5_0(w[45], w[133], w[17], pars->GC_51, pars->GC_58, amp[774]);
+ FFV2_5_0(w[71], w[127], w[17], pars->GC_51, pars->GC_58, amp[775]);
+ FFV1_0(w[74], w[119], w[6], pars->GC_11, amp[776]);
+ FFV1_0(w[74], w[117], w[5], pars->GC_11, amp[777]);
+ VVV1_0(w[94], w[6], w[144], pars->GC_10, amp[778]);
+ FFV1_0(w[3], w[117], w[94], pars->GC_11, amp[779]);
+ VVV1_0(w[75], w[5], w[144], pars->GC_10, amp[780]);
+ FFV1_0(w[3], w[119], w[75], pars->GC_11, amp[781]);
+ FFV1_0(w[3], w[116], w[156], pars->GC_11, amp[782]);
+ FFV1_0(w[3], w[116], w[157], pars->GC_11, amp[783]);
+ FFV1_0(w[3], w[116], w[158], pars->GC_11, amp[784]);
+ FFV1_0(w[15], w[135], w[6], pars->GC_11, amp[785]);
+ FFV1_0(w[12], w[135], w[5], pars->GC_11, amp[786]);
+ VVV1_0(w[94], w[6], w[148], pars->GC_10, amp[787]);
+ FFV1_0(w[12], w[2], w[94], pars->GC_11, amp[788]);
+ VVV1_0(w[75], w[5], w[148], pars->GC_10, amp[789]);
+ FFV1_0(w[15], w[2], w[75], pars->GC_11, amp[790]);
+ FFV1_0(w[10], w[2], w[156], pars->GC_11, amp[791]);
+ FFV1_0(w[10], w[2], w[157], pars->GC_11, amp[792]);
+ FFV1_0(w[10], w[2], w[158], pars->GC_11, amp[793]);
+ FFV1_0(w[74], w[123], w[6], pars->GC_11, amp[794]);
+ FFV1_0(w[74], w[121], w[5], pars->GC_11, amp[795]);
+ VVV1_0(w[94], w[6], w[149], pars->GC_10, amp[796]);
+ FFV1_0(w[3], w[121], w[94], pars->GC_11, amp[797]);
+ VVV1_0(w[75], w[5], w[149], pars->GC_10, amp[798]);
+ FFV1_0(w[3], w[123], w[75], pars->GC_11, amp[799]);
+ FFV1_0(w[3], w[120], w[156], pars->GC_11, amp[800]);
+ FFV1_0(w[3], w[120], w[157], pars->GC_11, amp[801]);
+ FFV1_0(w[3], w[120], w[158], pars->GC_11, amp[802]);
+ FFV1_0(w[21], w[135], w[6], pars->GC_11, amp[803]);
+ FFV1_0(w[19], w[135], w[5], pars->GC_11, amp[804]);
+ VVV1_0(w[94], w[6], w[150], pars->GC_10, amp[805]);
+ FFV1_0(w[19], w[2], w[94], pars->GC_11, amp[806]);
+ VVV1_0(w[75], w[5], w[150], pars->GC_10, amp[807]);
+ FFV1_0(w[21], w[2], w[75], pars->GC_11, amp[808]);
+ FFV1_0(w[18], w[2], w[156], pars->GC_11, amp[809]);
+ FFV1_0(w[18], w[2], w[157], pars->GC_11, amp[810]);
+ FFV1_0(w[18], w[2], w[158], pars->GC_11, amp[811]);
+ FFV1_0(w[74], w[116], w[41], pars->GC_11, amp[812]);
+ FFV1_0(w[42], w[116], w[68], pars->GC_11, amp[813]);
+ FFV1_0(w[3], w[116], w[159], pars->GC_11, amp[814]);
+ FFV1_0(w[10], w[135], w[41], pars->GC_11, amp[815]);
+ FFV1_0(w[10], w[125], w[68], pars->GC_11, amp[816]);
+ FFV1_0(w[10], w[2], w[159], pars->GC_11, amp[817]);
+ FFV1_0(w[42], w[135], w[8], pars->GC_2, amp[818]);
+ FFV1_0(w[74], w[125], w[8], pars->GC_2, amp[819]);
+ FFV1_0(w[74], w[120], w[41], pars->GC_11, amp[820]);
+ FFV1_0(w[42], w[120], w[68], pars->GC_11, amp[821]);
+ FFV1_0(w[3], w[120], w[159], pars->GC_11, amp[822]);
+ FFV1_0(w[18], w[135], w[41], pars->GC_11, amp[823]);
+ FFV1_0(w[18], w[125], w[68], pars->GC_11, amp[824]);
+ FFV1_0(w[18], w[2], w[159], pars->GC_11, amp[825]);
+ FFV2_5_0(w[42], w[135], w[17], pars->GC_51, pars->GC_58, amp[826]);
+ FFV2_5_0(w[74], w[125], w[17], pars->GC_51, pars->GC_58, amp[827]);
+ FFV1_0(w[42], w[130], w[7], pars->GC_11, amp[828]);
+ FFV1_0(w[42], w[118], w[4], pars->GC_11, amp[829]);
+ VVV1_0(w[111], w[7], w[144], pars->GC_10, amp[830]);
+ FFV1_0(w[3], w[118], w[111], pars->GC_11, amp[831]);
+ VVV1_0(w[4], w[43], w[144], pars->GC_10, amp[832]);
+ FFV1_0(w[3], w[130], w[43], pars->GC_11, amp[833]);
+ FFV1_0(w[3], w[116], w[160], pars->GC_11, amp[834]);
+ FFV1_0(w[3], w[116], w[161], pars->GC_11, amp[835]);
+ FFV1_0(w[3], w[116], w[162], pars->GC_11, amp[836]);
+ FFV1_0(w[57], w[125], w[7], pars->GC_11, amp[837]);
+ FFV1_0(w[13], w[125], w[4], pars->GC_11, amp[838]);
+ VVV1_0(w[111], w[7], w[148], pars->GC_10, amp[839]);
+ FFV1_0(w[13], w[2], w[111], pars->GC_11, amp[840]);
+ VVV1_0(w[4], w[43], w[148], pars->GC_10, amp[841]);
+ FFV1_0(w[57], w[2], w[43], pars->GC_11, amp[842]);
+ FFV1_0(w[10], w[2], w[160], pars->GC_11, amp[843]);
+ FFV1_0(w[10], w[2], w[161], pars->GC_11, amp[844]);
+ FFV1_0(w[10], w[2], w[162], pars->GC_11, amp[845]);
+ FFV1_0(w[42], w[131], w[7], pars->GC_11, amp[846]);
+ FFV1_0(w[42], w[122], w[4], pars->GC_11, amp[847]);
+ VVV1_0(w[111], w[7], w[149], pars->GC_10, amp[848]);
+ FFV1_0(w[3], w[122], w[111], pars->GC_11, amp[849]);
+ VVV1_0(w[4], w[43], w[149], pars->GC_10, amp[850]);
+ FFV1_0(w[3], w[131], w[43], pars->GC_11, amp[851]);
+ FFV1_0(w[3], w[120], w[160], pars->GC_11, amp[852]);
+ FFV1_0(w[3], w[120], w[161], pars->GC_11, amp[853]);
+ FFV1_0(w[3], w[120], w[162], pars->GC_11, amp[854]);
+ FFV1_0(w[59], w[125], w[7], pars->GC_11, amp[855]);
+ FFV1_0(w[20], w[125], w[4], pars->GC_11, amp[856]);
+ VVV1_0(w[111], w[7], w[150], pars->GC_10, amp[857]);
+ FFV1_0(w[20], w[2], w[111], pars->GC_11, amp[858]);
+ VVV1_0(w[4], w[43], w[150], pars->GC_10, amp[859]);
+ FFV1_0(w[59], w[2], w[43], pars->GC_11, amp[860]);
+ FFV1_0(w[18], w[2], w[160], pars->GC_11, amp[861]);
+ FFV1_0(w[18], w[2], w[161], pars->GC_11, amp[862]);
+ FFV1_0(w[18], w[2], w[162], pars->GC_11, amp[863]);
+ FFV1_0(w[45], w[130], w[6], pars->GC_11, amp[864]);
+ FFV1_0(w[45], w[117], w[4], pars->GC_11, amp[865]);
+ VVV1_0(w[96], w[6], w[144], pars->GC_10, amp[866]);
+ FFV1_0(w[3], w[117], w[96], pars->GC_11, amp[867]);
+ VVV1_0(w[4], w[46], w[144], pars->GC_10, amp[868]);
+ FFV1_0(w[3], w[130], w[46], pars->GC_11, amp[869]);
+ FFV1_0(w[3], w[116], w[163], pars->GC_11, amp[870]);
+ FFV1_0(w[3], w[116], w[164], pars->GC_11, amp[871]);
+ FFV1_0(w[3], w[116], w[165], pars->GC_11, amp[872]);
+ FFV1_0(w[57], w[127], w[6], pars->GC_11, amp[873]);
+ FFV1_0(w[12], w[127], w[4], pars->GC_11, amp[874]);
+ VVV1_0(w[96], w[6], w[148], pars->GC_10, amp[875]);
+ FFV1_0(w[12], w[2], w[96], pars->GC_11, amp[876]);
+ VVV1_0(w[4], w[46], w[148], pars->GC_10, amp[877]);
+ FFV1_0(w[57], w[2], w[46], pars->GC_11, amp[878]);
+ FFV1_0(w[10], w[2], w[163], pars->GC_11, amp[879]);
+ FFV1_0(w[10], w[2], w[164], pars->GC_11, amp[880]);
+ FFV1_0(w[10], w[2], w[165], pars->GC_11, amp[881]);
+ FFV1_0(w[45], w[131], w[6], pars->GC_11, amp[882]);
+ FFV1_0(w[45], w[121], w[4], pars->GC_11, amp[883]);
+ VVV1_0(w[96], w[6], w[149], pars->GC_10, amp[884]);
+ FFV1_0(w[3], w[121], w[96], pars->GC_11, amp[885]);
+ VVV1_0(w[4], w[46], w[149], pars->GC_10, amp[886]);
+ FFV1_0(w[3], w[131], w[46], pars->GC_11, amp[887]);
+ FFV1_0(w[3], w[120], w[163], pars->GC_11, amp[888]);
+ FFV1_0(w[3], w[120], w[164], pars->GC_11, amp[889]);
+ FFV1_0(w[3], w[120], w[165], pars->GC_11, amp[890]);
+ FFV1_0(w[59], w[127], w[6], pars->GC_11, amp[891]);
+ FFV1_0(w[19], w[127], w[4], pars->GC_11, amp[892]);
+ VVV1_0(w[96], w[6], w[150], pars->GC_10, amp[893]);
+ FFV1_0(w[19], w[2], w[96], pars->GC_11, amp[894]);
+ VVV1_0(w[4], w[46], w[150], pars->GC_10, amp[895]);
+ FFV1_0(w[59], w[2], w[46], pars->GC_11, amp[896]);
+ FFV1_0(w[18], w[2], w[163], pars->GC_11, amp[897]);
+ FFV1_0(w[18], w[2], w[164], pars->GC_11, amp[898]);
+ FFV1_0(w[18], w[2], w[165], pars->GC_11, amp[899]);
+ FFV1_0(w[48], w[130], w[5], pars->GC_11, amp[900]);
+ FFV1_0(w[48], w[119], w[4], pars->GC_11, amp[901]);
+ VVV1_0(w[77], w[5], w[144], pars->GC_10, amp[902]);
+ FFV1_0(w[3], w[119], w[77], pars->GC_11, amp[903]);
+ VVV1_0(w[4], w[49], w[144], pars->GC_10, amp[904]);
+ FFV1_0(w[3], w[130], w[49], pars->GC_11, amp[905]);
+ FFV1_0(w[3], w[116], w[166], pars->GC_11, amp[906]);
+ FFV1_0(w[3], w[116], w[167], pars->GC_11, amp[907]);
+ FFV1_0(w[3], w[116], w[168], pars->GC_11, amp[908]);
+ FFV1_0(w[57], w[129], w[5], pars->GC_11, amp[909]);
+ FFV1_0(w[15], w[129], w[4], pars->GC_11, amp[910]);
+ VVV1_0(w[77], w[5], w[148], pars->GC_10, amp[911]);
+ FFV1_0(w[15], w[2], w[77], pars->GC_11, amp[912]);
+ VVV1_0(w[4], w[49], w[148], pars->GC_10, amp[913]);
+ FFV1_0(w[57], w[2], w[49], pars->GC_11, amp[914]);
+ FFV1_0(w[10], w[2], w[166], pars->GC_11, amp[915]);
+ FFV1_0(w[10], w[2], w[167], pars->GC_11, amp[916]);
+ FFV1_0(w[10], w[2], w[168], pars->GC_11, amp[917]);
+ FFV1_0(w[48], w[131], w[5], pars->GC_11, amp[918]);
+ FFV1_0(w[48], w[123], w[4], pars->GC_11, amp[919]);
+ VVV1_0(w[77], w[5], w[149], pars->GC_10, amp[920]);
+ FFV1_0(w[3], w[123], w[77], pars->GC_11, amp[921]);
+ VVV1_0(w[4], w[49], w[149], pars->GC_10, amp[922]);
+ FFV1_0(w[3], w[131], w[49], pars->GC_11, amp[923]);
+ FFV1_0(w[3], w[120], w[166], pars->GC_11, amp[924]);
+ FFV1_0(w[3], w[120], w[167], pars->GC_11, amp[925]);
+ FFV1_0(w[3], w[120], w[168], pars->GC_11, amp[926]);
+ FFV1_0(w[59], w[129], w[5], pars->GC_11, amp[927]);
+ FFV1_0(w[21], w[129], w[4], pars->GC_11, amp[928]);
+ VVV1_0(w[77], w[5], w[150], pars->GC_10, amp[929]);
+ FFV1_0(w[21], w[2], w[77], pars->GC_11, amp[930]);
+ VVV1_0(w[4], w[49], w[150], pars->GC_10, amp[931]);
+ FFV1_0(w[59], w[2], w[49], pars->GC_11, amp[932]);
+ FFV1_0(w[18], w[2], w[166], pars->GC_11, amp[933]);
+ FFV1_0(w[18], w[2], w[167], pars->GC_11, amp[934]);
+ FFV1_0(w[18], w[2], w[168], pars->GC_11, amp[935]);
+ FFV1_0(w[169], w[116], w[7], pars->GC_11, amp[936]);
+ FFV1_0(w[170], w[116], w[7], pars->GC_11, amp[937]);
+ FFV1_0(w[171], w[116], w[7], pars->GC_11, amp[938]);
+ FFV1_0(w[3], w[116], w[172], pars->GC_11, amp[939]);
+ FFV1_0(w[3], w[116], w[173], pars->GC_11, amp[940]);
+ FFV1_0(w[3], w[116], w[174], pars->GC_11, amp[941]);
+ FFV1_0(w[10], w[175], w[7], pars->GC_11, amp[942]);
+ FFV1_0(w[10], w[176], w[7], pars->GC_11, amp[943]);
+ FFV1_0(w[10], w[177], w[7], pars->GC_11, amp[944]);
+ FFV1_0(w[10], w[2], w[172], pars->GC_11, amp[945]);
+ FFV1_0(w[10], w[2], w[173], pars->GC_11, amp[946]);
+ FFV1_0(w[10], w[2], w[174], pars->GC_11, amp[947]);
+ FFV1_0(w[169], w[120], w[7], pars->GC_11, amp[948]);
+ FFV1_0(w[170], w[120], w[7], pars->GC_11, amp[949]);
+ FFV1_0(w[171], w[120], w[7], pars->GC_11, amp[950]);
+ FFV1_0(w[3], w[120], w[172], pars->GC_11, amp[951]);
+ FFV1_0(w[3], w[120], w[173], pars->GC_11, amp[952]);
+ FFV1_0(w[3], w[120], w[174], pars->GC_11, amp[953]);
+ FFV1_0(w[18], w[175], w[7], pars->GC_11, amp[954]);
+ FFV1_0(w[18], w[176], w[7], pars->GC_11, amp[955]);
+ FFV1_0(w[18], w[177], w[7], pars->GC_11, amp[956]);
+ FFV1_0(w[18], w[2], w[172], pars->GC_11, amp[957]);
+ FFV1_0(w[18], w[2], w[173], pars->GC_11, amp[958]);
+ FFV1_0(w[18], w[2], w[174], pars->GC_11, amp[959]);
+ FFV1_0(w[178], w[116], w[6], pars->GC_11, amp[960]);
+ FFV1_0(w[179], w[116], w[6], pars->GC_11, amp[961]);
+ FFV1_0(w[180], w[116], w[6], pars->GC_11, amp[962]);
+ FFV1_0(w[3], w[116], w[181], pars->GC_11, amp[963]);
+ FFV1_0(w[3], w[116], w[182], pars->GC_11, amp[964]);
+ FFV1_0(w[3], w[116], w[183], pars->GC_11, amp[965]);
+ FFV1_0(w[10], w[184], w[6], pars->GC_11, amp[966]);
+ FFV1_0(w[10], w[185], w[6], pars->GC_11, amp[967]);
+ FFV1_0(w[10], w[186], w[6], pars->GC_11, amp[968]);
+ FFV1_0(w[10], w[2], w[181], pars->GC_11, amp[969]);
+ FFV1_0(w[10], w[2], w[182], pars->GC_11, amp[970]);
+ FFV1_0(w[10], w[2], w[183], pars->GC_11, amp[971]);
+ FFV1_0(w[178], w[120], w[6], pars->GC_11, amp[972]);
+ FFV1_0(w[179], w[120], w[6], pars->GC_11, amp[973]);
+ FFV1_0(w[180], w[120], w[6], pars->GC_11, amp[974]);
+ FFV1_0(w[3], w[120], w[181], pars->GC_11, amp[975]);
+ FFV1_0(w[3], w[120], w[182], pars->GC_11, amp[976]);
+ FFV1_0(w[3], w[120], w[183], pars->GC_11, amp[977]);
+ FFV1_0(w[18], w[184], w[6], pars->GC_11, amp[978]);
+ FFV1_0(w[18], w[185], w[6], pars->GC_11, amp[979]);
+ FFV1_0(w[18], w[186], w[6], pars->GC_11, amp[980]);
+ FFV1_0(w[18], w[2], w[181], pars->GC_11, amp[981]);
+ FFV1_0(w[18], w[2], w[182], pars->GC_11, amp[982]);
+ FFV1_0(w[18], w[2], w[183], pars->GC_11, amp[983]);
+ FFV1_0(w[187], w[116], w[5], pars->GC_11, amp[984]);
+ FFV1_0(w[188], w[116], w[5], pars->GC_11, amp[985]);
+ FFV1_0(w[189], w[116], w[5], pars->GC_11, amp[986]);
+ FFV1_0(w[3], w[116], w[190], pars->GC_11, amp[987]);
+ FFV1_0(w[3], w[116], w[191], pars->GC_11, amp[988]);
+ FFV1_0(w[3], w[116], w[192], pars->GC_11, amp[989]);
+ FFV1_0(w[10], w[193], w[5], pars->GC_11, amp[990]);
+ FFV1_0(w[10], w[194], w[5], pars->GC_11, amp[991]);
+ FFV1_0(w[10], w[195], w[5], pars->GC_11, amp[992]);
+ FFV1_0(w[10], w[2], w[190], pars->GC_11, amp[993]);
+ FFV1_0(w[10], w[2], w[191], pars->GC_11, amp[994]);
+ FFV1_0(w[10], w[2], w[192], pars->GC_11, amp[995]);
+ FFV1_0(w[187], w[120], w[5], pars->GC_11, amp[996]);
+ FFV1_0(w[188], w[120], w[5], pars->GC_11, amp[997]);
+ FFV1_0(w[189], w[120], w[5], pars->GC_11, amp[998]);
+ FFV1_0(w[3], w[120], w[190], pars->GC_11, amp[999]);
+ FFV1_0(w[3], w[120], w[191], pars->GC_11, amp[1000]);
+ FFV1_0(w[3], w[120], w[192], pars->GC_11, amp[1001]);
+ FFV1_0(w[18], w[193], w[5], pars->GC_11, amp[1002]);
+ FFV1_0(w[18], w[194], w[5], pars->GC_11, amp[1003]);
+ FFV1_0(w[18], w[195], w[5], pars->GC_11, amp[1004]);
+ FFV1_0(w[18], w[2], w[190], pars->GC_11, amp[1005]);
+ FFV1_0(w[18], w[2], w[191], pars->GC_11, amp[1006]);
+ FFV1_0(w[18], w[2], w[192], pars->GC_11, amp[1007]);
+ FFV1_0(w[196], w[116], w[4], pars->GC_11, amp[1008]);
+ FFV1_0(w[197], w[116], w[4], pars->GC_11, amp[1009]);
+ FFV1_0(w[198], w[116], w[4], pars->GC_11, amp[1010]);
+ FFV1_0(w[3], w[116], w[199], pars->GC_11, amp[1011]);
+ FFV1_0(w[3], w[116], w[200], pars->GC_11, amp[1012]);
+ FFV1_0(w[3], w[116], w[201], pars->GC_11, amp[1013]);
+ FFV1_0(w[10], w[202], w[4], pars->GC_11, amp[1014]);
+ FFV1_0(w[10], w[203], w[4], pars->GC_11, amp[1015]);
+ FFV1_0(w[10], w[204], w[4], pars->GC_11, amp[1016]);
+ FFV1_0(w[10], w[2], w[199], pars->GC_11, amp[1017]);
+ FFV1_0(w[10], w[2], w[200], pars->GC_11, amp[1018]);
+ FFV1_0(w[10], w[2], w[201], pars->GC_11, amp[1019]);
+ FFV1_0(w[196], w[120], w[4], pars->GC_11, amp[1020]);
+ FFV1_0(w[197], w[120], w[4], pars->GC_11, amp[1021]);
+ FFV1_0(w[198], w[120], w[4], pars->GC_11, amp[1022]);
+ FFV1_0(w[3], w[120], w[199], pars->GC_11, amp[1023]);
+ FFV1_0(w[3], w[120], w[200], pars->GC_11, amp[1024]);
+ FFV1_0(w[3], w[120], w[201], pars->GC_11, amp[1025]);
+ FFV1_0(w[18], w[202], w[4], pars->GC_11, amp[1026]);
+ FFV1_0(w[18], w[203], w[4], pars->GC_11, amp[1027]);
+ FFV1_0(w[18], w[204], w[4], pars->GC_11, amp[1028]);
+ FFV1_0(w[18], w[2], w[199], pars->GC_11, amp[1029]);
+ FFV1_0(w[18], w[2], w[200], pars->GC_11, amp[1030]);
+ FFV1_0(w[18], w[2], w[201], pars->GC_11, amp[1031]);
+
+}
+double eeuugggg::matrix_1_epem_uuxgggg()
+{
+// int i, j;
+ // Local variables
+// const int ngraphs = 1032;
+ const int ncolor = 24;
+ std::complex<double> ztemp;
+ std::complex<double> jamp[ncolor];
+ // The color matrix;
+ //static const double denom[ncolor] = {54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ // 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54};
+ /*static const double cf[ncolor][ncolor] = {{512, -64, -64, 8, 8, 80, -64, 8,
+ 8, -1, -1, -10, 8, -1, 80, -10, 71, 62, -1, -10, -10, 62, 62, -28}, {-64,
+ 512, 8, 80, -64, 8, 8, -64, -1, -10, 8, -1, -1, -10, -10, 62, 62, -28, 8,
+ -1, 80, -10, 71, 62}, {-64, 8, 512, -64, 80, 8, 8, -1, 80, -10, 71, 62,
+ -64, 8, 8, -1, -1, -10, -10, -1, 62, -28, -10, 62}, {8, 80, -64, 512, 8,
+ -64, -1, -10, -10, 62, 62, -28, 8, -64, -1, -10, 8, -1, -1, 8, 71, 62,
+ 80, -10}, {8, -64, 80, 8, 512, -64, -1, 8, 71, 62, 80, -10, -10, -1, 62,
+ -28, -10, 62, -64, 8, 8, -1, -1, -10}, {80, 8, 8, -64, -64, 512, -10, -1,
+ 62, -28, -10, 62, -1, 8, 71, 62, 80, -10, 8, -64, -1, -10, 8, -1}, {-64,
+ 8, 8, -1, -1, -10, 512, -64, -64, 8, 8, 80, 80, -10, 8, -1, 62, 71, -10,
+ 62, -1, -10, -28, 62}, {8, -64, -1, -10, 8, -1, -64, 512, 8, 80, -64, 8,
+ -10, 62, -1, -10, -28, 62, 80, -10, 8, -1, 62, 71}, {8, -1, 80, -10, 71,
+ 62, -64, 8, 512, -64, 80, 8, 8, -1, -64, 8, -10, -1, 62, -28, -10, -1,
+ 62, -10}, {-1, -10, -10, 62, 62, -28, 8, 80, -64, 512, 8, -64, -1, -10,
+ 8, -64, -1, 8, 71, 62, -1, 8, -10, 80}, {-1, 8, 71, 62, 80, -10, 8, -64,
+ 80, 8, 512, -64, 62, -28, -10, -1, 62, -10, 8, -1, -64, 8, -10, -1},
+ {-10, -1, 62, -28, -10, 62, 80, 8, 8, -64, -64, 512, 71, 62, -1, 8, -10,
+ 80, -1, -10, 8, -64, -1, 8}, {8, -1, -64, 8, -10, -1, 80, -10, 8, -1, 62,
+ 71, 512, -64, -64, 8, 8, 80, 62, -10, -28, 62, -1, -10}, {-1, -10, 8,
+ -64, -1, 8, -10, 62, -1, -10, -28, 62, -64, 512, 8, 80, -64, 8, -10, 80,
+ 62, 71, 8, -1}, {80, -10, 8, -1, 62, 71, 8, -1, -64, 8, -10, -1, -64, 8,
+ 512, -64, 80, 8, -28, 62, 62, -10, -10, -1}, {-10, 62, -1, -10, -28, 62,
+ -1, -10, 8, -64, -1, 8, 8, 80, -64, 512, 8, -64, 62, 71, -10, 80, -1, 8},
+ {71, 62, -1, 8, -10, 80, 62, -28, -10, -1, 62, -10, 8, -64, 80, 8, 512,
+ -64, -1, 8, -10, -1, -64, 8}, {62, -28, -10, -1, 62, -10, 71, 62, -1, 8,
+ -10, 80, 80, 8, 8, -64, -64, 512, -10, -1, -1, 8, 8, -64}, {-1, 8, -10,
+ -1, -64, 8, -10, 80, 62, 71, 8, -1, 62, -10, -28, 62, -1, -10, 512, -64,
+ -64, 8, 8, 80}, {-10, -1, -1, 8, 8, -64, 62, -10, -28, 62, -1, -10, -10,
+ 80, 62, 71, 8, -1, -64, 512, 8, 80, -64, 8}, {-10, 80, 62, 71, 8, -1, -1,
+ 8, -10, -1, -64, 8, -28, 62, 62, -10, -10, -1, -64, 8, 512, -64, 80, 8},
+ {62, -10, -28, 62, -1, -10, -10, -1, -1, 8, 8, -64, 62, 71, -10, 80, -1,
+ 8, 8, 80, -64, 512, 8, -64}, {62, 71, -10, 80, -1, 8, -28, 62, 62, -10,
+ -10, -1, -1, 8, -10, -1, -64, 8, 8, -64, 80, 8, 512, -64}, {-28, 62, 62,
+ -10, -10, -1, 62, 71, -10, 80, -1, 8, -10, -1, -1, 8, 8, -64, 80, 8, 8,
+ -64, -64, 512}};
+ */
+
+ // Calculate color flows
+ jamp[0] = +amp[1] + amp[7] + amp[45] + amp[46] + amp[48] + amp[51] + amp[52]
+ + amp[54] - std::complex<double> (0, 1) * amp[56] - std::complex<double>
+ (0, 1) * amp[57] - std::complex<double> (0, 1) * amp[58] -
+ std::complex<double> (0, 1) * amp[59] - amp[61] - std::complex<double>
+ (0, 1) * amp[62] - amp[64] - amp[67] - std::complex<double> (0, 1) *
+ amp[68] - amp[70] - std::complex<double> (0, 1) * amp[84] - amp[85] -
+ std::complex<double> (0, 1) * amp[86] - amp[88] - std::complex<double>
+ (0, 1) * amp[89] - std::complex<double> (0, 1) * amp[90] - amp[91] -
+ std::complex<double> (0, 1) * amp[92] - amp[94] - std::complex<double>
+ (0, 1) * amp[95] + amp[98] - amp[96] + amp[101] - amp[99] + amp[104] -
+ amp[102] + amp[107] - amp[105] + amp[616] + amp[622] -
+ std::complex<double> (0, 1) * amp[625] - amp[626] - std::complex<double>
+ (0, 1) * amp[627] - amp[628] - std::complex<double> (0, 1) * amp[629] -
+ std::complex<double> (0, 1) * amp[631] - amp[632] - std::complex<double>
+ (0, 1) * amp[633] - amp[634] - std::complex<double> (0, 1) * amp[635] -
+ std::complex<double> (0, 1) * amp[649] - amp[650] - amp[652] -
+ std::complex<double> (0, 1) * amp[655] - amp[656] - amp[658] + amp[662] -
+ amp[660] + amp[665] - amp[663] + amp[668] - amp[666] + amp[671] -
+ amp[669] + std::complex<double> (0, 1) * amp[674] - std::complex<double>
+ (0, 1) * amp[680] + std::complex<double> (0, 1) * amp[678] -
+ std::complex<double> (0, 1) * amp[682] + std::complex<double> (0, 1) *
+ amp[683] - amp[684] - std::complex<double> (0, 1) * amp[689] +
+ std::complex<double> (0, 1) * amp[687] + std::complex<double> (0, 1) *
+ amp[692] - std::complex<double> (0, 1) * amp[698] + std::complex<double>
+ (0, 1) * amp[696] - std::complex<double> (0, 1) * amp[700] +
+ std::complex<double> (0, 1) * amp[701] - amp[702] - std::complex<double>
+ (0, 1) * amp[707] + std::complex<double> (0, 1) * amp[705] - amp[709] +
+ std::complex<double> (0, 1) * amp[710] - amp[711] + std::complex<double>
+ (0, 1) * amp[713] - amp[714] - amp[717] + std::complex<double> (0, 1) *
+ amp[718] - amp[719] + std::complex<double> (0, 1) * amp[721] - amp[722] +
+ std::complex<double> (0, 1) * amp[830] + std::complex<double> (0, 1) *
+ amp[832] - amp[833] - std::complex<double> (0, 1) * amp[836] +
+ std::complex<double> (0, 1) * amp[834] + std::complex<double> (0, 1) *
+ amp[839] - amp[840] + std::complex<double> (0, 1) * amp[841] -
+ std::complex<double> (0, 1) * amp[845] + std::complex<double> (0, 1) *
+ amp[843] + std::complex<double> (0, 1) * amp[848] + std::complex<double>
+ (0, 1) * amp[850] - amp[851] - std::complex<double> (0, 1) * amp[854] +
+ std::complex<double> (0, 1) * amp[852] + std::complex<double> (0, 1) *
+ amp[857] - amp[858] + std::complex<double> (0, 1) * amp[859] -
+ std::complex<double> (0, 1) * amp[863] + std::complex<double> (0, 1) *
+ amp[861] - std::complex<double> (0, 1) * amp[900] + std::complex<double>
+ (0, 1) * amp[904] - amp[905] - std::complex<double> (0, 1) * amp[908] +
+ std::complex<double> (0, 1) * amp[906] + std::complex<double> (0, 1) *
+ amp[913] - std::complex<double> (0, 1) * amp[917] + std::complex<double>
+ (0, 1) * amp[915] - std::complex<double> (0, 1) * amp[918] +
+ std::complex<double> (0, 1) * amp[922] - amp[923] - std::complex<double>
+ (0, 1) * amp[926] + std::complex<double> (0, 1) * amp[924] +
+ std::complex<double> (0, 1) * amp[931] - std::complex<double> (0, 1) *
+ amp[935] + std::complex<double> (0, 1) * amp[933] - std::complex<double>
+ (0, 1) * amp[941] + std::complex<double> (0, 1) * amp[939] + amp[944] -
+ amp[942] - std::complex<double> (0, 1) * amp[947] + std::complex<double>
+ (0, 1) * amp[945] - std::complex<double> (0, 1) * amp[953] +
+ std::complex<double> (0, 1) * amp[951] + amp[956] - amp[954] -
+ std::complex<double> (0, 1) * amp[959] + std::complex<double> (0, 1) *
+ amp[957] + amp[1010] - amp[1008] - std::complex<double> (0, 1) *
+ amp[1013] + std::complex<double> (0, 1) * amp[1011] -
+ std::complex<double> (0, 1) * amp[1019] + std::complex<double> (0, 1) *
+ amp[1017] + amp[1022] - amp[1020] - std::complex<double> (0, 1) *
+ amp[1025] + std::complex<double> (0, 1) * amp[1023] -
+ std::complex<double> (0, 1) * amp[1031] + std::complex<double> (0, 1) *
+ amp[1029];
+ jamp[1] = +amp[0] + amp[6] + amp[29] + amp[30] + amp[32] + amp[35] + amp[36]
+ + amp[38] - std::complex<double> (0, 1) * amp[40] - std::complex<double>
+ (0, 1) * amp[41] - std::complex<double> (0, 1) * amp[42] -
+ std::complex<double> (0, 1) * amp[43] - amp[73] - std::complex<double>
+ (0, 1) * amp[74] - amp[76] - amp[79] - std::complex<double> (0, 1) *
+ amp[80] - amp[82] + std::complex<double> (0, 1) * amp[84] + amp[85] +
+ std::complex<double> (0, 1) * amp[86] + amp[88] + std::complex<double>
+ (0, 1) * amp[89] + std::complex<double> (0, 1) * amp[90] + amp[91] +
+ std::complex<double> (0, 1) * amp[92] + amp[94] + std::complex<double>
+ (0, 1) * amp[95] + amp[96] + amp[97] + amp[99] + amp[100] + amp[102] +
+ amp[103] + amp[105] + amp[106] + amp[556] + amp[562] -
+ std::complex<double> (0, 1) * amp[565] - amp[566] - std::complex<double>
+ (0, 1) * amp[567] - amp[568] - std::complex<double> (0, 1) * amp[569] -
+ std::complex<double> (0, 1) * amp[571] - amp[572] - std::complex<double>
+ (0, 1) * amp[573] - amp[574] - std::complex<double> (0, 1) * amp[575] -
+ std::complex<double> (0, 1) * amp[589] - amp[590] - amp[592] -
+ std::complex<double> (0, 1) * amp[595] - amp[596] - amp[598] + amp[602] -
+ amp[600] + amp[605] - amp[603] + amp[608] - amp[606] + amp[611] -
+ amp[609] + std::complex<double> (0, 1) * amp[676] - std::complex<double>
+ (0, 1) * amp[678] - std::complex<double> (0, 1) * amp[679] -
+ std::complex<double> (0, 1) * amp[681] + std::complex<double> (0, 1) *
+ amp[685] - amp[686] - std::complex<double> (0, 1) * amp[687] -
+ std::complex<double> (0, 1) * amp[688] + std::complex<double> (0, 1) *
+ amp[694] - std::complex<double> (0, 1) * amp[696] - std::complex<double>
+ (0, 1) * amp[697] - std::complex<double> (0, 1) * amp[699] +
+ std::complex<double> (0, 1) * amp[703] - amp[704] - std::complex<double>
+ (0, 1) * amp[705] - std::complex<double> (0, 1) * amp[706] + amp[709] -
+ std::complex<double> (0, 1) * amp[710] + amp[711] - std::complex<double>
+ (0, 1) * amp[713] + amp[714] + amp[717] - std::complex<double> (0, 1) *
+ amp[718] + amp[719] - std::complex<double> (0, 1) * amp[721] + amp[722] +
+ std::complex<double> (0, 1) * amp[866] + std::complex<double> (0, 1) *
+ amp[868] - amp[869] - std::complex<double> (0, 1) * amp[872] +
+ std::complex<double> (0, 1) * amp[870] + std::complex<double> (0, 1) *
+ amp[875] - amp[876] + std::complex<double> (0, 1) * amp[877] -
+ std::complex<double> (0, 1) * amp[881] + std::complex<double> (0, 1) *
+ amp[879] + std::complex<double> (0, 1) * amp[884] + std::complex<double>
+ (0, 1) * amp[886] - amp[887] - std::complex<double> (0, 1) * amp[890] +
+ std::complex<double> (0, 1) * amp[888] + std::complex<double> (0, 1) *
+ amp[893] - amp[894] + std::complex<double> (0, 1) * amp[895] -
+ std::complex<double> (0, 1) * amp[899] + std::complex<double> (0, 1) *
+ amp[897] + std::complex<double> (0, 1) * amp[900] - std::complex<double>
+ (0, 1) * amp[904] + amp[905] + std::complex<double> (0, 1) * amp[908] -
+ std::complex<double> (0, 1) * amp[906] - std::complex<double> (0, 1) *
+ amp[913] + std::complex<double> (0, 1) * amp[917] - std::complex<double>
+ (0, 1) * amp[915] + std::complex<double> (0, 1) * amp[918] -
+ std::complex<double> (0, 1) * amp[922] + amp[923] + std::complex<double>
+ (0, 1) * amp[926] - std::complex<double> (0, 1) * amp[924] -
+ std::complex<double> (0, 1) * amp[931] + std::complex<double> (0, 1) *
+ amp[935] - std::complex<double> (0, 1) * amp[933] - std::complex<double>
+ (0, 1) * amp[965] + std::complex<double> (0, 1) * amp[963] + amp[968] -
+ amp[966] - std::complex<double> (0, 1) * amp[971] + std::complex<double>
+ (0, 1) * amp[969] - std::complex<double> (0, 1) * amp[977] +
+ std::complex<double> (0, 1) * amp[975] + amp[980] - amp[978] -
+ std::complex<double> (0, 1) * amp[983] + std::complex<double> (0, 1) *
+ amp[981] + amp[1008] + amp[1009] - std::complex<double> (0, 1) *
+ amp[1011] - std::complex<double> (0, 1) * amp[1012] -
+ std::complex<double> (0, 1) * amp[1017] - std::complex<double> (0, 1) *
+ amp[1018] + amp[1020] + amp[1021] - std::complex<double> (0, 1) *
+ amp[1023] - std::complex<double> (0, 1) * amp[1024] -
+ std::complex<double> (0, 1) * amp[1029] - std::complex<double> (0, 1) *
+ amp[1030];
+ jamp[2] = +amp[3] + amp[9] + amp[44] + amp[47] + amp[49] + amp[50] + amp[53]
+ + amp[55] + std::complex<double> (0, 1) * amp[56] + std::complex<double>
+ (0, 1) * amp[57] + std::complex<double> (0, 1) * amp[58] +
+ std::complex<double> (0, 1) * amp[59] + amp[61] + std::complex<double>
+ (0, 1) * amp[62] + amp[64] + amp[67] + std::complex<double> (0, 1) *
+ amp[68] + amp[70] - std::complex<double> (0, 1) * amp[72] + amp[73] -
+ std::complex<double> (0, 1) * amp[75] + amp[76] - std::complex<double>
+ (0, 1) * amp[77] - std::complex<double> (0, 1) * amp[78] + amp[79] -
+ std::complex<double> (0, 1) * amp[81] + amp[82] - std::complex<double>
+ (0, 1) * amp[83] - amp[98] - amp[97] - amp[101] - amp[100] - amp[104] -
+ amp[103] - amp[107] - amp[106] + amp[614] + amp[620] -
+ std::complex<double> (0, 1) * amp[637] - amp[638] - std::complex<double>
+ (0, 1) * amp[639] - amp[640] - std::complex<double> (0, 1) * amp[641] -
+ std::complex<double> (0, 1) * amp[643] - amp[644] - std::complex<double>
+ (0, 1) * amp[645] - amp[646] - std::complex<double> (0, 1) * amp[647] +
+ std::complex<double> (0, 1) * amp[649] + amp[650] + amp[652] +
+ std::complex<double> (0, 1) * amp[655] + amp[656] + amp[658] + amp[660] +
+ amp[661] + amp[663] + amp[664] + amp[666] + amp[667] + amp[669] +
+ amp[670] + std::complex<double> (0, 1) * amp[726] - std::complex<double>
+ (0, 1) * amp[732] + std::complex<double> (0, 1) * amp[730] -
+ std::complex<double> (0, 1) * amp[734] + std::complex<double> (0, 1) *
+ amp[735] - amp[736] - std::complex<double> (0, 1) * amp[741] +
+ std::complex<double> (0, 1) * amp[739] + std::complex<double> (0, 1) *
+ amp[744] - std::complex<double> (0, 1) * amp[750] + std::complex<double>
+ (0, 1) * amp[748] - std::complex<double> (0, 1) * amp[752] +
+ std::complex<double> (0, 1) * amp[753] - amp[754] - std::complex<double>
+ (0, 1) * amp[759] + std::complex<double> (0, 1) * amp[757] - amp[761] +
+ std::complex<double> (0, 1) * amp[762] - amp[763] + std::complex<double>
+ (0, 1) * amp[765] - amp[766] - amp[769] + std::complex<double> (0, 1) *
+ amp[770] - amp[771] + std::complex<double> (0, 1) * amp[773] - amp[774] -
+ std::complex<double> (0, 1) * amp[830] - std::complex<double> (0, 1) *
+ amp[832] + amp[833] + std::complex<double> (0, 1) * amp[836] -
+ std::complex<double> (0, 1) * amp[834] - std::complex<double> (0, 1) *
+ amp[839] + amp[840] - std::complex<double> (0, 1) * amp[841] +
+ std::complex<double> (0, 1) * amp[845] - std::complex<double> (0, 1) *
+ amp[843] - std::complex<double> (0, 1) * amp[848] - std::complex<double>
+ (0, 1) * amp[850] + amp[851] + std::complex<double> (0, 1) * amp[854] -
+ std::complex<double> (0, 1) * amp[852] - std::complex<double> (0, 1) *
+ amp[857] + amp[858] - std::complex<double> (0, 1) * amp[859] +
+ std::complex<double> (0, 1) * amp[863] - std::complex<double> (0, 1) *
+ amp[861] - std::complex<double> (0, 1) * amp[864] - std::complex<double>
+ (0, 1) * amp[868] + amp[869] - std::complex<double> (0, 1) * amp[870] -
+ std::complex<double> (0, 1) * amp[871] - std::complex<double> (0, 1) *
+ amp[877] - std::complex<double> (0, 1) * amp[879] - std::complex<double>
+ (0, 1) * amp[880] - std::complex<double> (0, 1) * amp[882] -
+ std::complex<double> (0, 1) * amp[886] + amp[887] - std::complex<double>
+ (0, 1) * amp[888] - std::complex<double> (0, 1) * amp[889] -
+ std::complex<double> (0, 1) * amp[895] - std::complex<double> (0, 1) *
+ amp[897] - std::complex<double> (0, 1) * amp[898] - std::complex<double>
+ (0, 1) * amp[939] - std::complex<double> (0, 1) * amp[940] + amp[942] +
+ amp[943] - std::complex<double> (0, 1) * amp[945] - std::complex<double>
+ (0, 1) * amp[946] - std::complex<double> (0, 1) * amp[951] -
+ std::complex<double> (0, 1) * amp[952] + amp[954] + amp[955] -
+ std::complex<double> (0, 1) * amp[957] - std::complex<double> (0, 1) *
+ amp[958] - amp[1010] - amp[1009] + std::complex<double> (0, 1) *
+ amp[1013] + std::complex<double> (0, 1) * amp[1012] +
+ std::complex<double> (0, 1) * amp[1019] + std::complex<double> (0, 1) *
+ amp[1018] - amp[1022] - amp[1021] + std::complex<double> (0, 1) *
+ amp[1025] + std::complex<double> (0, 1) * amp[1024] +
+ std::complex<double> (0, 1) * amp[1031] + std::complex<double> (0, 1) *
+ amp[1030];
+ jamp[3] = +amp[2] + amp[8] + amp[13] + amp[14] + amp[16] + amp[19] + amp[20]
+ + amp[22] - std::complex<double> (0, 1) * amp[24] - std::complex<double>
+ (0, 1) * amp[25] - std::complex<double> (0, 1) * amp[26] -
+ std::complex<double> (0, 1) * amp[27] + std::complex<double> (0, 1) *
+ amp[72] - amp[73] + std::complex<double> (0, 1) * amp[75] - amp[76] +
+ std::complex<double> (0, 1) * amp[77] + std::complex<double> (0, 1) *
+ amp[78] - amp[79] + std::complex<double> (0, 1) * amp[81] - amp[82] +
+ std::complex<double> (0, 1) * amp[83] + amp[85] - std::complex<double>
+ (0, 1) * amp[87] + amp[88] + amp[91] - std::complex<double> (0, 1) *
+ amp[93] + amp[94] + amp[96] + amp[97] + amp[99] + amp[100] + amp[102] +
+ amp[103] + amp[105] + amp[106] + amp[496] + amp[502] -
+ std::complex<double> (0, 1) * amp[505] - amp[506] - std::complex<double>
+ (0, 1) * amp[507] - amp[508] - std::complex<double> (0, 1) * amp[509] -
+ std::complex<double> (0, 1) * amp[511] - amp[512] - std::complex<double>
+ (0, 1) * amp[513] - amp[514] - std::complex<double> (0, 1) * amp[515] -
+ std::complex<double> (0, 1) * amp[529] - amp[530] - amp[532] -
+ std::complex<double> (0, 1) * amp[535] - amp[536] - amp[538] + amp[542] -
+ amp[540] + amp[545] - amp[543] + amp[548] - amp[546] + amp[551] -
+ amp[549] + std::complex<double> (0, 1) * amp[728] - std::complex<double>
+ (0, 1) * amp[730] - std::complex<double> (0, 1) * amp[731] -
+ std::complex<double> (0, 1) * amp[733] + std::complex<double> (0, 1) *
+ amp[737] - amp[738] - std::complex<double> (0, 1) * amp[739] -
+ std::complex<double> (0, 1) * amp[740] + std::complex<double> (0, 1) *
+ amp[746] - std::complex<double> (0, 1) * amp[748] - std::complex<double>
+ (0, 1) * amp[749] - std::complex<double> (0, 1) * amp[751] +
+ std::complex<double> (0, 1) * amp[755] - amp[756] - std::complex<double>
+ (0, 1) * amp[757] - std::complex<double> (0, 1) * amp[758] + amp[761] -
+ std::complex<double> (0, 1) * amp[762] + amp[763] - std::complex<double>
+ (0, 1) * amp[765] + amp[766] + amp[769] - std::complex<double> (0, 1) *
+ amp[770] + amp[771] - std::complex<double> (0, 1) * amp[773] + amp[774] +
+ std::complex<double> (0, 1) * amp[864] + std::complex<double> (0, 1) *
+ amp[868] - amp[869] + std::complex<double> (0, 1) * amp[870] +
+ std::complex<double> (0, 1) * amp[871] + std::complex<double> (0, 1) *
+ amp[877] + std::complex<double> (0, 1) * amp[879] + std::complex<double>
+ (0, 1) * amp[880] + std::complex<double> (0, 1) * amp[882] +
+ std::complex<double> (0, 1) * amp[886] - amp[887] + std::complex<double>
+ (0, 1) * amp[888] + std::complex<double> (0, 1) * amp[889] +
+ std::complex<double> (0, 1) * amp[895] + std::complex<double> (0, 1) *
+ amp[897] + std::complex<double> (0, 1) * amp[898] + std::complex<double>
+ (0, 1) * amp[902] - std::complex<double> (0, 1) * amp[904] + amp[905] -
+ std::complex<double> (0, 1) * amp[906] - std::complex<double> (0, 1) *
+ amp[907] + std::complex<double> (0, 1) * amp[911] - amp[912] -
+ std::complex<double> (0, 1) * amp[913] - std::complex<double> (0, 1) *
+ amp[915] - std::complex<double> (0, 1) * amp[916] + std::complex<double>
+ (0, 1) * amp[920] - std::complex<double> (0, 1) * amp[922] + amp[923] -
+ std::complex<double> (0, 1) * amp[924] - std::complex<double> (0, 1) *
+ amp[925] + std::complex<double> (0, 1) * amp[929] - amp[930] -
+ std::complex<double> (0, 1) * amp[931] - std::complex<double> (0, 1) *
+ amp[933] - std::complex<double> (0, 1) * amp[934] - std::complex<double>
+ (0, 1) * amp[989] + std::complex<double> (0, 1) * amp[987] + amp[992] -
+ amp[990] - std::complex<double> (0, 1) * amp[995] + std::complex<double>
+ (0, 1) * amp[993] - std::complex<double> (0, 1) * amp[1001] +
+ std::complex<double> (0, 1) * amp[999] + amp[1004] - amp[1002] -
+ std::complex<double> (0, 1) * amp[1007] + std::complex<double> (0, 1) *
+ amp[1005] + amp[1008] + amp[1009] - std::complex<double> (0, 1) *
+ amp[1011] - std::complex<double> (0, 1) * amp[1012] -
+ std::complex<double> (0, 1) * amp[1017] - std::complex<double> (0, 1) *
+ amp[1018] + amp[1020] + amp[1021] - std::complex<double> (0, 1) *
+ amp[1023] - std::complex<double> (0, 1) * amp[1024] -
+ std::complex<double> (0, 1) * amp[1029] - std::complex<double> (0, 1) *
+ amp[1030];
+ jamp[4] = +amp[5] + amp[11] + amp[28] + amp[31] + amp[33] + amp[34] + amp[37]
+ + amp[39] + std::complex<double> (0, 1) * amp[40] + std::complex<double>
+ (0, 1) * amp[41] + std::complex<double> (0, 1) * amp[42] +
+ std::complex<double> (0, 1) * amp[43] - std::complex<double> (0, 1) *
+ amp[60] + amp[61] - std::complex<double> (0, 1) * amp[63] + amp[64] -
+ std::complex<double> (0, 1) * amp[65] - std::complex<double> (0, 1) *
+ amp[66] + amp[67] - std::complex<double> (0, 1) * amp[69] + amp[70] -
+ std::complex<double> (0, 1) * amp[71] + amp[73] + std::complex<double>
+ (0, 1) * amp[74] + amp[76] + amp[79] + std::complex<double> (0, 1) *
+ amp[80] + amp[82] - amp[98] - amp[97] - amp[101] - amp[100] - amp[104] -
+ amp[103] - amp[107] - amp[106] + amp[554] + amp[560] -
+ std::complex<double> (0, 1) * amp[577] - amp[578] - std::complex<double>
+ (0, 1) * amp[579] - amp[580] - std::complex<double> (0, 1) * amp[581] -
+ std::complex<double> (0, 1) * amp[583] - amp[584] - std::complex<double>
+ (0, 1) * amp[585] - amp[586] - std::complex<double> (0, 1) * amp[587] +
+ std::complex<double> (0, 1) * amp[589] + amp[590] + amp[592] +
+ std::complex<double> (0, 1) * amp[595] + amp[596] + amp[598] + amp[600] +
+ amp[601] + amp[603] + amp[604] + amp[606] + amp[607] + amp[609] +
+ amp[610] + std::complex<double> (0, 1) * amp[778] - std::complex<double>
+ (0, 1) * amp[784] + std::complex<double> (0, 1) * amp[782] -
+ std::complex<double> (0, 1) * amp[786] + std::complex<double> (0, 1) *
+ amp[787] - amp[788] - std::complex<double> (0, 1) * amp[793] +
+ std::complex<double> (0, 1) * amp[791] + std::complex<double> (0, 1) *
+ amp[796] - std::complex<double> (0, 1) * amp[802] + std::complex<double>
+ (0, 1) * amp[800] - std::complex<double> (0, 1) * amp[804] +
+ std::complex<double> (0, 1) * amp[805] - amp[806] - std::complex<double>
+ (0, 1) * amp[811] + std::complex<double> (0, 1) * amp[809] - amp[813] +
+ std::complex<double> (0, 1) * amp[814] - amp[815] + std::complex<double>
+ (0, 1) * amp[817] - amp[818] - amp[821] + std::complex<double> (0, 1) *
+ amp[822] - amp[823] + std::complex<double> (0, 1) * amp[825] - amp[826] -
+ std::complex<double> (0, 1) * amp[828] - std::complex<double> (0, 1) *
+ amp[832] + amp[833] - std::complex<double> (0, 1) * amp[834] -
+ std::complex<double> (0, 1) * amp[835] - std::complex<double> (0, 1) *
+ amp[841] - std::complex<double> (0, 1) * amp[843] - std::complex<double>
+ (0, 1) * amp[844] - std::complex<double> (0, 1) * amp[846] -
+ std::complex<double> (0, 1) * amp[850] + amp[851] - std::complex<double>
+ (0, 1) * amp[852] - std::complex<double> (0, 1) * amp[853] -
+ std::complex<double> (0, 1) * amp[859] - std::complex<double> (0, 1) *
+ amp[861] - std::complex<double> (0, 1) * amp[862] - std::complex<double>
+ (0, 1) * amp[866] - std::complex<double> (0, 1) * amp[868] + amp[869] +
+ std::complex<double> (0, 1) * amp[872] - std::complex<double> (0, 1) *
+ amp[870] - std::complex<double> (0, 1) * amp[875] + amp[876] -
+ std::complex<double> (0, 1) * amp[877] + std::complex<double> (0, 1) *
+ amp[881] - std::complex<double> (0, 1) * amp[879] - std::complex<double>
+ (0, 1) * amp[884] - std::complex<double> (0, 1) * amp[886] + amp[887] +
+ std::complex<double> (0, 1) * amp[890] - std::complex<double> (0, 1) *
+ amp[888] - std::complex<double> (0, 1) * amp[893] + amp[894] -
+ std::complex<double> (0, 1) * amp[895] + std::complex<double> (0, 1) *
+ amp[899] - std::complex<double> (0, 1) * amp[897] - std::complex<double>
+ (0, 1) * amp[963] - std::complex<double> (0, 1) * amp[964] + amp[966] +
+ amp[967] - std::complex<double> (0, 1) * amp[969] - std::complex<double>
+ (0, 1) * amp[970] - std::complex<double> (0, 1) * amp[975] -
+ std::complex<double> (0, 1) * amp[976] + amp[978] + amp[979] -
+ std::complex<double> (0, 1) * amp[981] - std::complex<double> (0, 1) *
+ amp[982] - amp[1010] - amp[1009] + std::complex<double> (0, 1) *
+ amp[1013] + std::complex<double> (0, 1) * amp[1012] +
+ std::complex<double> (0, 1) * amp[1019] + std::complex<double> (0, 1) *
+ amp[1018] - amp[1022] - amp[1021] + std::complex<double> (0, 1) *
+ amp[1025] + std::complex<double> (0, 1) * amp[1024] +
+ std::complex<double> (0, 1) * amp[1031] + std::complex<double> (0, 1) *
+ amp[1030];
+ jamp[5] = +amp[4] + amp[10] + amp[12] + amp[15] + amp[17] + amp[18] + amp[21]
+ + amp[23] + std::complex<double> (0, 1) * amp[24] + std::complex<double>
+ (0, 1) * amp[25] + std::complex<double> (0, 1) * amp[26] +
+ std::complex<double> (0, 1) * amp[27] + std::complex<double> (0, 1) *
+ amp[60] - amp[61] + std::complex<double> (0, 1) * amp[63] - amp[64] +
+ std::complex<double> (0, 1) * amp[65] + std::complex<double> (0, 1) *
+ amp[66] - amp[67] + std::complex<double> (0, 1) * amp[69] - amp[70] +
+ std::complex<double> (0, 1) * amp[71] - amp[85] + std::complex<double>
+ (0, 1) * amp[87] - amp[88] - amp[91] + std::complex<double> (0, 1) *
+ amp[93] - amp[94] + amp[98] - amp[96] + amp[101] - amp[99] + amp[104] -
+ amp[102] + amp[107] - amp[105] + amp[494] + amp[500] -
+ std::complex<double> (0, 1) * amp[517] - amp[518] - std::complex<double>
+ (0, 1) * amp[519] - amp[520] - std::complex<double> (0, 1) * amp[521] -
+ std::complex<double> (0, 1) * amp[523] - amp[524] - std::complex<double>
+ (0, 1) * amp[525] - amp[526] - std::complex<double> (0, 1) * amp[527] +
+ std::complex<double> (0, 1) * amp[529] + amp[530] + amp[532] +
+ std::complex<double> (0, 1) * amp[535] + amp[536] + amp[538] + amp[540] +
+ amp[541] + amp[543] + amp[544] + amp[546] + amp[547] + amp[549] +
+ amp[550] + std::complex<double> (0, 1) * amp[780] - std::complex<double>
+ (0, 1) * amp[782] - std::complex<double> (0, 1) * amp[783] -
+ std::complex<double> (0, 1) * amp[785] + std::complex<double> (0, 1) *
+ amp[789] - amp[790] - std::complex<double> (0, 1) * amp[791] -
+ std::complex<double> (0, 1) * amp[792] + std::complex<double> (0, 1) *
+ amp[798] - std::complex<double> (0, 1) * amp[800] - std::complex<double>
+ (0, 1) * amp[801] - std::complex<double> (0, 1) * amp[803] +
+ std::complex<double> (0, 1) * amp[807] - amp[808] - std::complex<double>
+ (0, 1) * amp[809] - std::complex<double> (0, 1) * amp[810] + amp[813] -
+ std::complex<double> (0, 1) * amp[814] + amp[815] - std::complex<double>
+ (0, 1) * amp[817] + amp[818] + amp[821] - std::complex<double> (0, 1) *
+ amp[822] + amp[823] - std::complex<double> (0, 1) * amp[825] + amp[826] +
+ std::complex<double> (0, 1) * amp[828] + std::complex<double> (0, 1) *
+ amp[832] - amp[833] + std::complex<double> (0, 1) * amp[834] +
+ std::complex<double> (0, 1) * amp[835] + std::complex<double> (0, 1) *
+ amp[841] + std::complex<double> (0, 1) * amp[843] + std::complex<double>
+ (0, 1) * amp[844] + std::complex<double> (0, 1) * amp[846] +
+ std::complex<double> (0, 1) * amp[850] - amp[851] + std::complex<double>
+ (0, 1) * amp[852] + std::complex<double> (0, 1) * amp[853] +
+ std::complex<double> (0, 1) * amp[859] + std::complex<double> (0, 1) *
+ amp[861] + std::complex<double> (0, 1) * amp[862] - std::complex<double>
+ (0, 1) * amp[902] + std::complex<double> (0, 1) * amp[904] - amp[905] +
+ std::complex<double> (0, 1) * amp[906] + std::complex<double> (0, 1) *
+ amp[907] - std::complex<double> (0, 1) * amp[911] + amp[912] +
+ std::complex<double> (0, 1) * amp[913] + std::complex<double> (0, 1) *
+ amp[915] + std::complex<double> (0, 1) * amp[916] - std::complex<double>
+ (0, 1) * amp[920] + std::complex<double> (0, 1) * amp[922] - amp[923] +
+ std::complex<double> (0, 1) * amp[924] + std::complex<double> (0, 1) *
+ amp[925] - std::complex<double> (0, 1) * amp[929] + amp[930] +
+ std::complex<double> (0, 1) * amp[931] + std::complex<double> (0, 1) *
+ amp[933] + std::complex<double> (0, 1) * amp[934] - std::complex<double>
+ (0, 1) * amp[987] - std::complex<double> (0, 1) * amp[988] + amp[990] +
+ amp[991] - std::complex<double> (0, 1) * amp[993] - std::complex<double>
+ (0, 1) * amp[994] - std::complex<double> (0, 1) * amp[999] -
+ std::complex<double> (0, 1) * amp[1000] + amp[1002] + amp[1003] -
+ std::complex<double> (0, 1) * amp[1005] - std::complex<double> (0, 1) *
+ amp[1006] + amp[1010] - amp[1008] - std::complex<double> (0, 1) *
+ amp[1013] + std::complex<double> (0, 1) * amp[1011] -
+ std::complex<double> (0, 1) * amp[1019] + std::complex<double> (0, 1) *
+ amp[1017] + amp[1022] - amp[1020] - std::complex<double> (0, 1) *
+ amp[1025] + std::complex<double> (0, 1) * amp[1023] -
+ std::complex<double> (0, 1) * amp[1031] + std::complex<double> (0, 1) *
+ amp[1029];
+ jamp[6] = +amp[109] + amp[115] + amp[153] + amp[154] + amp[156] + amp[159] +
+ amp[160] + amp[162] - std::complex<double> (0, 1) * amp[164] -
+ std::complex<double> (0, 1) * amp[165] - std::complex<double> (0, 1) *
+ amp[166] - std::complex<double> (0, 1) * amp[167] - amp[169] -
+ std::complex<double> (0, 1) * amp[170] - amp[172] - amp[175] -
+ std::complex<double> (0, 1) * amp[176] - amp[178] - std::complex<double>
+ (0, 1) * amp[192] - amp[193] - std::complex<double> (0, 1) * amp[194] -
+ amp[196] - std::complex<double> (0, 1) * amp[197] - std::complex<double>
+ (0, 1) * amp[198] - amp[199] - std::complex<double> (0, 1) * amp[200] -
+ amp[202] - std::complex<double> (0, 1) * amp[203] + amp[206] - amp[204] +
+ amp[209] - amp[207] + amp[212] - amp[210] + amp[215] - amp[213] +
+ amp[617] + amp[623] + std::complex<double> (0, 1) * amp[625] + amp[626] +
+ std::complex<double> (0, 1) * amp[627] + amp[628] + std::complex<double>
+ (0, 1) * amp[629] + std::complex<double> (0, 1) * amp[631] + amp[632] +
+ std::complex<double> (0, 1) * amp[633] + amp[634] + std::complex<double>
+ (0, 1) * amp[635] - std::complex<double> (0, 1) * amp[636] + amp[638] +
+ amp[640] - std::complex<double> (0, 1) * amp[642] + amp[644] + amp[646] -
+ amp[662] - amp[661] - amp[665] - amp[664] - amp[668] - amp[667] -
+ amp[671] - amp[670] - std::complex<double> (0, 1) * amp[674] +
+ std::complex<double> (0, 1) * amp[680] - std::complex<double> (0, 1) *
+ amp[678] + std::complex<double> (0, 1) * amp[682] - std::complex<double>
+ (0, 1) * amp[683] + amp[684] + std::complex<double> (0, 1) * amp[689] -
+ std::complex<double> (0, 1) * amp[687] - std::complex<double> (0, 1) *
+ amp[692] + std::complex<double> (0, 1) * amp[698] - std::complex<double>
+ (0, 1) * amp[696] + std::complex<double> (0, 1) * amp[700] -
+ std::complex<double> (0, 1) * amp[701] + amp[702] + std::complex<double>
+ (0, 1) * amp[707] - std::complex<double> (0, 1) * amp[705] + amp[709] -
+ std::complex<double> (0, 1) * amp[710] + amp[711] - std::complex<double>
+ (0, 1) * amp[713] + amp[714] + amp[717] - std::complex<double> (0, 1) *
+ amp[718] + amp[719] - std::complex<double> (0, 1) * amp[721] + amp[722] -
+ std::complex<double> (0, 1) * amp[726] - std::complex<double> (0, 1) *
+ amp[728] - amp[729] + std::complex<double> (0, 1) * amp[732] +
+ std::complex<double> (0, 1) * amp[731] - std::complex<double> (0, 1) *
+ amp[735] + amp[736] - std::complex<double> (0, 1) * amp[737] +
+ std::complex<double> (0, 1) * amp[741] + std::complex<double> (0, 1) *
+ amp[740] - std::complex<double> (0, 1) * amp[744] - std::complex<double>
+ (0, 1) * amp[746] - amp[747] + std::complex<double> (0, 1) * amp[750] +
+ std::complex<double> (0, 1) * amp[749] - std::complex<double> (0, 1) *
+ amp[753] + amp[754] - std::complex<double> (0, 1) * amp[755] +
+ std::complex<double> (0, 1) * amp[759] + std::complex<double> (0, 1) *
+ amp[758] - std::complex<double> (0, 1) * amp[901] - std::complex<double>
+ (0, 1) * amp[902] - amp[903] + std::complex<double> (0, 1) * amp[908] +
+ std::complex<double> (0, 1) * amp[907] - std::complex<double> (0, 1) *
+ amp[911] + std::complex<double> (0, 1) * amp[917] + std::complex<double>
+ (0, 1) * amp[916] - std::complex<double> (0, 1) * amp[919] -
+ std::complex<double> (0, 1) * amp[920] - amp[921] + std::complex<double>
+ (0, 1) * amp[926] + std::complex<double> (0, 1) * amp[925] -
+ std::complex<double> (0, 1) * amp[929] + std::complex<double> (0, 1) *
+ amp[935] + std::complex<double> (0, 1) * amp[934] + std::complex<double>
+ (0, 1) * amp[941] + std::complex<double> (0, 1) * amp[940] - amp[944] -
+ amp[943] + std::complex<double> (0, 1) * amp[947] + std::complex<double>
+ (0, 1) * amp[946] + std::complex<double> (0, 1) * amp[953] +
+ std::complex<double> (0, 1) * amp[952] - amp[956] - amp[955] +
+ std::complex<double> (0, 1) * amp[959] + std::complex<double> (0, 1) *
+ amp[958] + amp[986] - amp[984] + std::complex<double> (0, 1) * amp[989] -
+ std::complex<double> (0, 1) * amp[987] + std::complex<double> (0, 1) *
+ amp[995] - std::complex<double> (0, 1) * amp[993] + amp[998] - amp[996] +
+ std::complex<double> (0, 1) * amp[1001] - std::complex<double> (0, 1) *
+ amp[999] + std::complex<double> (0, 1) * amp[1007] - std::complex<double>
+ (0, 1) * amp[1005];
+ jamp[7] = +amp[108] + amp[114] + amp[137] + amp[138] + amp[140] + amp[143] +
+ amp[144] + amp[146] - std::complex<double> (0, 1) * amp[148] -
+ std::complex<double> (0, 1) * amp[149] - std::complex<double> (0, 1) *
+ amp[150] - std::complex<double> (0, 1) * amp[151] - amp[181] -
+ std::complex<double> (0, 1) * amp[182] - amp[184] - amp[187] -
+ std::complex<double> (0, 1) * amp[188] - amp[190] + std::complex<double>
+ (0, 1) * amp[192] + amp[193] + std::complex<double> (0, 1) * amp[194] +
+ amp[196] + std::complex<double> (0, 1) * amp[197] + std::complex<double>
+ (0, 1) * amp[198] + amp[199] + std::complex<double> (0, 1) * amp[200] +
+ amp[202] + std::complex<double> (0, 1) * amp[203] + amp[204] + amp[205] +
+ amp[207] + amp[208] + amp[210] + amp[211] + amp[213] + amp[214] +
+ amp[557] + amp[563] + std::complex<double> (0, 1) * amp[565] + amp[566] +
+ std::complex<double> (0, 1) * amp[567] + amp[568] + std::complex<double>
+ (0, 1) * amp[569] + std::complex<double> (0, 1) * amp[571] + amp[572] +
+ std::complex<double> (0, 1) * amp[573] + amp[574] + std::complex<double>
+ (0, 1) * amp[575] - std::complex<double> (0, 1) * amp[576] + amp[578] +
+ amp[580] - std::complex<double> (0, 1) * amp[582] + amp[584] + amp[586] -
+ amp[602] - amp[601] - amp[605] - amp[604] - amp[608] - amp[607] -
+ amp[611] - amp[610] - std::complex<double> (0, 1) * amp[676] +
+ std::complex<double> (0, 1) * amp[678] + std::complex<double> (0, 1) *
+ amp[679] + std::complex<double> (0, 1) * amp[681] - std::complex<double>
+ (0, 1) * amp[685] + amp[686] + std::complex<double> (0, 1) * amp[687] +
+ std::complex<double> (0, 1) * amp[688] - std::complex<double> (0, 1) *
+ amp[694] + std::complex<double> (0, 1) * amp[696] + std::complex<double>
+ (0, 1) * amp[697] + std::complex<double> (0, 1) * amp[699] -
+ std::complex<double> (0, 1) * amp[703] + amp[704] + std::complex<double>
+ (0, 1) * amp[705] + std::complex<double> (0, 1) * amp[706] - amp[709] +
+ std::complex<double> (0, 1) * amp[710] - amp[711] + std::complex<double>
+ (0, 1) * amp[713] - amp[714] - amp[717] + std::complex<double> (0, 1) *
+ amp[718] - amp[719] + std::complex<double> (0, 1) * amp[721] - amp[722] -
+ std::complex<double> (0, 1) * amp[778] - std::complex<double> (0, 1) *
+ amp[780] - amp[781] + std::complex<double> (0, 1) * amp[784] +
+ std::complex<double> (0, 1) * amp[783] - std::complex<double> (0, 1) *
+ amp[787] + amp[788] - std::complex<double> (0, 1) * amp[789] +
+ std::complex<double> (0, 1) * amp[793] + std::complex<double> (0, 1) *
+ amp[792] - std::complex<double> (0, 1) * amp[796] - std::complex<double>
+ (0, 1) * amp[798] - amp[799] + std::complex<double> (0, 1) * amp[802] +
+ std::complex<double> (0, 1) * amp[801] - std::complex<double> (0, 1) *
+ amp[805] + amp[806] - std::complex<double> (0, 1) * amp[807] +
+ std::complex<double> (0, 1) * amp[811] + std::complex<double> (0, 1) *
+ amp[810] + std::complex<double> (0, 1) * amp[901] + std::complex<double>
+ (0, 1) * amp[902] + amp[903] - std::complex<double> (0, 1) * amp[908] -
+ std::complex<double> (0, 1) * amp[907] + std::complex<double> (0, 1) *
+ amp[911] - std::complex<double> (0, 1) * amp[917] - std::complex<double>
+ (0, 1) * amp[916] + std::complex<double> (0, 1) * amp[919] +
+ std::complex<double> (0, 1) * amp[920] + amp[921] - std::complex<double>
+ (0, 1) * amp[926] - std::complex<double> (0, 1) * amp[925] +
+ std::complex<double> (0, 1) * amp[929] - std::complex<double> (0, 1) *
+ amp[935] - std::complex<double> (0, 1) * amp[934] + std::complex<double>
+ (0, 1) * amp[965] + std::complex<double> (0, 1) * amp[964] - amp[968] -
+ amp[967] + std::complex<double> (0, 1) * amp[971] + std::complex<double>
+ (0, 1) * amp[970] + std::complex<double> (0, 1) * amp[977] +
+ std::complex<double> (0, 1) * amp[976] - amp[980] - amp[979] +
+ std::complex<double> (0, 1) * amp[983] + std::complex<double> (0, 1) *
+ amp[982] + amp[984] + amp[985] + std::complex<double> (0, 1) * amp[987] +
+ std::complex<double> (0, 1) * amp[988] + std::complex<double> (0, 1) *
+ amp[993] + std::complex<double> (0, 1) * amp[994] + amp[996] + amp[997] +
+ std::complex<double> (0, 1) * amp[999] + std::complex<double> (0, 1) *
+ amp[1000] + std::complex<double> (0, 1) * amp[1005] +
+ std::complex<double> (0, 1) * amp[1006];
+ jamp[8] = +amp[111] + amp[117] + amp[152] + amp[155] + amp[157] + amp[158] +
+ amp[161] + amp[163] + std::complex<double> (0, 1) * amp[164] +
+ std::complex<double> (0, 1) * amp[165] + std::complex<double> (0, 1) *
+ amp[166] + std::complex<double> (0, 1) * amp[167] + amp[169] +
+ std::complex<double> (0, 1) * amp[170] + amp[172] + amp[175] +
+ std::complex<double> (0, 1) * amp[176] + amp[178] - std::complex<double>
+ (0, 1) * amp[180] + amp[181] - std::complex<double> (0, 1) * amp[183] +
+ amp[184] - std::complex<double> (0, 1) * amp[185] - std::complex<double>
+ (0, 1) * amp[186] + amp[187] - std::complex<double> (0, 1) * amp[189] +
+ amp[190] - std::complex<double> (0, 1) * amp[191] - amp[206] - amp[205] -
+ amp[209] - amp[208] - amp[212] - amp[211] - amp[215] - amp[214] +
+ amp[612] + amp[618] + std::complex<double> (0, 1) * amp[636] - amp[638] -
+ amp[640] + std::complex<double> (0, 1) * amp[642] - amp[644] - amp[646] -
+ std::complex<double> (0, 1) * amp[648] + amp[650] - std::complex<double>
+ (0, 1) * amp[651] + amp[652] - std::complex<double> (0, 1) * amp[653] -
+ std::complex<double> (0, 1) * amp[654] + amp[656] - std::complex<double>
+ (0, 1) * amp[657] + amp[658] - std::complex<double> (0, 1) * amp[659] +
+ amp[660] + amp[661] + amp[663] + amp[664] + amp[666] + amp[667] +
+ amp[669] + amp[670] + std::complex<double> (0, 1) * amp[726] +
+ std::complex<double> (0, 1) * amp[728] + amp[729] - std::complex<double>
+ (0, 1) * amp[732] - std::complex<double> (0, 1) * amp[731] +
+ std::complex<double> (0, 1) * amp[735] - amp[736] + std::complex<double>
+ (0, 1) * amp[737] - std::complex<double> (0, 1) * amp[741] -
+ std::complex<double> (0, 1) * amp[740] + std::complex<double> (0, 1) *
+ amp[744] + std::complex<double> (0, 1) * amp[746] + amp[747] -
+ std::complex<double> (0, 1) * amp[750] - std::complex<double> (0, 1) *
+ amp[749] + std::complex<double> (0, 1) * amp[753] - amp[754] +
+ std::complex<double> (0, 1) * amp[755] - std::complex<double> (0, 1) *
+ amp[759] - std::complex<double> (0, 1) * amp[758] - std::complex<double>
+ (0, 1) * amp[776] + std::complex<double> (0, 1) * amp[780] + amp[781] -
+ std::complex<double> (0, 1) * amp[782] - std::complex<double> (0, 1) *
+ amp[783] + std::complex<double> (0, 1) * amp[789] - std::complex<double>
+ (0, 1) * amp[791] - std::complex<double> (0, 1) * amp[792] -
+ std::complex<double> (0, 1) * amp[794] + std::complex<double> (0, 1) *
+ amp[798] + amp[799] - std::complex<double> (0, 1) * amp[800] -
+ std::complex<double> (0, 1) * amp[801] + std::complex<double> (0, 1) *
+ amp[807] - std::complex<double> (0, 1) * amp[809] - std::complex<double>
+ (0, 1) * amp[810] - amp[812] - std::complex<double> (0, 1) * amp[814] -
+ amp[816] - std::complex<double> (0, 1) * amp[817] - amp[819] - amp[820] -
+ std::complex<double> (0, 1) * amp[822] - amp[824] - std::complex<double>
+ (0, 1) * amp[825] - amp[827] - std::complex<double> (0, 1) * amp[830] +
+ std::complex<double> (0, 1) * amp[836] + std::complex<double> (0, 1) *
+ amp[835] - std::complex<double> (0, 1) * amp[838] - std::complex<double>
+ (0, 1) * amp[839] + amp[840] + std::complex<double> (0, 1) * amp[845] +
+ std::complex<double> (0, 1) * amp[844] - std::complex<double> (0, 1) *
+ amp[848] + std::complex<double> (0, 1) * amp[854] + std::complex<double>
+ (0, 1) * amp[853] - std::complex<double> (0, 1) * amp[856] -
+ std::complex<double> (0, 1) * amp[857] + amp[858] + std::complex<double>
+ (0, 1) * amp[863] + std::complex<double> (0, 1) * amp[862] -
+ std::complex<double> (0, 1) * amp[939] - std::complex<double> (0, 1) *
+ amp[940] + amp[942] + amp[943] - std::complex<double> (0, 1) * amp[945] -
+ std::complex<double> (0, 1) * amp[946] - std::complex<double> (0, 1) *
+ amp[951] - std::complex<double> (0, 1) * amp[952] + amp[954] + amp[955] -
+ std::complex<double> (0, 1) * amp[957] - std::complex<double> (0, 1) *
+ amp[958] - amp[986] - amp[985] - std::complex<double> (0, 1) * amp[989] -
+ std::complex<double> (0, 1) * amp[988] - std::complex<double> (0, 1) *
+ amp[995] - std::complex<double> (0, 1) * amp[994] - amp[998] - amp[997] -
+ std::complex<double> (0, 1) * amp[1001] - std::complex<double> (0, 1) *
+ amp[1000] - std::complex<double> (0, 1) * amp[1007] -
+ std::complex<double> (0, 1) * amp[1006];
+ jamp[9] = +amp[110] + amp[116] + amp[121] + amp[122] + amp[124] + amp[127] +
+ amp[128] + amp[130] - std::complex<double> (0, 1) * amp[132] -
+ std::complex<double> (0, 1) * amp[133] - std::complex<double> (0, 1) *
+ amp[134] - std::complex<double> (0, 1) * amp[135] + std::complex<double>
+ (0, 1) * amp[180] - amp[181] + std::complex<double> (0, 1) * amp[183] -
+ amp[184] + std::complex<double> (0, 1) * amp[185] + std::complex<double>
+ (0, 1) * amp[186] - amp[187] + std::complex<double> (0, 1) * amp[189] -
+ amp[190] + std::complex<double> (0, 1) * amp[191] + amp[193] -
+ std::complex<double> (0, 1) * amp[195] + amp[196] + amp[199] -
+ std::complex<double> (0, 1) * amp[201] + amp[202] + amp[204] + amp[205] +
+ amp[207] + amp[208] + amp[210] + amp[211] + amp[213] + amp[214] +
+ amp[436] + amp[442] - std::complex<double> (0, 1) * amp[445] - amp[446] -
+ std::complex<double> (0, 1) * amp[447] - amp[448] - std::complex<double>
+ (0, 1) * amp[449] - std::complex<double> (0, 1) * amp[451] - amp[452] -
+ std::complex<double> (0, 1) * amp[453] - amp[454] - std::complex<double>
+ (0, 1) * amp[455] - std::complex<double> (0, 1) * amp[469] - amp[470] -
+ amp[472] - std::complex<double> (0, 1) * amp[475] - amp[476] - amp[478] +
+ amp[482] - amp[480] + amp[485] - amp[483] + amp[488] - amp[486] +
+ amp[491] - amp[489] + std::complex<double> (0, 1) * amp[776] -
+ std::complex<double> (0, 1) * amp[780] - amp[781] + std::complex<double>
+ (0, 1) * amp[782] + std::complex<double> (0, 1) * amp[783] -
+ std::complex<double> (0, 1) * amp[789] + std::complex<double> (0, 1) *
+ amp[791] + std::complex<double> (0, 1) * amp[792] + std::complex<double>
+ (0, 1) * amp[794] - std::complex<double> (0, 1) * amp[798] - amp[799] +
+ std::complex<double> (0, 1) * amp[800] + std::complex<double> (0, 1) *
+ amp[801] - std::complex<double> (0, 1) * amp[807] + std::complex<double>
+ (0, 1) * amp[809] + std::complex<double> (0, 1) * amp[810] + amp[812] +
+ std::complex<double> (0, 1) * amp[814] + amp[816] + std::complex<double>
+ (0, 1) * amp[817] + amp[819] + amp[820] + std::complex<double> (0, 1) *
+ amp[822] + amp[824] + std::complex<double> (0, 1) * amp[825] + amp[827] -
+ std::complex<double> (0, 1) * amp[832] - std::complex<double> (0, 1) *
+ amp[834] - std::complex<double> (0, 1) * amp[835] - std::complex<double>
+ (0, 1) * amp[837] - std::complex<double> (0, 1) * amp[841] - amp[842] -
+ std::complex<double> (0, 1) * amp[843] - std::complex<double> (0, 1) *
+ amp[844] - std::complex<double> (0, 1) * amp[850] - std::complex<double>
+ (0, 1) * amp[852] - std::complex<double> (0, 1) * amp[853] -
+ std::complex<double> (0, 1) * amp[855] - std::complex<double> (0, 1) *
+ amp[859] - amp[860] - std::complex<double> (0, 1) * amp[861] -
+ std::complex<double> (0, 1) * amp[862] + std::complex<double> (0, 1) *
+ amp[902] + amp[903] - std::complex<double> (0, 1) * amp[904] -
+ std::complex<double> (0, 1) * amp[906] - std::complex<double> (0, 1) *
+ amp[907] + std::complex<double> (0, 1) * amp[911] - std::complex<double>
+ (0, 1) * amp[913] - amp[914] - std::complex<double> (0, 1) * amp[915] -
+ std::complex<double> (0, 1) * amp[916] + std::complex<double> (0, 1) *
+ amp[920] + amp[921] - std::complex<double> (0, 1) * amp[922] -
+ std::complex<double> (0, 1) * amp[924] - std::complex<double> (0, 1) *
+ amp[925] + std::complex<double> (0, 1) * amp[929] - std::complex<double>
+ (0, 1) * amp[931] - amp[932] - std::complex<double> (0, 1) * amp[933] -
+ std::complex<double> (0, 1) * amp[934] + amp[984] + amp[985] +
+ std::complex<double> (0, 1) * amp[987] + std::complex<double> (0, 1) *
+ amp[988] + std::complex<double> (0, 1) * amp[993] + std::complex<double>
+ (0, 1) * amp[994] + amp[996] + amp[997] + std::complex<double> (0, 1) *
+ amp[999] + std::complex<double> (0, 1) * amp[1000] + std::complex<double>
+ (0, 1) * amp[1005] + std::complex<double> (0, 1) * amp[1006] +
+ std::complex<double> (0, 1) * amp[1013] - std::complex<double> (0, 1) *
+ amp[1011] + amp[1016] - amp[1014] + std::complex<double> (0, 1) *
+ amp[1019] - std::complex<double> (0, 1) * amp[1017] +
+ std::complex<double> (0, 1) * amp[1025] - std::complex<double> (0, 1) *
+ amp[1023] + amp[1028] - amp[1026] + std::complex<double> (0, 1) *
+ amp[1031] - std::complex<double> (0, 1) * amp[1029];
+ jamp[10] = +amp[113] + amp[119] + amp[136] + amp[139] + amp[141] + amp[142] +
+ amp[145] + amp[147] + std::complex<double> (0, 1) * amp[148] +
+ std::complex<double> (0, 1) * amp[149] + std::complex<double> (0, 1) *
+ amp[150] + std::complex<double> (0, 1) * amp[151] - std::complex<double>
+ (0, 1) * amp[168] + amp[169] - std::complex<double> (0, 1) * amp[171] +
+ amp[172] - std::complex<double> (0, 1) * amp[173] - std::complex<double>
+ (0, 1) * amp[174] + amp[175] - std::complex<double> (0, 1) * amp[177] +
+ amp[178] - std::complex<double> (0, 1) * amp[179] + amp[181] +
+ std::complex<double> (0, 1) * amp[182] + amp[184] + amp[187] +
+ std::complex<double> (0, 1) * amp[188] + amp[190] - amp[206] - amp[205] -
+ amp[209] - amp[208] - amp[212] - amp[211] - amp[215] - amp[214] +
+ amp[552] + amp[558] + std::complex<double> (0, 1) * amp[576] - amp[578] -
+ amp[580] + std::complex<double> (0, 1) * amp[582] - amp[584] - amp[586] -
+ std::complex<double> (0, 1) * amp[588] + amp[590] - std::complex<double>
+ (0, 1) * amp[591] + amp[592] - std::complex<double> (0, 1) * amp[593] -
+ std::complex<double> (0, 1) * amp[594] + amp[596] - std::complex<double>
+ (0, 1) * amp[597] + amp[598] - std::complex<double> (0, 1) * amp[599] +
+ amp[600] + amp[601] + amp[603] + amp[604] + amp[606] + amp[607] +
+ amp[609] + amp[610] - std::complex<double> (0, 1) * amp[724] +
+ std::complex<double> (0, 1) * amp[728] + amp[729] - std::complex<double>
+ (0, 1) * amp[730] - std::complex<double> (0, 1) * amp[731] +
+ std::complex<double> (0, 1) * amp[737] - std::complex<double> (0, 1) *
+ amp[739] - std::complex<double> (0, 1) * amp[740] - std::complex<double>
+ (0, 1) * amp[742] + std::complex<double> (0, 1) * amp[746] + amp[747] -
+ std::complex<double> (0, 1) * amp[748] - std::complex<double> (0, 1) *
+ amp[749] + std::complex<double> (0, 1) * amp[755] - std::complex<double>
+ (0, 1) * amp[757] - std::complex<double> (0, 1) * amp[758] - amp[760] -
+ std::complex<double> (0, 1) * amp[762] - amp[764] - std::complex<double>
+ (0, 1) * amp[765] - amp[767] - amp[768] - std::complex<double> (0, 1) *
+ amp[770] - amp[772] - std::complex<double> (0, 1) * amp[773] - amp[775] +
+ std::complex<double> (0, 1) * amp[778] + std::complex<double> (0, 1) *
+ amp[780] + amp[781] - std::complex<double> (0, 1) * amp[784] -
+ std::complex<double> (0, 1) * amp[783] + std::complex<double> (0, 1) *
+ amp[787] - amp[788] + std::complex<double> (0, 1) * amp[789] -
+ std::complex<double> (0, 1) * amp[793] - std::complex<double> (0, 1) *
+ amp[792] + std::complex<double> (0, 1) * amp[796] + std::complex<double>
+ (0, 1) * amp[798] + amp[799] - std::complex<double> (0, 1) * amp[802] -
+ std::complex<double> (0, 1) * amp[801] + std::complex<double> (0, 1) *
+ amp[805] - amp[806] + std::complex<double> (0, 1) * amp[807] -
+ std::complex<double> (0, 1) * amp[811] - std::complex<double> (0, 1) *
+ amp[810] - std::complex<double> (0, 1) * amp[866] + std::complex<double>
+ (0, 1) * amp[872] + std::complex<double> (0, 1) * amp[871] -
+ std::complex<double> (0, 1) * amp[874] - std::complex<double> (0, 1) *
+ amp[875] + amp[876] + std::complex<double> (0, 1) * amp[881] +
+ std::complex<double> (0, 1) * amp[880] - std::complex<double> (0, 1) *
+ amp[884] + std::complex<double> (0, 1) * amp[890] + std::complex<double>
+ (0, 1) * amp[889] - std::complex<double> (0, 1) * amp[892] -
+ std::complex<double> (0, 1) * amp[893] + amp[894] + std::complex<double>
+ (0, 1) * amp[899] + std::complex<double> (0, 1) * amp[898] -
+ std::complex<double> (0, 1) * amp[963] - std::complex<double> (0, 1) *
+ amp[964] + amp[966] + amp[967] - std::complex<double> (0, 1) * amp[969] -
+ std::complex<double> (0, 1) * amp[970] - std::complex<double> (0, 1) *
+ amp[975] - std::complex<double> (0, 1) * amp[976] + amp[978] + amp[979] -
+ std::complex<double> (0, 1) * amp[981] - std::complex<double> (0, 1) *
+ amp[982] - amp[986] - amp[985] - std::complex<double> (0, 1) * amp[989] -
+ std::complex<double> (0, 1) * amp[988] - std::complex<double> (0, 1) *
+ amp[995] - std::complex<double> (0, 1) * amp[994] - amp[998] - amp[997] -
+ std::complex<double> (0, 1) * amp[1001] - std::complex<double> (0, 1) *
+ amp[1000] - std::complex<double> (0, 1) * amp[1007] -
+ std::complex<double> (0, 1) * amp[1006];
+ jamp[11] = +amp[112] + amp[118] + amp[120] + amp[123] + amp[125] + amp[126] +
+ amp[129] + amp[131] + std::complex<double> (0, 1) * amp[132] +
+ std::complex<double> (0, 1) * amp[133] + std::complex<double> (0, 1) *
+ amp[134] + std::complex<double> (0, 1) * amp[135] + std::complex<double>
+ (0, 1) * amp[168] - amp[169] + std::complex<double> (0, 1) * amp[171] -
+ amp[172] + std::complex<double> (0, 1) * amp[173] + std::complex<double>
+ (0, 1) * amp[174] - amp[175] + std::complex<double> (0, 1) * amp[177] -
+ amp[178] + std::complex<double> (0, 1) * amp[179] - amp[193] +
+ std::complex<double> (0, 1) * amp[195] - amp[196] - amp[199] +
+ std::complex<double> (0, 1) * amp[201] - amp[202] + amp[206] - amp[204] +
+ amp[209] - amp[207] + amp[212] - amp[210] + amp[215] - amp[213] +
+ amp[434] + amp[440] - std::complex<double> (0, 1) * amp[457] - amp[458] -
+ std::complex<double> (0, 1) * amp[459] - amp[460] - std::complex<double>
+ (0, 1) * amp[461] - std::complex<double> (0, 1) * amp[463] - amp[464] -
+ std::complex<double> (0, 1) * amp[465] - amp[466] - std::complex<double>
+ (0, 1) * amp[467] + std::complex<double> (0, 1) * amp[469] + amp[470] +
+ amp[472] + std::complex<double> (0, 1) * amp[475] + amp[476] + amp[478] +
+ amp[480] + amp[481] + amp[483] + amp[484] + amp[486] + amp[487] +
+ amp[489] + amp[490] + std::complex<double> (0, 1) * amp[724] -
+ std::complex<double> (0, 1) * amp[728] - amp[729] + std::complex<double>
+ (0, 1) * amp[730] + std::complex<double> (0, 1) * amp[731] -
+ std::complex<double> (0, 1) * amp[737] + std::complex<double> (0, 1) *
+ amp[739] + std::complex<double> (0, 1) * amp[740] + std::complex<double>
+ (0, 1) * amp[742] - std::complex<double> (0, 1) * amp[746] - amp[747] +
+ std::complex<double> (0, 1) * amp[748] + std::complex<double> (0, 1) *
+ amp[749] - std::complex<double> (0, 1) * amp[755] + std::complex<double>
+ (0, 1) * amp[757] + std::complex<double> (0, 1) * amp[758] + amp[760] +
+ std::complex<double> (0, 1) * amp[762] + amp[764] + std::complex<double>
+ (0, 1) * amp[765] + amp[767] + amp[768] + std::complex<double> (0, 1) *
+ amp[770] + amp[772] + std::complex<double> (0, 1) * amp[773] + amp[775] -
+ std::complex<double> (0, 1) * amp[868] - std::complex<double> (0, 1) *
+ amp[870] - std::complex<double> (0, 1) * amp[871] - std::complex<double>
+ (0, 1) * amp[873] - std::complex<double> (0, 1) * amp[877] - amp[878] -
+ std::complex<double> (0, 1) * amp[879] - std::complex<double> (0, 1) *
+ amp[880] - std::complex<double> (0, 1) * amp[886] - std::complex<double>
+ (0, 1) * amp[888] - std::complex<double> (0, 1) * amp[889] -
+ std::complex<double> (0, 1) * amp[891] - std::complex<double> (0, 1) *
+ amp[895] - amp[896] - std::complex<double> (0, 1) * amp[897] -
+ std::complex<double> (0, 1) * amp[898] - std::complex<double> (0, 1) *
+ amp[902] - amp[903] + std::complex<double> (0, 1) * amp[904] +
+ std::complex<double> (0, 1) * amp[906] + std::complex<double> (0, 1) *
+ amp[907] - std::complex<double> (0, 1) * amp[911] + std::complex<double>
+ (0, 1) * amp[913] + amp[914] + std::complex<double> (0, 1) * amp[915] +
+ std::complex<double> (0, 1) * amp[916] - std::complex<double> (0, 1) *
+ amp[920] - amp[921] + std::complex<double> (0, 1) * amp[922] +
+ std::complex<double> (0, 1) * amp[924] + std::complex<double> (0, 1) *
+ amp[925] - std::complex<double> (0, 1) * amp[929] + std::complex<double>
+ (0, 1) * amp[931] + amp[932] + std::complex<double> (0, 1) * amp[933] +
+ std::complex<double> (0, 1) * amp[934] + amp[986] - amp[984] +
+ std::complex<double> (0, 1) * amp[989] - std::complex<double> (0, 1) *
+ amp[987] + std::complex<double> (0, 1) * amp[995] - std::complex<double>
+ (0, 1) * amp[993] + amp[998] - amp[996] + std::complex<double> (0, 1) *
+ amp[1001] - std::complex<double> (0, 1) * amp[999] + std::complex<double>
+ (0, 1) * amp[1007] - std::complex<double> (0, 1) * amp[1005] +
+ std::complex<double> (0, 1) * amp[1011] + std::complex<double> (0, 1) *
+ amp[1012] + amp[1014] + amp[1015] + std::complex<double> (0, 1) *
+ amp[1017] + std::complex<double> (0, 1) * amp[1018] +
+ std::complex<double> (0, 1) * amp[1023] + std::complex<double> (0, 1) *
+ amp[1024] + amp[1026] + amp[1027] + std::complex<double> (0, 1) *
+ amp[1029] + std::complex<double> (0, 1) * amp[1030];
+ jamp[12] = +amp[217] + amp[223] + amp[261] + amp[262] + amp[264] + amp[267] +
+ amp[268] + amp[270] - std::complex<double> (0, 1) * amp[272] -
+ std::complex<double> (0, 1) * amp[273] - std::complex<double> (0, 1) *
+ amp[274] - std::complex<double> (0, 1) * amp[275] - amp[277] -
+ std::complex<double> (0, 1) * amp[278] - amp[280] - amp[283] -
+ std::complex<double> (0, 1) * amp[284] - amp[286] - std::complex<double>
+ (0, 1) * amp[300] - amp[301] - std::complex<double> (0, 1) * amp[302] -
+ amp[304] - std::complex<double> (0, 1) * amp[305] - std::complex<double>
+ (0, 1) * amp[306] - amp[307] - std::complex<double> (0, 1) * amp[308] -
+ amp[310] - std::complex<double> (0, 1) * amp[311] + amp[314] - amp[312] +
+ amp[317] - amp[315] + amp[320] - amp[318] + amp[323] - amp[321] +
+ amp[615] + amp[621] - std::complex<double> (0, 1) * amp[624] + amp[626] +
+ amp[628] - std::complex<double> (0, 1) * amp[630] + amp[632] + amp[634] +
+ std::complex<double> (0, 1) * amp[637] + amp[638] + std::complex<double>
+ (0, 1) * amp[639] + amp[640] + std::complex<double> (0, 1) * amp[641] +
+ std::complex<double> (0, 1) * amp[643] + amp[644] + std::complex<double>
+ (0, 1) * amp[645] + amp[646] + std::complex<double> (0, 1) * amp[647] -
+ amp[662] - amp[661] - amp[665] - amp[664] - amp[668] - amp[667] -
+ amp[671] - amp[670] - std::complex<double> (0, 1) * amp[674] -
+ std::complex<double> (0, 1) * amp[676] - amp[677] + std::complex<double>
+ (0, 1) * amp[680] + std::complex<double> (0, 1) * amp[679] -
+ std::complex<double> (0, 1) * amp[683] + amp[684] - std::complex<double>
+ (0, 1) * amp[685] + std::complex<double> (0, 1) * amp[689] +
+ std::complex<double> (0, 1) * amp[688] - std::complex<double> (0, 1) *
+ amp[692] - std::complex<double> (0, 1) * amp[694] - amp[695] +
+ std::complex<double> (0, 1) * amp[698] + std::complex<double> (0, 1) *
+ amp[697] - std::complex<double> (0, 1) * amp[701] + amp[702] -
+ std::complex<double> (0, 1) * amp[703] + std::complex<double> (0, 1) *
+ amp[707] + std::complex<double> (0, 1) * amp[706] - std::complex<double>
+ (0, 1) * amp[726] + std::complex<double> (0, 1) * amp[732] -
+ std::complex<double> (0, 1) * amp[730] + std::complex<double> (0, 1) *
+ amp[734] - std::complex<double> (0, 1) * amp[735] + amp[736] +
+ std::complex<double> (0, 1) * amp[741] - std::complex<double> (0, 1) *
+ amp[739] - std::complex<double> (0, 1) * amp[744] + std::complex<double>
+ (0, 1) * amp[750] - std::complex<double> (0, 1) * amp[748] +
+ std::complex<double> (0, 1) * amp[752] - std::complex<double> (0, 1) *
+ amp[753] + amp[754] + std::complex<double> (0, 1) * amp[759] -
+ std::complex<double> (0, 1) * amp[757] + amp[761] - std::complex<double>
+ (0, 1) * amp[762] + amp[763] - std::complex<double> (0, 1) * amp[765] +
+ amp[766] + amp[769] - std::complex<double> (0, 1) * amp[770] + amp[771] -
+ std::complex<double> (0, 1) * amp[773] + amp[774] - std::complex<double>
+ (0, 1) * amp[865] - std::complex<double> (0, 1) * amp[866] - amp[867] +
+ std::complex<double> (0, 1) * amp[872] + std::complex<double> (0, 1) *
+ amp[871] - std::complex<double> (0, 1) * amp[875] + std::complex<double>
+ (0, 1) * amp[881] + std::complex<double> (0, 1) * amp[880] -
+ std::complex<double> (0, 1) * amp[883] - std::complex<double> (0, 1) *
+ amp[884] - amp[885] + std::complex<double> (0, 1) * amp[890] +
+ std::complex<double> (0, 1) * amp[889] - std::complex<double> (0, 1) *
+ amp[893] + std::complex<double> (0, 1) * amp[899] + std::complex<double>
+ (0, 1) * amp[898] + std::complex<double> (0, 1) * amp[941] +
+ std::complex<double> (0, 1) * amp[940] - amp[944] - amp[943] +
+ std::complex<double> (0, 1) * amp[947] + std::complex<double> (0, 1) *
+ amp[946] + std::complex<double> (0, 1) * amp[953] + std::complex<double>
+ (0, 1) * amp[952] - amp[956] - amp[955] + std::complex<double> (0, 1) *
+ amp[959] + std::complex<double> (0, 1) * amp[958] + amp[962] - amp[960] +
+ std::complex<double> (0, 1) * amp[965] - std::complex<double> (0, 1) *
+ amp[963] + std::complex<double> (0, 1) * amp[971] - std::complex<double>
+ (0, 1) * amp[969] + amp[974] - amp[972] + std::complex<double> (0, 1) *
+ amp[977] - std::complex<double> (0, 1) * amp[975] + std::complex<double>
+ (0, 1) * amp[983] - std::complex<double> (0, 1) * amp[981];
+ jamp[13] = +amp[216] + amp[222] + amp[245] + amp[246] + amp[248] + amp[251] +
+ amp[252] + amp[254] - std::complex<double> (0, 1) * amp[256] -
+ std::complex<double> (0, 1) * amp[257] - std::complex<double> (0, 1) *
+ amp[258] - std::complex<double> (0, 1) * amp[259] - amp[289] -
+ std::complex<double> (0, 1) * amp[290] - amp[292] - amp[295] -
+ std::complex<double> (0, 1) * amp[296] - amp[298] + std::complex<double>
+ (0, 1) * amp[300] + amp[301] + std::complex<double> (0, 1) * amp[302] +
+ amp[304] + std::complex<double> (0, 1) * amp[305] + std::complex<double>
+ (0, 1) * amp[306] + amp[307] + std::complex<double> (0, 1) * amp[308] +
+ amp[310] + std::complex<double> (0, 1) * amp[311] + amp[312] + amp[313] +
+ amp[315] + amp[316] + amp[318] + amp[319] + amp[321] + amp[322] +
+ amp[497] + amp[503] + std::complex<double> (0, 1) * amp[505] + amp[506] +
+ std::complex<double> (0, 1) * amp[507] + amp[508] + std::complex<double>
+ (0, 1) * amp[509] + std::complex<double> (0, 1) * amp[511] + amp[512] +
+ std::complex<double> (0, 1) * amp[513] + amp[514] + std::complex<double>
+ (0, 1) * amp[515] - std::complex<double> (0, 1) * amp[516] + amp[518] +
+ amp[520] - std::complex<double> (0, 1) * amp[522] + amp[524] + amp[526] -
+ amp[542] - amp[541] - amp[545] - amp[544] - amp[548] - amp[547] -
+ amp[551] - amp[550] - std::complex<double> (0, 1) * amp[728] +
+ std::complex<double> (0, 1) * amp[730] + std::complex<double> (0, 1) *
+ amp[731] + std::complex<double> (0, 1) * amp[733] - std::complex<double>
+ (0, 1) * amp[737] + amp[738] + std::complex<double> (0, 1) * amp[739] +
+ std::complex<double> (0, 1) * amp[740] - std::complex<double> (0, 1) *
+ amp[746] + std::complex<double> (0, 1) * amp[748] + std::complex<double>
+ (0, 1) * amp[749] + std::complex<double> (0, 1) * amp[751] -
+ std::complex<double> (0, 1) * amp[755] + amp[756] + std::complex<double>
+ (0, 1) * amp[757] + std::complex<double> (0, 1) * amp[758] - amp[761] +
+ std::complex<double> (0, 1) * amp[762] - amp[763] + std::complex<double>
+ (0, 1) * amp[765] - amp[766] - amp[769] + std::complex<double> (0, 1) *
+ amp[770] - amp[771] + std::complex<double> (0, 1) * amp[773] - amp[774] -
+ std::complex<double> (0, 1) * amp[778] - amp[779] - std::complex<double>
+ (0, 1) * amp[780] + std::complex<double> (0, 1) * amp[784] +
+ std::complex<double> (0, 1) * amp[783] - std::complex<double> (0, 1) *
+ amp[787] - std::complex<double> (0, 1) * amp[789] + amp[790] +
+ std::complex<double> (0, 1) * amp[793] + std::complex<double> (0, 1) *
+ amp[792] - std::complex<double> (0, 1) * amp[796] - amp[797] -
+ std::complex<double> (0, 1) * amp[798] + std::complex<double> (0, 1) *
+ amp[802] + std::complex<double> (0, 1) * amp[801] - std::complex<double>
+ (0, 1) * amp[805] - std::complex<double> (0, 1) * amp[807] + amp[808] +
+ std::complex<double> (0, 1) * amp[811] + std::complex<double> (0, 1) *
+ amp[810] + std::complex<double> (0, 1) * amp[865] + std::complex<double>
+ (0, 1) * amp[866] + amp[867] - std::complex<double> (0, 1) * amp[872] -
+ std::complex<double> (0, 1) * amp[871] + std::complex<double> (0, 1) *
+ amp[875] - std::complex<double> (0, 1) * amp[881] - std::complex<double>
+ (0, 1) * amp[880] + std::complex<double> (0, 1) * amp[883] +
+ std::complex<double> (0, 1) * amp[884] + amp[885] - std::complex<double>
+ (0, 1) * amp[890] - std::complex<double> (0, 1) * amp[889] +
+ std::complex<double> (0, 1) * amp[893] - std::complex<double> (0, 1) *
+ amp[899] - std::complex<double> (0, 1) * amp[898] + amp[960] + amp[961] +
+ std::complex<double> (0, 1) * amp[963] + std::complex<double> (0, 1) *
+ amp[964] + std::complex<double> (0, 1) * amp[969] + std::complex<double>
+ (0, 1) * amp[970] + amp[972] + amp[973] + std::complex<double> (0, 1) *
+ amp[975] + std::complex<double> (0, 1) * amp[976] + std::complex<double>
+ (0, 1) * amp[981] + std::complex<double> (0, 1) * amp[982] +
+ std::complex<double> (0, 1) * amp[989] + std::complex<double> (0, 1) *
+ amp[988] - amp[992] - amp[991] + std::complex<double> (0, 1) * amp[995] +
+ std::complex<double> (0, 1) * amp[994] + std::complex<double> (0, 1) *
+ amp[1001] + std::complex<double> (0, 1) * amp[1000] - amp[1004] -
+ amp[1003] + std::complex<double> (0, 1) * amp[1007] +
+ std::complex<double> (0, 1) * amp[1006];
+ jamp[14] = +amp[219] + amp[225] + amp[260] + amp[263] + amp[265] + amp[266] +
+ amp[269] + amp[271] + std::complex<double> (0, 1) * amp[272] +
+ std::complex<double> (0, 1) * amp[273] + std::complex<double> (0, 1) *
+ amp[274] + std::complex<double> (0, 1) * amp[275] + amp[277] +
+ std::complex<double> (0, 1) * amp[278] + amp[280] + amp[283] +
+ std::complex<double> (0, 1) * amp[284] + amp[286] - std::complex<double>
+ (0, 1) * amp[288] + amp[289] - std::complex<double> (0, 1) * amp[291] +
+ amp[292] - std::complex<double> (0, 1) * amp[293] - std::complex<double>
+ (0, 1) * amp[294] + amp[295] - std::complex<double> (0, 1) * amp[297] +
+ amp[298] - std::complex<double> (0, 1) * amp[299] - amp[314] - amp[313] -
+ amp[317] - amp[316] - amp[320] - amp[319] - amp[323] - amp[322] +
+ amp[613] + amp[619] + std::complex<double> (0, 1) * amp[624] - amp[626] -
+ amp[628] + std::complex<double> (0, 1) * amp[630] - amp[632] - amp[634] +
+ std::complex<double> (0, 1) * amp[648] - amp[650] + std::complex<double>
+ (0, 1) * amp[651] - amp[652] + std::complex<double> (0, 1) * amp[653] +
+ std::complex<double> (0, 1) * amp[654] - amp[656] + std::complex<double>
+ (0, 1) * amp[657] - amp[658] + std::complex<double> (0, 1) * amp[659] +
+ amp[662] - amp[660] + amp[665] - amp[663] + amp[668] - amp[666] +
+ amp[671] - amp[669] + std::complex<double> (0, 1) * amp[674] +
+ std::complex<double> (0, 1) * amp[676] + amp[677] - std::complex<double>
+ (0, 1) * amp[680] - std::complex<double> (0, 1) * amp[679] +
+ std::complex<double> (0, 1) * amp[683] - amp[684] + std::complex<double>
+ (0, 1) * amp[685] - std::complex<double> (0, 1) * amp[689] -
+ std::complex<double> (0, 1) * amp[688] + std::complex<double> (0, 1) *
+ amp[692] + std::complex<double> (0, 1) * amp[694] + amp[695] -
+ std::complex<double> (0, 1) * amp[698] - std::complex<double> (0, 1) *
+ amp[697] + std::complex<double> (0, 1) * amp[701] - amp[702] +
+ std::complex<double> (0, 1) * amp[703] - std::complex<double> (0, 1) *
+ amp[707] - std::complex<double> (0, 1) * amp[706] - std::complex<double>
+ (0, 1) * amp[777] + std::complex<double> (0, 1) * amp[778] + amp[779] -
+ std::complex<double> (0, 1) * amp[784] + std::complex<double> (0, 1) *
+ amp[782] + std::complex<double> (0, 1) * amp[787] - std::complex<double>
+ (0, 1) * amp[793] + std::complex<double> (0, 1) * amp[791] -
+ std::complex<double> (0, 1) * amp[795] + std::complex<double> (0, 1) *
+ amp[796] + amp[797] - std::complex<double> (0, 1) * amp[802] +
+ std::complex<double> (0, 1) * amp[800] + std::complex<double> (0, 1) *
+ amp[805] - std::complex<double> (0, 1) * amp[811] + std::complex<double>
+ (0, 1) * amp[809] + amp[812] + std::complex<double> (0, 1) * amp[814] +
+ amp[816] + std::complex<double> (0, 1) * amp[817] + amp[819] + amp[820] +
+ std::complex<double> (0, 1) * amp[822] + amp[824] + std::complex<double>
+ (0, 1) * amp[825] + amp[827] + std::complex<double> (0, 1) * amp[830] -
+ std::complex<double> (0, 1) * amp[836] - std::complex<double> (0, 1) *
+ amp[835] + std::complex<double> (0, 1) * amp[838] + std::complex<double>
+ (0, 1) * amp[839] - amp[840] - std::complex<double> (0, 1) * amp[845] -
+ std::complex<double> (0, 1) * amp[844] + std::complex<double> (0, 1) *
+ amp[848] - std::complex<double> (0, 1) * amp[854] - std::complex<double>
+ (0, 1) * amp[853] + std::complex<double> (0, 1) * amp[856] +
+ std::complex<double> (0, 1) * amp[857] - amp[858] - std::complex<double>
+ (0, 1) * amp[863] - std::complex<double> (0, 1) * amp[862] -
+ std::complex<double> (0, 1) * amp[941] + std::complex<double> (0, 1) *
+ amp[939] + amp[944] - amp[942] - std::complex<double> (0, 1) * amp[947] +
+ std::complex<double> (0, 1) * amp[945] - std::complex<double> (0, 1) *
+ amp[953] + std::complex<double> (0, 1) * amp[951] + amp[956] - amp[954] -
+ std::complex<double> (0, 1) * amp[959] + std::complex<double> (0, 1) *
+ amp[957] - amp[962] - amp[961] - std::complex<double> (0, 1) * amp[965] -
+ std::complex<double> (0, 1) * amp[964] - std::complex<double> (0, 1) *
+ amp[971] - std::complex<double> (0, 1) * amp[970] - amp[974] - amp[973] -
+ std::complex<double> (0, 1) * amp[977] - std::complex<double> (0, 1) *
+ amp[976] - std::complex<double> (0, 1) * amp[983] - std::complex<double>
+ (0, 1) * amp[982];
+ jamp[15] = +amp[218] + amp[224] + amp[229] + amp[230] + amp[232] + amp[235] +
+ amp[236] + amp[238] - std::complex<double> (0, 1) * amp[240] -
+ std::complex<double> (0, 1) * amp[241] - std::complex<double> (0, 1) *
+ amp[242] - std::complex<double> (0, 1) * amp[243] + std::complex<double>
+ (0, 1) * amp[288] - amp[289] + std::complex<double> (0, 1) * amp[291] -
+ amp[292] + std::complex<double> (0, 1) * amp[293] + std::complex<double>
+ (0, 1) * amp[294] - amp[295] + std::complex<double> (0, 1) * amp[297] -
+ amp[298] + std::complex<double> (0, 1) * amp[299] + amp[301] -
+ std::complex<double> (0, 1) * amp[303] + amp[304] + amp[307] -
+ std::complex<double> (0, 1) * amp[309] + amp[310] + amp[312] + amp[313] +
+ amp[315] + amp[316] + amp[318] + amp[319] + amp[321] + amp[322] +
+ amp[437] + amp[443] + std::complex<double> (0, 1) * amp[445] + amp[446] +
+ std::complex<double> (0, 1) * amp[447] + amp[448] + std::complex<double>
+ (0, 1) * amp[449] + std::complex<double> (0, 1) * amp[451] + amp[452] +
+ std::complex<double> (0, 1) * amp[453] + amp[454] + std::complex<double>
+ (0, 1) * amp[455] - std::complex<double> (0, 1) * amp[456] + amp[458] +
+ amp[460] - std::complex<double> (0, 1) * amp[462] + amp[464] + amp[466] -
+ amp[482] - amp[481] - amp[485] - amp[484] - amp[488] - amp[487] -
+ amp[491] - amp[490] + std::complex<double> (0, 1) * amp[777] -
+ std::complex<double> (0, 1) * amp[778] - amp[779] + std::complex<double>
+ (0, 1) * amp[784] - std::complex<double> (0, 1) * amp[782] -
+ std::complex<double> (0, 1) * amp[787] + std::complex<double> (0, 1) *
+ amp[793] - std::complex<double> (0, 1) * amp[791] + std::complex<double>
+ (0, 1) * amp[795] - std::complex<double> (0, 1) * amp[796] - amp[797] +
+ std::complex<double> (0, 1) * amp[802] - std::complex<double> (0, 1) *
+ amp[800] - std::complex<double> (0, 1) * amp[805] + std::complex<double>
+ (0, 1) * amp[811] - std::complex<double> (0, 1) * amp[809] - amp[812] -
+ std::complex<double> (0, 1) * amp[814] - amp[816] - std::complex<double>
+ (0, 1) * amp[817] - amp[819] - amp[820] - std::complex<double> (0, 1) *
+ amp[822] - amp[824] - std::complex<double> (0, 1) * amp[825] - amp[827] +
+ std::complex<double> (0, 1) * amp[832] + std::complex<double> (0, 1) *
+ amp[834] + std::complex<double> (0, 1) * amp[835] + std::complex<double>
+ (0, 1) * amp[837] + std::complex<double> (0, 1) * amp[841] + amp[842] +
+ std::complex<double> (0, 1) * amp[843] + std::complex<double> (0, 1) *
+ amp[844] + std::complex<double> (0, 1) * amp[850] + std::complex<double>
+ (0, 1) * amp[852] + std::complex<double> (0, 1) * amp[853] +
+ std::complex<double> (0, 1) * amp[855] + std::complex<double> (0, 1) *
+ amp[859] + amp[860] + std::complex<double> (0, 1) * amp[861] +
+ std::complex<double> (0, 1) * amp[862] + std::complex<double> (0, 1) *
+ amp[866] + amp[867] + std::complex<double> (0, 1) * amp[868] -
+ std::complex<double> (0, 1) * amp[872] + std::complex<double> (0, 1) *
+ amp[870] + std::complex<double> (0, 1) * amp[875] + std::complex<double>
+ (0, 1) * amp[877] + amp[878] - std::complex<double> (0, 1) * amp[881] +
+ std::complex<double> (0, 1) * amp[879] + std::complex<double> (0, 1) *
+ amp[884] + amp[885] + std::complex<double> (0, 1) * amp[886] -
+ std::complex<double> (0, 1) * amp[890] + std::complex<double> (0, 1) *
+ amp[888] + std::complex<double> (0, 1) * amp[893] + std::complex<double>
+ (0, 1) * amp[895] + amp[896] - std::complex<double> (0, 1) * amp[899] +
+ std::complex<double> (0, 1) * amp[897] + amp[960] + amp[961] +
+ std::complex<double> (0, 1) * amp[963] + std::complex<double> (0, 1) *
+ amp[964] + std::complex<double> (0, 1) * amp[969] + std::complex<double>
+ (0, 1) * amp[970] + amp[972] + amp[973] + std::complex<double> (0, 1) *
+ amp[975] + std::complex<double> (0, 1) * amp[976] + std::complex<double>
+ (0, 1) * amp[981] + std::complex<double> (0, 1) * amp[982] -
+ std::complex<double> (0, 1) * amp[1013] - std::complex<double> (0, 1) *
+ amp[1012] - amp[1016] - amp[1015] - std::complex<double> (0, 1) *
+ amp[1019] - std::complex<double> (0, 1) * amp[1018] -
+ std::complex<double> (0, 1) * amp[1025] - std::complex<double> (0, 1) *
+ amp[1024] - amp[1028] - amp[1027] - std::complex<double> (0, 1) *
+ amp[1031] - std::complex<double> (0, 1) * amp[1030];
+ jamp[16] = +amp[221] + amp[227] + amp[244] + amp[247] + amp[249] + amp[250] +
+ amp[253] + amp[255] + std::complex<double> (0, 1) * amp[256] +
+ std::complex<double> (0, 1) * amp[257] + std::complex<double> (0, 1) *
+ amp[258] + std::complex<double> (0, 1) * amp[259] - std::complex<double>
+ (0, 1) * amp[276] + amp[277] - std::complex<double> (0, 1) * amp[279] +
+ amp[280] - std::complex<double> (0, 1) * amp[281] - std::complex<double>
+ (0, 1) * amp[282] + amp[283] - std::complex<double> (0, 1) * amp[285] +
+ amp[286] - std::complex<double> (0, 1) * amp[287] + amp[289] +
+ std::complex<double> (0, 1) * amp[290] + amp[292] + amp[295] +
+ std::complex<double> (0, 1) * amp[296] + amp[298] - amp[314] - amp[313] -
+ amp[317] - amp[316] - amp[320] - amp[319] - amp[323] - amp[322] +
+ amp[492] + amp[498] + std::complex<double> (0, 1) * amp[516] - amp[518] -
+ amp[520] + std::complex<double> (0, 1) * amp[522] - amp[524] - amp[526] -
+ std::complex<double> (0, 1) * amp[528] + amp[530] - std::complex<double>
+ (0, 1) * amp[531] + amp[532] - std::complex<double> (0, 1) * amp[533] -
+ std::complex<double> (0, 1) * amp[534] + amp[536] - std::complex<double>
+ (0, 1) * amp[537] + amp[538] - std::complex<double> (0, 1) * amp[539] +
+ amp[540] + amp[541] + amp[543] + amp[544] + amp[546] + amp[547] +
+ amp[549] + amp[550] - std::complex<double> (0, 1) * amp[672] +
+ std::complex<double> (0, 1) * amp[676] + amp[677] - std::complex<double>
+ (0, 1) * amp[678] - std::complex<double> (0, 1) * amp[679] +
+ std::complex<double> (0, 1) * amp[685] - std::complex<double> (0, 1) *
+ amp[687] - std::complex<double> (0, 1) * amp[688] - std::complex<double>
+ (0, 1) * amp[690] + std::complex<double> (0, 1) * amp[694] + amp[695] -
+ std::complex<double> (0, 1) * amp[696] - std::complex<double> (0, 1) *
+ amp[697] + std::complex<double> (0, 1) * amp[703] - std::complex<double>
+ (0, 1) * amp[705] - std::complex<double> (0, 1) * amp[706] - amp[708] -
+ std::complex<double> (0, 1) * amp[710] - amp[712] - std::complex<double>
+ (0, 1) * amp[713] - amp[715] - amp[716] - std::complex<double> (0, 1) *
+ amp[718] - amp[720] - std::complex<double> (0, 1) * amp[721] - amp[723] +
+ std::complex<double> (0, 1) * amp[778] + amp[779] + std::complex<double>
+ (0, 1) * amp[780] - std::complex<double> (0, 1) * amp[784] -
+ std::complex<double> (0, 1) * amp[783] + std::complex<double> (0, 1) *
+ amp[787] + std::complex<double> (0, 1) * amp[789] - amp[790] -
+ std::complex<double> (0, 1) * amp[793] - std::complex<double> (0, 1) *
+ amp[792] + std::complex<double> (0, 1) * amp[796] + amp[797] +
+ std::complex<double> (0, 1) * amp[798] - std::complex<double> (0, 1) *
+ amp[802] - std::complex<double> (0, 1) * amp[801] + std::complex<double>
+ (0, 1) * amp[805] + std::complex<double> (0, 1) * amp[807] - amp[808] -
+ std::complex<double> (0, 1) * amp[811] - std::complex<double> (0, 1) *
+ amp[810] - std::complex<double> (0, 1) * amp[902] + std::complex<double>
+ (0, 1) * amp[908] + std::complex<double> (0, 1) * amp[907] -
+ std::complex<double> (0, 1) * amp[910] - std::complex<double> (0, 1) *
+ amp[911] + amp[912] + std::complex<double> (0, 1) * amp[917] +
+ std::complex<double> (0, 1) * amp[916] - std::complex<double> (0, 1) *
+ amp[920] + std::complex<double> (0, 1) * amp[926] + std::complex<double>
+ (0, 1) * amp[925] - std::complex<double> (0, 1) * amp[928] -
+ std::complex<double> (0, 1) * amp[929] + amp[930] + std::complex<double>
+ (0, 1) * amp[935] + std::complex<double> (0, 1) * amp[934] - amp[962] -
+ amp[961] - std::complex<double> (0, 1) * amp[965] - std::complex<double>
+ (0, 1) * amp[964] - std::complex<double> (0, 1) * amp[971] -
+ std::complex<double> (0, 1) * amp[970] - amp[974] - amp[973] -
+ std::complex<double> (0, 1) * amp[977] - std::complex<double> (0, 1) *
+ amp[976] - std::complex<double> (0, 1) * amp[983] - std::complex<double>
+ (0, 1) * amp[982] - std::complex<double> (0, 1) * amp[987] -
+ std::complex<double> (0, 1) * amp[988] + amp[990] + amp[991] -
+ std::complex<double> (0, 1) * amp[993] - std::complex<double> (0, 1) *
+ amp[994] - std::complex<double> (0, 1) * amp[999] - std::complex<double>
+ (0, 1) * amp[1000] + amp[1002] + amp[1003] - std::complex<double> (0, 1)
+ * amp[1005] - std::complex<double> (0, 1) * amp[1006];
+ jamp[17] = +amp[220] + amp[226] + amp[228] + amp[231] + amp[233] + amp[234] +
+ amp[237] + amp[239] + std::complex<double> (0, 1) * amp[240] +
+ std::complex<double> (0, 1) * amp[241] + std::complex<double> (0, 1) *
+ amp[242] + std::complex<double> (0, 1) * amp[243] + std::complex<double>
+ (0, 1) * amp[276] - amp[277] + std::complex<double> (0, 1) * amp[279] -
+ amp[280] + std::complex<double> (0, 1) * amp[281] + std::complex<double>
+ (0, 1) * amp[282] - amp[283] + std::complex<double> (0, 1) * amp[285] -
+ amp[286] + std::complex<double> (0, 1) * amp[287] - amp[301] +
+ std::complex<double> (0, 1) * amp[303] - amp[304] - amp[307] +
+ std::complex<double> (0, 1) * amp[309] - amp[310] + amp[314] - amp[312] +
+ amp[317] - amp[315] + amp[320] - amp[318] + amp[323] - amp[321] +
+ amp[432] + amp[438] + std::complex<double> (0, 1) * amp[456] - amp[458] -
+ amp[460] + std::complex<double> (0, 1) * amp[462] - amp[464] - amp[466] -
+ std::complex<double> (0, 1) * amp[468] + amp[470] - std::complex<double>
+ (0, 1) * amp[471] + amp[472] - std::complex<double> (0, 1) * amp[473] -
+ std::complex<double> (0, 1) * amp[474] + amp[476] - std::complex<double>
+ (0, 1) * amp[477] + amp[478] - std::complex<double> (0, 1) * amp[479] +
+ amp[480] + amp[481] + amp[483] + amp[484] + amp[486] + amp[487] +
+ amp[489] + amp[490] + std::complex<double> (0, 1) * amp[672] -
+ std::complex<double> (0, 1) * amp[676] - amp[677] + std::complex<double>
+ (0, 1) * amp[678] + std::complex<double> (0, 1) * amp[679] -
+ std::complex<double> (0, 1) * amp[685] + std::complex<double> (0, 1) *
+ amp[687] + std::complex<double> (0, 1) * amp[688] + std::complex<double>
+ (0, 1) * amp[690] - std::complex<double> (0, 1) * amp[694] - amp[695] +
+ std::complex<double> (0, 1) * amp[696] + std::complex<double> (0, 1) *
+ amp[697] - std::complex<double> (0, 1) * amp[703] + std::complex<double>
+ (0, 1) * amp[705] + std::complex<double> (0, 1) * amp[706] + amp[708] +
+ std::complex<double> (0, 1) * amp[710] + amp[712] + std::complex<double>
+ (0, 1) * amp[713] + amp[715] + amp[716] + std::complex<double> (0, 1) *
+ amp[718] + amp[720] + std::complex<double> (0, 1) * amp[721] + amp[723] -
+ std::complex<double> (0, 1) * amp[866] - amp[867] - std::complex<double>
+ (0, 1) * amp[868] + std::complex<double> (0, 1) * amp[872] -
+ std::complex<double> (0, 1) * amp[870] - std::complex<double> (0, 1) *
+ amp[875] - std::complex<double> (0, 1) * amp[877] - amp[878] +
+ std::complex<double> (0, 1) * amp[881] - std::complex<double> (0, 1) *
+ amp[879] - std::complex<double> (0, 1) * amp[884] - amp[885] -
+ std::complex<double> (0, 1) * amp[886] + std::complex<double> (0, 1) *
+ amp[890] - std::complex<double> (0, 1) * amp[888] - std::complex<double>
+ (0, 1) * amp[893] - std::complex<double> (0, 1) * amp[895] - amp[896] +
+ std::complex<double> (0, 1) * amp[899] - std::complex<double> (0, 1) *
+ amp[897] + std::complex<double> (0, 1) * amp[904] - std::complex<double>
+ (0, 1) * amp[908] + std::complex<double> (0, 1) * amp[906] -
+ std::complex<double> (0, 1) * amp[909] + std::complex<double> (0, 1) *
+ amp[913] + amp[914] - std::complex<double> (0, 1) * amp[917] +
+ std::complex<double> (0, 1) * amp[915] + std::complex<double> (0, 1) *
+ amp[922] - std::complex<double> (0, 1) * amp[926] + std::complex<double>
+ (0, 1) * amp[924] - std::complex<double> (0, 1) * amp[927] +
+ std::complex<double> (0, 1) * amp[931] + amp[932] - std::complex<double>
+ (0, 1) * amp[935] + std::complex<double> (0, 1) * amp[933] + amp[962] -
+ amp[960] + std::complex<double> (0, 1) * amp[965] - std::complex<double>
+ (0, 1) * amp[963] + std::complex<double> (0, 1) * amp[971] -
+ std::complex<double> (0, 1) * amp[969] + amp[974] - amp[972] +
+ std::complex<double> (0, 1) * amp[977] - std::complex<double> (0, 1) *
+ amp[975] + std::complex<double> (0, 1) * amp[983] - std::complex<double>
+ (0, 1) * amp[981] + std::complex<double> (0, 1) * amp[1011] +
+ std::complex<double> (0, 1) * amp[1012] + amp[1014] + amp[1015] +
+ std::complex<double> (0, 1) * amp[1017] + std::complex<double> (0, 1) *
+ amp[1018] + std::complex<double> (0, 1) * amp[1023] +
+ std::complex<double> (0, 1) * amp[1024] + amp[1026] + amp[1027] +
+ std::complex<double> (0, 1) * amp[1029] + std::complex<double> (0, 1) *
+ amp[1030];
+ jamp[18] = +amp[325] + amp[331] + amp[369] + amp[370] + amp[372] + amp[375] +
+ amp[376] + amp[378] - std::complex<double> (0, 1) * amp[380] -
+ std::complex<double> (0, 1) * amp[381] - std::complex<double> (0, 1) *
+ amp[382] - std::complex<double> (0, 1) * amp[383] - amp[385] -
+ std::complex<double> (0, 1) * amp[386] - amp[388] - amp[391] -
+ std::complex<double> (0, 1) * amp[392] - amp[394] - std::complex<double>
+ (0, 1) * amp[408] - amp[409] - std::complex<double> (0, 1) * amp[410] -
+ amp[412] - std::complex<double> (0, 1) * amp[413] - std::complex<double>
+ (0, 1) * amp[414] - amp[415] - std::complex<double> (0, 1) * amp[416] -
+ amp[418] - std::complex<double> (0, 1) * amp[419] + amp[422] - amp[420] +
+ amp[425] - amp[423] + amp[428] - amp[426] + amp[431] - amp[429] +
+ amp[555] + amp[561] - std::complex<double> (0, 1) * amp[564] + amp[566] +
+ amp[568] - std::complex<double> (0, 1) * amp[570] + amp[572] + amp[574] +
+ std::complex<double> (0, 1) * amp[577] + amp[578] + std::complex<double>
+ (0, 1) * amp[579] + amp[580] + std::complex<double> (0, 1) * amp[581] +
+ std::complex<double> (0, 1) * amp[583] + amp[584] + std::complex<double>
+ (0, 1) * amp[585] + amp[586] + std::complex<double> (0, 1) * amp[587] -
+ amp[602] - amp[601] - amp[605] - amp[604] - amp[608] - amp[607] -
+ amp[611] - amp[610] - std::complex<double> (0, 1) * amp[674] - amp[675] -
+ std::complex<double> (0, 1) * amp[676] + std::complex<double> (0, 1) *
+ amp[680] + std::complex<double> (0, 1) * amp[679] - std::complex<double>
+ (0, 1) * amp[683] - std::complex<double> (0, 1) * amp[685] + amp[686] +
+ std::complex<double> (0, 1) * amp[689] + std::complex<double> (0, 1) *
+ amp[688] - std::complex<double> (0, 1) * amp[692] - amp[693] -
+ std::complex<double> (0, 1) * amp[694] + std::complex<double> (0, 1) *
+ amp[698] + std::complex<double> (0, 1) * amp[697] - std::complex<double>
+ (0, 1) * amp[701] - std::complex<double> (0, 1) * amp[703] + amp[704] +
+ std::complex<double> (0, 1) * amp[707] + std::complex<double> (0, 1) *
+ amp[706] - std::complex<double> (0, 1) * amp[778] + std::complex<double>
+ (0, 1) * amp[784] - std::complex<double> (0, 1) * amp[782] +
+ std::complex<double> (0, 1) * amp[786] - std::complex<double> (0, 1) *
+ amp[787] + amp[788] + std::complex<double> (0, 1) * amp[793] -
+ std::complex<double> (0, 1) * amp[791] - std::complex<double> (0, 1) *
+ amp[796] + std::complex<double> (0, 1) * amp[802] - std::complex<double>
+ (0, 1) * amp[800] + std::complex<double> (0, 1) * amp[804] -
+ std::complex<double> (0, 1) * amp[805] + amp[806] + std::complex<double>
+ (0, 1) * amp[811] - std::complex<double> (0, 1) * amp[809] + amp[813] -
+ std::complex<double> (0, 1) * amp[814] + amp[815] - std::complex<double>
+ (0, 1) * amp[817] + amp[818] + amp[821] - std::complex<double> (0, 1) *
+ amp[822] + amp[823] - std::complex<double> (0, 1) * amp[825] + amp[826] -
+ std::complex<double> (0, 1) * amp[829] - std::complex<double> (0, 1) *
+ amp[830] - amp[831] + std::complex<double> (0, 1) * amp[836] +
+ std::complex<double> (0, 1) * amp[835] - std::complex<double> (0, 1) *
+ amp[839] + std::complex<double> (0, 1) * amp[845] + std::complex<double>
+ (0, 1) * amp[844] - std::complex<double> (0, 1) * amp[847] -
+ std::complex<double> (0, 1) * amp[848] - amp[849] + std::complex<double>
+ (0, 1) * amp[854] + std::complex<double> (0, 1) * amp[853] -
+ std::complex<double> (0, 1) * amp[857] + std::complex<double> (0, 1) *
+ amp[863] + std::complex<double> (0, 1) * amp[862] + amp[938] - amp[936] +
+ std::complex<double> (0, 1) * amp[941] - std::complex<double> (0, 1) *
+ amp[939] + std::complex<double> (0, 1) * amp[947] - std::complex<double>
+ (0, 1) * amp[945] + amp[950] - amp[948] + std::complex<double> (0, 1) *
+ amp[953] - std::complex<double> (0, 1) * amp[951] + std::complex<double>
+ (0, 1) * amp[959] - std::complex<double> (0, 1) * amp[957] +
+ std::complex<double> (0, 1) * amp[965] + std::complex<double> (0, 1) *
+ amp[964] - amp[968] - amp[967] + std::complex<double> (0, 1) * amp[971] +
+ std::complex<double> (0, 1) * amp[970] + std::complex<double> (0, 1) *
+ amp[977] + std::complex<double> (0, 1) * amp[976] - amp[980] - amp[979] +
+ std::complex<double> (0, 1) * amp[983] + std::complex<double> (0, 1) *
+ amp[982];
+ jamp[19] = +amp[324] + amp[330] + amp[353] + amp[354] + amp[356] + amp[359] +
+ amp[360] + amp[362] - std::complex<double> (0, 1) * amp[364] -
+ std::complex<double> (0, 1) * amp[365] - std::complex<double> (0, 1) *
+ amp[366] - std::complex<double> (0, 1) * amp[367] - amp[397] -
+ std::complex<double> (0, 1) * amp[398] - amp[400] - amp[403] -
+ std::complex<double> (0, 1) * amp[404] - amp[406] + std::complex<double>
+ (0, 1) * amp[408] + amp[409] + std::complex<double> (0, 1) * amp[410] +
+ amp[412] + std::complex<double> (0, 1) * amp[413] + std::complex<double>
+ (0, 1) * amp[414] + amp[415] + std::complex<double> (0, 1) * amp[416] +
+ amp[418] + std::complex<double> (0, 1) * amp[419] + amp[420] + amp[421] +
+ amp[423] + amp[424] + amp[426] + amp[427] + amp[429] + amp[430] +
+ amp[495] + amp[501] - std::complex<double> (0, 1) * amp[504] + amp[506] +
+ amp[508] - std::complex<double> (0, 1) * amp[510] + amp[512] + amp[514] +
+ std::complex<double> (0, 1) * amp[517] + amp[518] + std::complex<double>
+ (0, 1) * amp[519] + amp[520] + std::complex<double> (0, 1) * amp[521] +
+ std::complex<double> (0, 1) * amp[523] + amp[524] + std::complex<double>
+ (0, 1) * amp[525] + amp[526] + std::complex<double> (0, 1) * amp[527] -
+ amp[542] - amp[541] - amp[545] - amp[544] - amp[548] - amp[547] -
+ amp[551] - amp[550] - std::complex<double> (0, 1) * amp[726] - amp[727] -
+ std::complex<double> (0, 1) * amp[728] + std::complex<double> (0, 1) *
+ amp[732] + std::complex<double> (0, 1) * amp[731] - std::complex<double>
+ (0, 1) * amp[735] - std::complex<double> (0, 1) * amp[737] + amp[738] +
+ std::complex<double> (0, 1) * amp[741] + std::complex<double> (0, 1) *
+ amp[740] - std::complex<double> (0, 1) * amp[744] - amp[745] -
+ std::complex<double> (0, 1) * amp[746] + std::complex<double> (0, 1) *
+ amp[750] + std::complex<double> (0, 1) * amp[749] - std::complex<double>
+ (0, 1) * amp[753] - std::complex<double> (0, 1) * amp[755] + amp[756] +
+ std::complex<double> (0, 1) * amp[759] + std::complex<double> (0, 1) *
+ amp[758] - std::complex<double> (0, 1) * amp[780] + std::complex<double>
+ (0, 1) * amp[782] + std::complex<double> (0, 1) * amp[783] +
+ std::complex<double> (0, 1) * amp[785] - std::complex<double> (0, 1) *
+ amp[789] + amp[790] + std::complex<double> (0, 1) * amp[791] +
+ std::complex<double> (0, 1) * amp[792] - std::complex<double> (0, 1) *
+ amp[798] + std::complex<double> (0, 1) * amp[800] + std::complex<double>
+ (0, 1) * amp[801] + std::complex<double> (0, 1) * amp[803] -
+ std::complex<double> (0, 1) * amp[807] + amp[808] + std::complex<double>
+ (0, 1) * amp[809] + std::complex<double> (0, 1) * amp[810] - amp[813] +
+ std::complex<double> (0, 1) * amp[814] - amp[815] + std::complex<double>
+ (0, 1) * amp[817] - amp[818] - amp[821] + std::complex<double> (0, 1) *
+ amp[822] - amp[823] + std::complex<double> (0, 1) * amp[825] - amp[826] +
+ std::complex<double> (0, 1) * amp[829] + std::complex<double> (0, 1) *
+ amp[830] + amp[831] - std::complex<double> (0, 1) * amp[836] -
+ std::complex<double> (0, 1) * amp[835] + std::complex<double> (0, 1) *
+ amp[839] - std::complex<double> (0, 1) * amp[845] - std::complex<double>
+ (0, 1) * amp[844] + std::complex<double> (0, 1) * amp[847] +
+ std::complex<double> (0, 1) * amp[848] + amp[849] - std::complex<double>
+ (0, 1) * amp[854] - std::complex<double> (0, 1) * amp[853] +
+ std::complex<double> (0, 1) * amp[857] - std::complex<double> (0, 1) *
+ amp[863] - std::complex<double> (0, 1) * amp[862] + amp[936] + amp[937] +
+ std::complex<double> (0, 1) * amp[939] + std::complex<double> (0, 1) *
+ amp[940] + std::complex<double> (0, 1) * amp[945] + std::complex<double>
+ (0, 1) * amp[946] + amp[948] + amp[949] + std::complex<double> (0, 1) *
+ amp[951] + std::complex<double> (0, 1) * amp[952] + std::complex<double>
+ (0, 1) * amp[957] + std::complex<double> (0, 1) * amp[958] +
+ std::complex<double> (0, 1) * amp[989] + std::complex<double> (0, 1) *
+ amp[988] - amp[992] - amp[991] + std::complex<double> (0, 1) * amp[995] +
+ std::complex<double> (0, 1) * amp[994] + std::complex<double> (0, 1) *
+ amp[1001] + std::complex<double> (0, 1) * amp[1000] - amp[1004] -
+ amp[1003] + std::complex<double> (0, 1) * amp[1007] +
+ std::complex<double> (0, 1) * amp[1006];
+ jamp[20] = +amp[327] + amp[333] + amp[368] + amp[371] + amp[373] + amp[374] +
+ amp[377] + amp[379] + std::complex<double> (0, 1) * amp[380] +
+ std::complex<double> (0, 1) * amp[381] + std::complex<double> (0, 1) *
+ amp[382] + std::complex<double> (0, 1) * amp[383] + amp[385] +
+ std::complex<double> (0, 1) * amp[386] + amp[388] + amp[391] +
+ std::complex<double> (0, 1) * amp[392] + amp[394] - std::complex<double>
+ (0, 1) * amp[396] + amp[397] - std::complex<double> (0, 1) * amp[399] +
+ amp[400] - std::complex<double> (0, 1) * amp[401] - std::complex<double>
+ (0, 1) * amp[402] + amp[403] - std::complex<double> (0, 1) * amp[405] +
+ amp[406] - std::complex<double> (0, 1) * amp[407] - amp[422] - amp[421] -
+ amp[425] - amp[424] - amp[428] - amp[427] - amp[431] - amp[430] +
+ amp[553] + amp[559] + std::complex<double> (0, 1) * amp[564] - amp[566] -
+ amp[568] + std::complex<double> (0, 1) * amp[570] - amp[572] - amp[574] +
+ std::complex<double> (0, 1) * amp[588] - amp[590] + std::complex<double>
+ (0, 1) * amp[591] - amp[592] + std::complex<double> (0, 1) * amp[593] +
+ std::complex<double> (0, 1) * amp[594] - amp[596] + std::complex<double>
+ (0, 1) * amp[597] - amp[598] + std::complex<double> (0, 1) * amp[599] +
+ amp[602] - amp[600] + amp[605] - amp[603] + amp[608] - amp[606] +
+ amp[611] - amp[609] + std::complex<double> (0, 1) * amp[674] + amp[675] +
+ std::complex<double> (0, 1) * amp[676] - std::complex<double> (0, 1) *
+ amp[680] - std::complex<double> (0, 1) * amp[679] + std::complex<double>
+ (0, 1) * amp[683] + std::complex<double> (0, 1) * amp[685] - amp[686] -
+ std::complex<double> (0, 1) * amp[689] - std::complex<double> (0, 1) *
+ amp[688] + std::complex<double> (0, 1) * amp[692] + amp[693] +
+ std::complex<double> (0, 1) * amp[694] - std::complex<double> (0, 1) *
+ amp[698] - std::complex<double> (0, 1) * amp[697] + std::complex<double>
+ (0, 1) * amp[701] + std::complex<double> (0, 1) * amp[703] - amp[704] -
+ std::complex<double> (0, 1) * amp[707] - std::complex<double> (0, 1) *
+ amp[706] - std::complex<double> (0, 1) * amp[725] + std::complex<double>
+ (0, 1) * amp[726] + amp[727] - std::complex<double> (0, 1) * amp[732] +
+ std::complex<double> (0, 1) * amp[730] + std::complex<double> (0, 1) *
+ amp[735] - std::complex<double> (0, 1) * amp[741] + std::complex<double>
+ (0, 1) * amp[739] - std::complex<double> (0, 1) * amp[743] +
+ std::complex<double> (0, 1) * amp[744] + amp[745] - std::complex<double>
+ (0, 1) * amp[750] + std::complex<double> (0, 1) * amp[748] +
+ std::complex<double> (0, 1) * amp[753] - std::complex<double> (0, 1) *
+ amp[759] + std::complex<double> (0, 1) * amp[757] + amp[760] +
+ std::complex<double> (0, 1) * amp[762] + amp[764] + std::complex<double>
+ (0, 1) * amp[765] + amp[767] + amp[768] + std::complex<double> (0, 1) *
+ amp[770] + amp[772] + std::complex<double> (0, 1) * amp[773] + amp[775] +
+ std::complex<double> (0, 1) * amp[866] - std::complex<double> (0, 1) *
+ amp[872] - std::complex<double> (0, 1) * amp[871] + std::complex<double>
+ (0, 1) * amp[874] + std::complex<double> (0, 1) * amp[875] - amp[876] -
+ std::complex<double> (0, 1) * amp[881] - std::complex<double> (0, 1) *
+ amp[880] + std::complex<double> (0, 1) * amp[884] - std::complex<double>
+ (0, 1) * amp[890] - std::complex<double> (0, 1) * amp[889] +
+ std::complex<double> (0, 1) * amp[892] + std::complex<double> (0, 1) *
+ amp[893] - amp[894] - std::complex<double> (0, 1) * amp[899] -
+ std::complex<double> (0, 1) * amp[898] - amp[938] - amp[937] -
+ std::complex<double> (0, 1) * amp[941] - std::complex<double> (0, 1) *
+ amp[940] - std::complex<double> (0, 1) * amp[947] - std::complex<double>
+ (0, 1) * amp[946] - amp[950] - amp[949] - std::complex<double> (0, 1) *
+ amp[953] - std::complex<double> (0, 1) * amp[952] - std::complex<double>
+ (0, 1) * amp[959] - std::complex<double> (0, 1) * amp[958] -
+ std::complex<double> (0, 1) * amp[965] + std::complex<double> (0, 1) *
+ amp[963] + amp[968] - amp[966] - std::complex<double> (0, 1) * amp[971] +
+ std::complex<double> (0, 1) * amp[969] - std::complex<double> (0, 1) *
+ amp[977] + std::complex<double> (0, 1) * amp[975] + amp[980] - amp[978] -
+ std::complex<double> (0, 1) * amp[983] + std::complex<double> (0, 1) *
+ amp[981];
+ jamp[21] = +amp[326] + amp[332] + amp[337] + amp[338] + amp[340] + amp[343] +
+ amp[344] + amp[346] - std::complex<double> (0, 1) * amp[348] -
+ std::complex<double> (0, 1) * amp[349] - std::complex<double> (0, 1) *
+ amp[350] - std::complex<double> (0, 1) * amp[351] + std::complex<double>
+ (0, 1) * amp[396] - amp[397] + std::complex<double> (0, 1) * amp[399] -
+ amp[400] + std::complex<double> (0, 1) * amp[401] + std::complex<double>
+ (0, 1) * amp[402] - amp[403] + std::complex<double> (0, 1) * amp[405] -
+ amp[406] + std::complex<double> (0, 1) * amp[407] + amp[409] -
+ std::complex<double> (0, 1) * amp[411] + amp[412] + amp[415] -
+ std::complex<double> (0, 1) * amp[417] + amp[418] + amp[420] + amp[421] +
+ amp[423] + amp[424] + amp[426] + amp[427] + amp[429] + amp[430] +
+ amp[435] + amp[441] - std::complex<double> (0, 1) * amp[444] + amp[446] +
+ amp[448] - std::complex<double> (0, 1) * amp[450] + amp[452] + amp[454] +
+ std::complex<double> (0, 1) * amp[457] + amp[458] + std::complex<double>
+ (0, 1) * amp[459] + amp[460] + std::complex<double> (0, 1) * amp[461] +
+ std::complex<double> (0, 1) * amp[463] + amp[464] + std::complex<double>
+ (0, 1) * amp[465] + amp[466] + std::complex<double> (0, 1) * amp[467] -
+ amp[482] - amp[481] - amp[485] - amp[484] - amp[488] - amp[487] -
+ amp[491] - amp[490] + std::complex<double> (0, 1) * amp[725] -
+ std::complex<double> (0, 1) * amp[726] - amp[727] + std::complex<double>
+ (0, 1) * amp[732] - std::complex<double> (0, 1) * amp[730] -
+ std::complex<double> (0, 1) * amp[735] + std::complex<double> (0, 1) *
+ amp[741] - std::complex<double> (0, 1) * amp[739] + std::complex<double>
+ (0, 1) * amp[743] - std::complex<double> (0, 1) * amp[744] - amp[745] +
+ std::complex<double> (0, 1) * amp[750] - std::complex<double> (0, 1) *
+ amp[748] - std::complex<double> (0, 1) * amp[753] + std::complex<double>
+ (0, 1) * amp[759] - std::complex<double> (0, 1) * amp[757] - amp[760] -
+ std::complex<double> (0, 1) * amp[762] - amp[764] - std::complex<double>
+ (0, 1) * amp[765] - amp[767] - amp[768] - std::complex<double> (0, 1) *
+ amp[770] - amp[772] - std::complex<double> (0, 1) * amp[773] - amp[775] +
+ std::complex<double> (0, 1) * amp[830] + amp[831] + std::complex<double>
+ (0, 1) * amp[832] - std::complex<double> (0, 1) * amp[836] +
+ std::complex<double> (0, 1) * amp[834] + std::complex<double> (0, 1) *
+ amp[839] + std::complex<double> (0, 1) * amp[841] + amp[842] -
+ std::complex<double> (0, 1) * amp[845] + std::complex<double> (0, 1) *
+ amp[843] + std::complex<double> (0, 1) * amp[848] + amp[849] +
+ std::complex<double> (0, 1) * amp[850] - std::complex<double> (0, 1) *
+ amp[854] + std::complex<double> (0, 1) * amp[852] + std::complex<double>
+ (0, 1) * amp[857] + std::complex<double> (0, 1) * amp[859] + amp[860] -
+ std::complex<double> (0, 1) * amp[863] + std::complex<double> (0, 1) *
+ amp[861] + std::complex<double> (0, 1) * amp[868] + std::complex<double>
+ (0, 1) * amp[870] + std::complex<double> (0, 1) * amp[871] +
+ std::complex<double> (0, 1) * amp[873] + std::complex<double> (0, 1) *
+ amp[877] + amp[878] + std::complex<double> (0, 1) * amp[879] +
+ std::complex<double> (0, 1) * amp[880] + std::complex<double> (0, 1) *
+ amp[886] + std::complex<double> (0, 1) * amp[888] + std::complex<double>
+ (0, 1) * amp[889] + std::complex<double> (0, 1) * amp[891] +
+ std::complex<double> (0, 1) * amp[895] + amp[896] + std::complex<double>
+ (0, 1) * amp[897] + std::complex<double> (0, 1) * amp[898] + amp[936] +
+ amp[937] + std::complex<double> (0, 1) * amp[939] + std::complex<double>
+ (0, 1) * amp[940] + std::complex<double> (0, 1) * amp[945] +
+ std::complex<double> (0, 1) * amp[946] + amp[948] + amp[949] +
+ std::complex<double> (0, 1) * amp[951] + std::complex<double> (0, 1) *
+ amp[952] + std::complex<double> (0, 1) * amp[957] + std::complex<double>
+ (0, 1) * amp[958] - std::complex<double> (0, 1) * amp[1013] -
+ std::complex<double> (0, 1) * amp[1012] - amp[1016] - amp[1015] -
+ std::complex<double> (0, 1) * amp[1019] - std::complex<double> (0, 1) *
+ amp[1018] - std::complex<double> (0, 1) * amp[1025] -
+ std::complex<double> (0, 1) * amp[1024] - amp[1028] - amp[1027] -
+ std::complex<double> (0, 1) * amp[1031] - std::complex<double> (0, 1) *
+ amp[1030];
+ jamp[22] = +amp[329] + amp[335] + amp[352] + amp[355] + amp[357] + amp[358] +
+ amp[361] + amp[363] + std::complex<double> (0, 1) * amp[364] +
+ std::complex<double> (0, 1) * amp[365] + std::complex<double> (0, 1) *
+ amp[366] + std::complex<double> (0, 1) * amp[367] - std::complex<double>
+ (0, 1) * amp[384] + amp[385] - std::complex<double> (0, 1) * amp[387] +
+ amp[388] - std::complex<double> (0, 1) * amp[389] - std::complex<double>
+ (0, 1) * amp[390] + amp[391] - std::complex<double> (0, 1) * amp[393] +
+ amp[394] - std::complex<double> (0, 1) * amp[395] + amp[397] +
+ std::complex<double> (0, 1) * amp[398] + amp[400] + amp[403] +
+ std::complex<double> (0, 1) * amp[404] + amp[406] - amp[422] - amp[421] -
+ amp[425] - amp[424] - amp[428] - amp[427] - amp[431] - amp[430] +
+ amp[493] + amp[499] + std::complex<double> (0, 1) * amp[504] - amp[506] -
+ amp[508] + std::complex<double> (0, 1) * amp[510] - amp[512] - amp[514] +
+ std::complex<double> (0, 1) * amp[528] - amp[530] + std::complex<double>
+ (0, 1) * amp[531] - amp[532] + std::complex<double> (0, 1) * amp[533] +
+ std::complex<double> (0, 1) * amp[534] - amp[536] + std::complex<double>
+ (0, 1) * amp[537] - amp[538] + std::complex<double> (0, 1) * amp[539] +
+ amp[542] - amp[540] + amp[545] - amp[543] + amp[548] - amp[546] +
+ amp[551] - amp[549] - std::complex<double> (0, 1) * amp[673] +
+ std::complex<double> (0, 1) * amp[674] + amp[675] - std::complex<double>
+ (0, 1) * amp[680] + std::complex<double> (0, 1) * amp[678] +
+ std::complex<double> (0, 1) * amp[683] - std::complex<double> (0, 1) *
+ amp[689] + std::complex<double> (0, 1) * amp[687] - std::complex<double>
+ (0, 1) * amp[691] + std::complex<double> (0, 1) * amp[692] + amp[693] -
+ std::complex<double> (0, 1) * amp[698] + std::complex<double> (0, 1) *
+ amp[696] + std::complex<double> (0, 1) * amp[701] - std::complex<double>
+ (0, 1) * amp[707] + std::complex<double> (0, 1) * amp[705] + amp[708] +
+ std::complex<double> (0, 1) * amp[710] + amp[712] + std::complex<double>
+ (0, 1) * amp[713] + amp[715] + amp[716] + std::complex<double> (0, 1) *
+ amp[718] + amp[720] + std::complex<double> (0, 1) * amp[721] + amp[723] +
+ std::complex<double> (0, 1) * amp[726] + amp[727] + std::complex<double>
+ (0, 1) * amp[728] - std::complex<double> (0, 1) * amp[732] -
+ std::complex<double> (0, 1) * amp[731] + std::complex<double> (0, 1) *
+ amp[735] + std::complex<double> (0, 1) * amp[737] - amp[738] -
+ std::complex<double> (0, 1) * amp[741] - std::complex<double> (0, 1) *
+ amp[740] + std::complex<double> (0, 1) * amp[744] + amp[745] +
+ std::complex<double> (0, 1) * amp[746] - std::complex<double> (0, 1) *
+ amp[750] - std::complex<double> (0, 1) * amp[749] + std::complex<double>
+ (0, 1) * amp[753] + std::complex<double> (0, 1) * amp[755] - amp[756] -
+ std::complex<double> (0, 1) * amp[759] - std::complex<double> (0, 1) *
+ amp[758] + std::complex<double> (0, 1) * amp[902] - std::complex<double>
+ (0, 1) * amp[908] - std::complex<double> (0, 1) * amp[907] +
+ std::complex<double> (0, 1) * amp[910] + std::complex<double> (0, 1) *
+ amp[911] - amp[912] - std::complex<double> (0, 1) * amp[917] -
+ std::complex<double> (0, 1) * amp[916] + std::complex<double> (0, 1) *
+ amp[920] - std::complex<double> (0, 1) * amp[926] - std::complex<double>
+ (0, 1) * amp[925] + std::complex<double> (0, 1) * amp[928] +
+ std::complex<double> (0, 1) * amp[929] - amp[930] - std::complex<double>
+ (0, 1) * amp[935] - std::complex<double> (0, 1) * amp[934] - amp[938] -
+ amp[937] - std::complex<double> (0, 1) * amp[941] - std::complex<double>
+ (0, 1) * amp[940] - std::complex<double> (0, 1) * amp[947] -
+ std::complex<double> (0, 1) * amp[946] - amp[950] - amp[949] -
+ std::complex<double> (0, 1) * amp[953] - std::complex<double> (0, 1) *
+ amp[952] - std::complex<double> (0, 1) * amp[959] - std::complex<double>
+ (0, 1) * amp[958] - std::complex<double> (0, 1) * amp[989] +
+ std::complex<double> (0, 1) * amp[987] + amp[992] - amp[990] -
+ std::complex<double> (0, 1) * amp[995] + std::complex<double> (0, 1) *
+ amp[993] - std::complex<double> (0, 1) * amp[1001] + std::complex<double>
+ (0, 1) * amp[999] + amp[1004] - amp[1002] - std::complex<double> (0, 1) *
+ amp[1007] + std::complex<double> (0, 1) * amp[1005];
+ jamp[23] = +amp[328] + amp[334] + amp[336] + amp[339] + amp[341] + amp[342] +
+ amp[345] + amp[347] + std::complex<double> (0, 1) * amp[348] +
+ std::complex<double> (0, 1) * amp[349] + std::complex<double> (0, 1) *
+ amp[350] + std::complex<double> (0, 1) * amp[351] + std::complex<double>
+ (0, 1) * amp[384] - amp[385] + std::complex<double> (0, 1) * amp[387] -
+ amp[388] + std::complex<double> (0, 1) * amp[389] + std::complex<double>
+ (0, 1) * amp[390] - amp[391] + std::complex<double> (0, 1) * amp[393] -
+ amp[394] + std::complex<double> (0, 1) * amp[395] - amp[409] +
+ std::complex<double> (0, 1) * amp[411] - amp[412] - amp[415] +
+ std::complex<double> (0, 1) * amp[417] - amp[418] + amp[422] - amp[420] +
+ amp[425] - amp[423] + amp[428] - amp[426] + amp[431] - amp[429] +
+ amp[433] + amp[439] + std::complex<double> (0, 1) * amp[444] - amp[446] -
+ amp[448] + std::complex<double> (0, 1) * amp[450] - amp[452] - amp[454] +
+ std::complex<double> (0, 1) * amp[468] - amp[470] + std::complex<double>
+ (0, 1) * amp[471] - amp[472] + std::complex<double> (0, 1) * amp[473] +
+ std::complex<double> (0, 1) * amp[474] - amp[476] + std::complex<double>
+ (0, 1) * amp[477] - amp[478] + std::complex<double> (0, 1) * amp[479] +
+ amp[482] - amp[480] + amp[485] - amp[483] + amp[488] - amp[486] +
+ amp[491] - amp[489] + std::complex<double> (0, 1) * amp[673] -
+ std::complex<double> (0, 1) * amp[674] - amp[675] + std::complex<double>
+ (0, 1) * amp[680] - std::complex<double> (0, 1) * amp[678] -
+ std::complex<double> (0, 1) * amp[683] + std::complex<double> (0, 1) *
+ amp[689] - std::complex<double> (0, 1) * amp[687] + std::complex<double>
+ (0, 1) * amp[691] - std::complex<double> (0, 1) * amp[692] - amp[693] +
+ std::complex<double> (0, 1) * amp[698] - std::complex<double> (0, 1) *
+ amp[696] - std::complex<double> (0, 1) * amp[701] + std::complex<double>
+ (0, 1) * amp[707] - std::complex<double> (0, 1) * amp[705] - amp[708] -
+ std::complex<double> (0, 1) * amp[710] - amp[712] - std::complex<double>
+ (0, 1) * amp[713] - amp[715] - amp[716] - std::complex<double> (0, 1) *
+ amp[718] - amp[720] - std::complex<double> (0, 1) * amp[721] - amp[723] -
+ std::complex<double> (0, 1) * amp[830] - amp[831] - std::complex<double>
+ (0, 1) * amp[832] + std::complex<double> (0, 1) * amp[836] -
+ std::complex<double> (0, 1) * amp[834] - std::complex<double> (0, 1) *
+ amp[839] - std::complex<double> (0, 1) * amp[841] - amp[842] +
+ std::complex<double> (0, 1) * amp[845] - std::complex<double> (0, 1) *
+ amp[843] - std::complex<double> (0, 1) * amp[848] - amp[849] -
+ std::complex<double> (0, 1) * amp[850] + std::complex<double> (0, 1) *
+ amp[854] - std::complex<double> (0, 1) * amp[852] - std::complex<double>
+ (0, 1) * amp[857] - std::complex<double> (0, 1) * amp[859] - amp[860] +
+ std::complex<double> (0, 1) * amp[863] - std::complex<double> (0, 1) *
+ amp[861] - std::complex<double> (0, 1) * amp[904] + std::complex<double>
+ (0, 1) * amp[908] - std::complex<double> (0, 1) * amp[906] +
+ std::complex<double> (0, 1) * amp[909] - std::complex<double> (0, 1) *
+ amp[913] - amp[914] + std::complex<double> (0, 1) * amp[917] -
+ std::complex<double> (0, 1) * amp[915] - std::complex<double> (0, 1) *
+ amp[922] + std::complex<double> (0, 1) * amp[926] - std::complex<double>
+ (0, 1) * amp[924] + std::complex<double> (0, 1) * amp[927] -
+ std::complex<double> (0, 1) * amp[931] - amp[932] + std::complex<double>
+ (0, 1) * amp[935] - std::complex<double> (0, 1) * amp[933] + amp[938] -
+ amp[936] + std::complex<double> (0, 1) * amp[941] - std::complex<double>
+ (0, 1) * amp[939] + std::complex<double> (0, 1) * amp[947] -
+ std::complex<double> (0, 1) * amp[945] + amp[950] - amp[948] +
+ std::complex<double> (0, 1) * amp[953] - std::complex<double> (0, 1) *
+ amp[951] + std::complex<double> (0, 1) * amp[959] - std::complex<double>
+ (0, 1) * amp[957] + std::complex<double> (0, 1) * amp[1013] -
+ std::complex<double> (0, 1) * amp[1011] + amp[1016] - amp[1014] +
+ std::complex<double> (0, 1) * amp[1019] - std::complex<double> (0, 1) *
+ amp[1017] + std::complex<double> (0, 1) * amp[1025] -
+ std::complex<double> (0, 1) * amp[1023] + amp[1028] - amp[1026] +
+ std::complex<double> (0, 1) * amp[1031] - std::complex<double> (0, 1) *
+ amp[1029];
+
+ // Store the leading color flows for choice of color
+ for(int i = 0; i < ncolor; i++ )
+ jamp2[0][i] += real(jamp[i] * conj(jamp[i]));
+
+ return -1.;
+}
+
+
+double eeuugggg::get_jamp2(int i)
+{
+ return jamp2[0][i];
+}
+
+int eeuugggg::colorstring(int i, int j)
+{
+ static const int res[24][8] = {
+ {5, 6, 7, 8, 3, 4, 0, 0},
+ {5, 6, 8, 7, 3, 4, 0, 0},
+ {5, 7, 6, 8, 3, 4, 0, 0},
+ {5, 7, 8, 6, 3, 4, 0, 0},
+ {5, 8, 6, 7, 3, 4, 0, 0},
+ {5, 8, 7, 6, 3, 4, 0, 0},
+ {6, 5, 7, 8, 3, 4, 0, 0},
+ {6, 5, 8, 7, 3, 4, 0, 0},
+ {6, 7, 5, 8, 3, 4, 0, 0},
+ {6, 7, 8, 5, 3, 4, 0, 0},
+ {6, 8, 5, 7, 3, 4, 0, 0},
+ {6, 8, 7, 5, 3, 4, 0, 0},
+ {7, 5, 6, 8, 3, 4, 0, 0},
+ {7, 5, 8, 6, 3, 4, 0, 0},
+ {7, 6, 5, 8, 3, 4, 0, 0},
+ {7, 6, 8, 5, 3, 4, 0, 0},
+ {7, 8, 5, 6, 3, 4, 0, 0},
+ {7, 8, 6, 5, 3, 4, 0, 0},
+ {8, 5, 6, 7, 3, 4, 0, 0},
+ {8, 5, 7, 6, 3, 4, 0, 0},
+ {8, 6, 5, 7, 3, 4, 0, 0},
+ {8, 6, 7, 5, 3, 4, 0, 0},
+ {8, 7, 5, 6, 3, 4, 0, 0},
+ {8, 7, 6, 5, 3, 4, 0, 0}};
+ return res[i][j];
+}
+
+
+int eeuugggg::NCol()
+{
+ static const int ncolor = 24;
+ return ncolor;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Shower/Dipole/Colorea/eeuugggg.h b/Shower/Dipole/Colorea/eeuugggg.h
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/eeuugggg.h
@@ -0,0 +1,52 @@
+ //==========================================================================
+ // This file has been automatically generated for C++ Standalone by
+ // MadGraph5_aMC@NLO v. 2.5.4, 2017-03-28
+ // By the MadGraph5_aMC@NLO Development Team
+ // Visit launchpad.net/madgraph5 and amcatnlo.web.cern.ch
+ //==========================================================================
+ // and was then modified by J. Bellm.
+#ifndef MG5_Sigma_sm_epem_uuxgggg_H
+#define MG5_Sigma_sm_epem_uuxgggg_H
+#include <complex>
+#include <vector>
+#include "Parameters_sm.h"
+using namespace std;
+class eeuugggg
+{
+ public:
+ eeuugggg(){
+ initProc("param_card.dat");
+ }
+ // Retrun the prefered gluon order
+ vector<int> producePermutation(double r,vector < double * > & momenta);
+ void setMass(int i,double M){mME[i]=M;}
+ private:
+ ///////// Process Dependent
+ static const int ninitial = 2;
+ static const int nexternal = 8;
+ static const int nprocesses = 1;
+ static const int nwavefuncs = 205;
+ static const int namplitudes = 1032;
+ std::complex<double> w[nwavefuncs][18];
+ double matrix_1_epem_uuxgggg();
+ ///////// Generic
+ double matrix_element[nprocesses];
+ std::complex<double> amp[namplitudes];
+ double * jamp2[nprocesses];
+ Parameters_sm * pars;
+ vector<double> mME;
+ vector < double * > p;
+ int id1, id2;
+ void initProc(string param_card_name);
+ void sigmaKin();
+ const vector<double> & getMasses() const {return mME;}
+ vector < double * > getMomenta(){return p;}
+ void setMomenta(vector < double * > & momenta){p = momenta;}
+ void setInitial(int inid1, int inid2){id1 = inid1; id2 = inid2;}
+ void calculate_wavefunctions(const int perm[], const int hel[]);
+ // New function
+ double get_jamp2(int i);
+ int colorstring(int i, int j);
+ int NCol();
+};
+#endif // MG5_Sigma_sm_epem_uuxgggg_H
diff --git a/Shower/Dipole/Colorea/read_slha_COLOREA.cc b/Shower/Dipole/Colorea/read_slha_COLOREA.cc
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/read_slha_COLOREA.cc
@@ -0,0 +1,144 @@
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include "read_slha_COLOREA.h"
+
+void SLHABlock_COLOREA::set_entry(std::vector<int> indices, double value)
+{
+ if (_entries.size() == 0)
+ _indices = indices.size();
+ else if(indices.size() != _indices)
+ throw "Wrong number of indices in set_entry";
+
+ _entries[indices] = value;
+}
+
+double SLHABlock_COLOREA::get_entry(std::vector<int> indices, double def_val)
+{
+ if (_entries.find(indices) == _entries.end()){
+ std::cout << "Warning: No such entry in " << _name << ", using default value "
+ << def_val << std::endl;
+ return def_val;
+ }
+ return _entries[indices];
+}
+
+void SLHAReader_COLOREA::read_slha_file(std::string file_name)
+{
+ std::ifstream param_card;
+ param_card.open(file_name.c_str(), std::ifstream::in);
+ if(!param_card.good())
+ throw "Error while opening param card";
+ std::cout << "\nColorea: Opened slha file " << file_name << " for reading" << std::endl;
+ char buf[200];
+ std::string line;
+ std::string block("");
+
+ while(param_card.good()){
+ param_card.getline(buf, 200);
+ line = buf;
+ // Change to lowercase
+ transform(line.begin(), line.end(), line.begin(), (int(*)(int)) tolower);
+ if(line != "" && line[0] != '#'){
+ if(block != ""){
+ // Look for double index blocks
+ double dindex1, dindex2;
+ double value;
+ std::stringstream linestr2(line);
+ if (linestr2 >> dindex1 >> dindex2 >> value &&
+ dindex1 == int(dindex1) and dindex2 == int(dindex2))
+ {
+ std::vector<int> indices;
+ indices.push_back(int(dindex1));
+ indices.push_back(int(dindex2));
+ set_block_entry(block, indices, value);
+ // Done with this line, read next
+ continue;
+ }
+ std::stringstream linestr1(line);
+ // Look for single index blocks
+ if(linestr1 >> dindex1 >> value && dindex1 == int(dindex1))
+ {
+ std::vector<int> indices;
+ indices.push_back(int(dindex1));
+ set_block_entry(block, indices, value);
+ // Done with this line, read next
+ continue;
+ }
+ }
+ // Look for block
+ if(line.find("block ") != line.npos){
+ line = line.substr(6);
+ // Get rid of spaces between block and block name
+ while (line[0] == ' ')
+ line = line.substr(1);
+ // Now find end of block name
+ int space_pos = line.find(' ');
+ if(space_pos != line.npos)
+ line = line.substr(0, space_pos);
+ block = line;
+ continue;
+ }
+ // Look for decay
+ if(line.find("decay ") == 0){
+ line = line.substr(6);
+ block = "";
+ std::stringstream linestr(line);
+ int pdg_code;
+ double value;
+ if(linestr >> pdg_code >> value)
+ set_block_entry("decay", pdg_code, value);
+ else
+ std::cout << "Warning: Wrong format for decay block " << line << std::endl;
+ continue;
+ }
+ }
+ }
+
+ if (_blocks.size() == 0)
+ throw "No information read from SLHA card";
+
+ param_card.close();
+}
+
+double SLHAReader_COLOREA::get_block_entry(std::string block_name, std::vector<int> indices,
+ double def_val)
+{
+ if (_blocks.find(block_name) == _blocks.end()){
+ std::cout << "No such block " << block_name << ", using default value "
+ << def_val << std::endl;
+ return def_val;
+ }
+ return _blocks[block_name].get_entry(indices);
+}
+
+double SLHAReader_COLOREA::get_block_entry(std::string block_name, int index,
+ double def_val)
+{
+ std::vector<int> indices;
+ indices.push_back(index);
+ return get_block_entry(block_name, indices, def_val);
+}
+
+
+void SLHAReader_COLOREA::set_block_entry(std::string block_name, std::vector<int> indices,
+ double value)
+{
+ if (_blocks.find(block_name) == _blocks.end()){
+ SLHABlock_COLOREA block(block_name);
+ _blocks[block_name] = block;
+ }
+ _blocks[block_name].set_entry(indices, value);
+ /* cout << "Set block " << block_name << " entry ";
+ for (int i=0;i < indices.size();i++)
+ cout << indices[i] << " ";
+ cout << "to " << _blocks[block_name].get_entry(indices) << endl;*/
+}
+
+void SLHAReader_COLOREA::set_block_entry(std::string block_name, int index,
+ double value)
+{
+ std::vector<int> indices;
+ indices.push_back(index);
+ set_block_entry(block_name, indices, value);
+}
diff --git a/Shower/Dipole/Colorea/read_slha_COLOREA.h b/Shower/Dipole/Colorea/read_slha_COLOREA.h
new file mode 100644
--- /dev/null
+++ b/Shower/Dipole/Colorea/read_slha_COLOREA.h
@@ -0,0 +1,46 @@
+#ifndef READ_SLHA_H
+#define READ_SLHA_H
+
+#include <map>
+#include <string>
+#include <sstream>
+#include <vector>
+
+class SLHABlock_COLOREA
+{
+ public:
+ SLHABlock_COLOREA(std::string name = ""){_name = name;}
+ ~SLHABlock_COLOREA(){}
+
+ void set_entry(std::vector<int> indices, double value);
+ double get_entry(std::vector<int> indices, double def_val = 0);
+ void set_name(std::string name) {_name = name;}
+ std::string get_name(){return _name;}
+ int get_indices() { return _indices;}
+
+ private:
+ std::string _name;
+ std::map<std::vector<int>, double> _entries;
+ unsigned int _indices;
+};
+
+class SLHAReader_COLOREA
+{
+ public:
+ SLHAReader_COLOREA(std::string file_name = "")
+ {if(file_name != "") read_slha_file(file_name);}
+
+ void read_slha_file(std::string file_name);
+ double get_block_entry(std::string block_name, std::vector<int> indices,
+ double def_val = 0);
+ double get_block_entry(std::string block_name, int index,
+ double def_val = 0);
+ void set_block_entry(std::string block_name, std::vector<int> indices,
+ double value);
+ void set_block_entry(std::string block_name, int index,
+ double value);
+ private:
+ std::map<std::string, SLHABlock_COLOREA> _blocks;
+};
+
+#endif
diff --git a/Shower/Dipole/DipoleShowerHandler.cc b/Shower/Dipole/DipoleShowerHandler.cc
--- a/Shower/Dipole/DipoleShowerHandler.cc
+++ b/Shower/Dipole/DipoleShowerHandler.cc
@@ -1,1287 +1,1384 @@
// -*- C++ -*-
//
// DipoleShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DipoleShowerHandler class.
//
#include <config.h>
#include "DipoleShowerHandler.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Parameter.h"
+#include "ThePEG/Interface/ParVector.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
// include theses to have complete types
#include "Herwig/PDF/MPIPDF.h"
#include "Herwig/PDF/MinBiasPDF.h"
#include "Herwig/PDF/HwRemDecayer.h"
#include "Herwig/Shower/Dipole/Utility/DipolePartonSplitter.h"
#include "Herwig/MatrixElement/Matchbox/Base/MergerBase.h"
#include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h"
#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h"
#include <queue>
using namespace Herwig;
bool DipoleShowerHandler::firstWarn = true;
-DipoleShowerHandler::DipoleShowerHandler()
-: ShowerHandler(), chainOrderVetoScales(true),
-nEmissions(0), discardNoEmissions(false), firstMCatNLOEmission(false),
-thePowhegDecayEmission(true),
-realignmentScheme(0),
-verbosity(0), printEvent(0), nTries(0),
-didRadiate(false), didRealign(false),
-theRenormalizationScaleFreeze(1.*GeV),
-theFactorizationScaleFreeze(2.*GeV), theDoCompensate(false),
-theFreezeGrid(500000), theDetuning(1.0),
-maxPt(ZERO), muPt(ZERO) {}
+DipoleShowerHandler::DipoleShowerHandler() :
+ ShowerHandler(), chainOrderVetoScales(true),
+ nEmissions(0), discardNoEmissions(false), firstMCatNLOEmission(false),
+ thePowhegDecayEmission(true),
+ realignmentScheme(0),
+ verbosity(0), printEvent(0), nTries(0),
+ didRadiate(false), didRealign(false),
+ theRenormalizationScaleFreeze(1.*GeV),
+ theFactorizationScaleFreeze(2.*GeV), theDoCompensate(false),
+ theFreezeGrid(500000), theDetuning(1.0),
+ maxPt(ZERO), muPt(ZERO),
+ theInputColouredOffShellInShower(),
+ theZBoundaries(1) {}
DipoleShowerHandler::~DipoleShowerHandler() {}
IBPtr DipoleShowerHandler::clone() const {
return new_ptr(*this);
}
IBPtr DipoleShowerHandler::fullclone() const {
return new_ptr(*this);
}
void DipoleShowerHandler::cascade(tPVector ) {
throw Exception()
<< "DipoleShowerHandler: Dipoleshower not implemented as second shower."
<< "Check your setup or contact Herwig authors."
<< Exception::runerror;
}
tPPair DipoleShowerHandler::cascade(tSubProPtr sub, XCombPtr,
Energy optHardPt, Energy optCutoff) {
-
+
useMe();
prepareCascade(sub);
resetWeights();
if ( !doFSR() && ! doISR() )
return sub->incoming();
eventRecord().clear();
eventRecord().prepare(sub, dynamic_ptr_cast<tStdXCombPtr>(lastXCombPtr()), newStep(), pdfs(),
- ShowerHandler::currentHandler()->generator()->currentEvent()->incoming(),
- firstInteraction());
+ ShowerHandler::currentHandler()->generator()->currentEvent()->incoming(),
+ firstInteraction(), offShellPartons());
if ( eventRecord().outgoing().empty() && !doISR() )
return sub->incoming();
if ( !eventRecord().incoming().first->coloured() &&
!eventRecord().incoming().second->coloured() &&
!doFSR() )
return sub->incoming();
nTries = 0;
while ( true ) {
try {
didRadiate = false;
didRealign = false;
if ( eventRecord().truncatedShower() ) {
throw Exception() << "Inconsistent hard emission set-up in DipoleShowerHandler::cascade. "
<< "No truncated shower needed with DipoleShowerHandler. Add "
<< "'set MEMatching:TruncatedShower No' to input file."
<< Exception::runerror;
}
hardScales(lastXCombPtr()->lastShowerScale());
if ( verbosity > 1 ) {
generator()->log() << "DipoleShowerHandler starting off:\n";
eventRecord().debugLastEvent(generator()->log());
generator()->log() << flush;
}
unsigned int nEmitted = 0;
if ( firstMCatNLOEmission ) {
if ( !eventRecord().isMCatNLOHEvent() )
nEmissions = 1;
else
nEmissions = 0;
}
if ( !firstMCatNLOEmission ) {
doCascade(nEmitted,optHardPt,optCutoff);
if ( discardNoEmissions ) {
if ( !didRadiate )
throw Veto();
if ( nEmissions )
if ( nEmissions < nEmitted )
throw Veto();
}
} else {
if ( nEmissions == 1 )
doCascade(nEmitted,optHardPt,optCutoff);
}
if ( intrinsicPtGenerator ) {
if ( eventRecord().incoming().first->coloured() &&
eventRecord().incoming().second->coloured() ) {
SpinOneLorentzRotation rot =
intrinsicPtGenerator->kick(eventRecord().incoming(),
eventRecord().intermediates());
eventRecord().transform(rot);
}
}
didRealign = realign();
constituentReshuffle();
// Decay and shower any particles that require decaying
while ( !eventRecord().decays().empty() ) {
map<PPtr,PerturbativeProcessPtr>::const_iterator decayIt = eventRecord().decays().begin();
// find the decay to do, one with greatest width and parent showered
while(find(eventRecord().outgoing().begin(),eventRecord().outgoing().end(),decayIt->first)==
eventRecord().outgoing().end() &&
find(eventRecord().hard().begin(),eventRecord().hard().end(),decayIt->first)==
eventRecord().hard().end()) ++decayIt;
assert(decayIt!=eventRecord().decays().end());
PPtr incoming = decayIt->first;
eventRecord().currentDecay(decayIt->second);
// Use this to record if an emission actually happens
bool powhegEmission = !( nEmissions && nEmitted==nEmissions) ? thePowhegDecayEmission : false;
// Decay the particle / sort out its pert proc
Energy showerScale = eventRecord().decay(incoming, powhegEmission);
// Following the decay, the bool powheg emission is updated
// to indicate whether or not an emission occurred
if ( powhegEmission )
nEmitted += 1;
// Check that there is only one particle incoming to the decay
assert(eventRecord().currentDecay()->incoming().size()==1);
// Prepare the event record for the showering of the decay
- bool needToShower = eventRecord().prepareDecay(eventRecord().currentDecay());
+ bool needToShower = eventRecord().prepareDecay(eventRecord().currentDecay(),
+ offShellPartons());
// Only need to shower if we have coloured outgoing particles
if ( needToShower ) {
// The decays currently considered produce a maximum of 2 chains (with powheg emission)
// so all dipole should have the same scale as returned by the decay function.
assert( eventRecord().chains().size() <= 2 );
for ( auto & ch : eventRecord().chains()) {
for ( auto & dip : ch.dipoles()) {
assert ( showerScale > ZERO );
dip.leftScale( showerScale );
dip.rightScale( showerScale );
}
}
// Perform the cascade
doCascade(nEmitted,optHardPt,optCutoff,true);
// Do the constituent mass shell reshuffling
decayConstituentReshuffle(eventRecord().currentDecay());
}
// Update the decays, adding any decays and updating momenta
eventRecord().updateDecays(eventRecord().currentDecay());
eventRecord().decays().erase(decayIt);
}
break;
} catch (RedoShower&) {
resetWeights();
if ( ++nTries > maxtry() )
throw ShowerTriesVeto(maxtry());
eventRecord().clear();
eventRecord().prepare(sub, dynamic_ptr_cast<tStdXCombPtr>(lastXCombPtr()), newStep(), pdfs(),
ShowerHandler::currentHandler()->generator()->currentEvent()->incoming(),
- firstInteraction());
+ firstInteraction(), offShellPartons());
continue;
} catch (...) {
throw;
}
}
tPPair incoming=eventRecord().fillEventRecord(newStep(),firstInteraction(),didRealign);
setDidRunCascade(true);
return incoming;
}
// Reshuffle the outgoing partons from the hard process onto their constituent mass shells
void DipoleShowerHandler::constituentReshuffle() {
if ( constituentReshuffler ) {
if ( eventRecord().decays().empty() ) {
constituentReshuffler->reshuffle(eventRecord().outgoing(),
eventRecord().incoming(),
eventRecord().intermediates());
return;
}
else {
PList decaying;
for(auto const & dec : eventRecord().decays())
decaying.push_back(dec.first);
constituentReshuffler->hardProcDecayReshuffle( decaying,
eventRecord().outgoing(),
eventRecord().hard(),
eventRecord().incoming(),
eventRecord().intermediates());
}
}
// After reshuffling the hard process, the decays need to be updated
// as this is not done in reshuffle
vector<pair<PPtr,PerturbativeProcessPtr> > decays;
for(auto const & dec : eventRecord().decays() )
decays.push_back({dec.first,dec.second});
for(auto const & dec : decays) {
PPtr unstable = dec.first;
PList::iterator pos = find(eventRecord().intermediates().begin(),
eventRecord().intermediates().end(),
dec.first);
// Update the PPtr in theDecays
if(pos!=eventRecord().intermediates().end()) {
unstable = *pos;
while(!unstable->children().empty()) {
unstable = unstable->children()[0];
}
eventRecord().decays().erase(dec.first);
eventRecord().decays()[unstable] = dec.second;
// Update the momenta of any other particles in the decay chain
// (for externally provided events)
if ( !(eventRecord().decays()[unstable]->outgoing().empty()) )
eventRecord().updateDecayChainMom( unstable , eventRecord().decays()[unstable]);
}
else {
if ( !(eventRecord().decays()[unstable]->outgoing().empty()) ) {
// Update the momenta of any other particles in the decay chain
// (for externally provided events)
// Note this needs to be done for all decaying particles in the
// outgoing/hard regardless of whether that particle radiated
// or was involved in the reshuffling, this is due to the
// transformation performed for IILightKinematics.
if ( (find(eventRecord().outgoing().begin(),
eventRecord().outgoing().end(), unstable) != eventRecord().outgoing().end())
|| (find(eventRecord().hard().begin(),
eventRecord().hard().end(), unstable) != eventRecord().hard().end()) )
eventRecord().updateDecayChainMom( unstable , eventRecord().decays()[unstable]);
}
}
}
eventRecord().currentDecay(PerturbativeProcessPtr());
}
// Reshuffle outgoing partons from a decay process onto their constituent mass shells
void DipoleShowerHandler::decayConstituentReshuffle(PerturbativeProcessPtr decayProc) {
if ( Debug::level > 2 ){
// Test this function by comparing the
// invariant mass of the outgoing decay
// systems before and after reshuffling
Lorentz5Momentum testOutMomBefore (ZERO,ZERO,ZERO,ZERO);
Energy testInvMassBefore = ZERO;
for ( auto const & testDecayOutItBefore : decayProc->outgoing() ) {
testOutMomBefore += testDecayOutItBefore.first->momentum();
}
testInvMassBefore = testOutMomBefore.m();
// decayReshuffle updates both the event record and the decay perturbative process
if ( constituentReshuffler ) {
constituentReshuffler->decayReshuffle(decayProc,
eventRecord().outgoing(),
eventRecord().hard(),
eventRecord().intermediates());
}
Lorentz5Momentum testOutMomAfter (ZERO,ZERO,ZERO,ZERO);
Energy testInvMassAfter = ZERO;
for ( auto const & testDecayOutItAfter : decayProc->outgoing() ) {
testOutMomAfter += testDecayOutItAfter.first->momentum();
}
testInvMassAfter = testOutMomAfter.m();
Energy incomingMass = decayProc->incoming()[0].first->momentum().m();
assert( abs(testInvMassBefore-incomingMass)/GeV < 1e-5 );
assert( abs(testInvMassBefore-testInvMassAfter)/GeV < 1e-5);
}else{
// decayReshuffle updates both the event record and the decay perturbative process
if ( constituentReshuffler ) {
constituentReshuffler->decayReshuffle(decayProc,
eventRecord().outgoing(),
eventRecord().hard(),
eventRecord().intermediates());
}
return;
}
}
// Sets the scale of each particle in the dipole chains by finding the smallest
//of several upper bound energy scales: the CMEnergy of the event,
//the transverse mass of outgoing particles, the hardScale (maxPT or maxQ)
//calculated for each dipole (in both configurations) and the veto scale for each particle
void DipoleShowerHandler::hardScales(Energy2 muf) {
// Initalise maximum pt as max CMEnergy of the event
maxPt = generator()->maximumCMEnergy();
if ( restrictPhasespace() ) {
// First interaction == hard collision (i.e. not a MPI collision)
if ( !hardScaleIsMuF() || !firstInteraction() ) {
if ( !eventRecord().outgoing().empty() ) {
for ( auto const & p : eventRecord().outgoing() )
maxPt = min(maxPt,p->momentum().mt());
}
//Look at any non-coloured outgoing particles in the current subprocess
else {
assert(!eventRecord().hard().empty());
Lorentz5Momentum phard(ZERO,ZERO,ZERO,ZERO);
for ( auto const & p : eventRecord().hard())
phard += p->momentum();
Energy mhard = phard.m();
maxPt = mhard;
}
maxPt *= hardScaleFactor();
}
else {
maxPt = hardScaleFactor()*sqrt(muf);
}
muPt = maxPt;
} else {
muPt = hardScaleFactor()*sqrt(muf);
}
for ( auto & ch : eventRecord().chains()) {
// Note that minVetoScale is a value for each DipoleChain, not each dipole
// It will contain the minimum veto scale from all of the dipoles in the chain
Energy minVetoScale = -1.*GeV;
for ( auto & dip : ch.dipoles()) {
// max scale per config
Energy maxFirst = ZERO;
Energy maxSecond = ZERO;
// Loop over the kernels for the given dipole.
// For each dipole configuration, calculate ptMax (or QMax if virtuality ordering)
// for each kernel and find the maximum
for ( auto const & k : kernels) {
pair<bool,bool> conf = {true,false};
if ( k->canHandle(dip.index(conf)) ) {
// Look in DipoleChainOrdering for this
Energy scale =
evolutionOrdering()->hardScale(dip.emitter(conf),dip.spectator(conf),
dip.emitterX(conf),dip.spectatorX(conf),
*k,dip.index(conf));
maxFirst = max(maxFirst,scale);
}
conf = {false,true};
if ( k->canHandle(dip.index(conf)) ) {
Energy scale =
evolutionOrdering()->hardScale(dip.emitter(conf),dip.spectator(conf),
dip.emitterX(conf),dip.spectatorX(conf),
*k,dip.index(conf));
maxSecond = max(maxSecond,scale);
}
}
// Find the maximum value from comparing the maxScale found from maxPt and the vetoScale of the particle
if ( dip.leftParticle()->vetoScale() >= ZERO ) {
maxFirst = min(maxFirst,sqrt(dip.leftParticle()->vetoScale()));
// minVetoScale is a value for each DipoleChain, not each dipole
// It contains the minimum veto scale for all the dipoles in the entire DipoleChain
if ( minVetoScale >= ZERO )
minVetoScale = min(minVetoScale,sqrt(dip.leftParticle()->vetoScale()));
else
minVetoScale = sqrt(dip.leftParticle()->vetoScale());
}
if ( dip.rightParticle()->vetoScale() >= ZERO ) {
maxSecond = min(maxSecond,sqrt(dip.rightParticle()->vetoScale()));
if ( minVetoScale >= ZERO )
minVetoScale = min(minVetoScale,sqrt(dip.rightParticle()->vetoScale()));
else
minVetoScale = sqrt(dip.rightParticle()->vetoScale());
}
// Set the emitterScale for both members of each dipole
maxFirst = min(maxPt,maxFirst);
dip.emitterScale({true,false},maxFirst);
maxSecond = min(maxPt,maxSecond);
dip.emitterScale({false,true},maxSecond);
}
// if the smallest veto scale (i.e. from all of the dipoles)
// is smaller than the scale calculated for a particular
// particle in a particular dipole,
// replace the scale with the veto scale
if ( !evolutionOrdering()->independentDipoles() &&
chainOrderVetoScales &&
minVetoScale >= ZERO ) {
for ( auto & dip : ch.dipoles() ) {
dip.leftScale(min(dip.leftScale(),minVetoScale));
dip.rightScale(min(dip.rightScale(),minVetoScale));
}
}
}
}
Energy DipoleShowerHandler::getWinner(DipoleSplittingInfo& winner,
const Dipole& dip,
pair<bool,bool> conf,
Energy optHardPt,
Energy optCutoff) {
return
getWinner(winner,dip.index(conf),
dip.emitterX(conf),dip.spectatorX(conf),
conf,dip.emitter(conf),dip.spectator(conf),
dip.emitterScale(conf),optHardPt,optCutoff);
}
Energy DipoleShowerHandler::getWinner(SubleadingSplittingInfo& winner,
Energy optHardPt,
Energy optCutoff) {
return
getWinner(winner,winner.index(),
winner.emitterX(),winner.spectatorX(),
winner.configuration(),
winner.emitter(),winner.spectator(),
winner.startScale(),optHardPt,optCutoff);
}
Energy DipoleShowerHandler::getWinner(DipoleSplittingInfo& winner,
const DipoleIndex& index,
double emitterX, double spectatorX,
pair<bool,bool> conf,
tPPtr emitter, tPPtr spectator,
Energy startScale,
Energy optHardPt,
Energy optCutoff) {
if ( !index.initialStateEmitter() &&
!doFSR() ) {
winner.didStopEvolving();
return 0.0*GeV;
}
if ( index.initialStateEmitter() &&
!doISR() ) {
winner.didStopEvolving();
return 0.0*GeV;
}
- // Currently do not split IF dipoles so
- // don't evaluate them in order to avoid
- // exceptions in the log
+ // Currently do not split IF dipoles so
+ // don't evaluate them in order to avoid
+ // exceptions in the log
if ( index.incomingDecayEmitter() ) {
winner.didStopEvolving();
return 0.0*GeV;
}
DipoleSplittingInfo candidate;
candidate.index(index);
candidate.configuration(conf);
candidate.emitterX(emitterX);
candidate.spectatorX(spectatorX);
if ( generators().find(candidate.index()) == generators().end() )
getGenerators(candidate.index(),theSplittingReweight);
- //
- // NOTE -- needs proper fixing at some point
- //
- // For some very strange reason, equal_range gives back
- // key ranges it hasn't been asked for. This particularly
- // happens e.g. for FI dipoles of the same kind, but different
- // PDF (hard vs MPI PDF). I can't see a reason for this,
- // as DipoleIndex properly implements comparison for equality
- // and (lexicographic) ordering; for the time being, we
- // use equal_range, extented by an explicit check for wether
- // the key is indeed what we wanted. See line after (*) comment
- // below.
- //
- // SW - Update 04/01/2016: Note - This caused a bug for me as I did not
- // include equality checks on the decay booleans in the == definition
+ //
+ // NOTE -- needs proper fixing at some point
+ //
+ // For some very strange reason, equal_range gives back
+ // key ranges it hasn't been asked for. This particularly
+ // happens e.g. for FI dipoles of the same kind, but different
+ // PDF (hard vs MPI PDF). I can't see a reason for this,
+ // as DipoleIndex properly implements comparison for equality
+ // and (lexicographic) ordering; for the time being, we
+ // use equal_range, extented by an explicit check for wether
+ // the key is indeed what we wanted. See line after (*) comment
+ // below.
+ //
+ // SW - Update 04/01/2016: Note - This caused a bug for me as I did not
+ // include equality checks on the decay booleans in the == definition
pair<GeneratorMap::iterator,GeneratorMap::iterator> gens
= generators().equal_range(candidate.index());
Energy winnerScale = 0.0*GeV;
GeneratorMap::iterator winnerGen = generators().end();
for ( GeneratorMap::iterator gen = gens.first; gen != gens.second; ++gen ) {
// (*) see NOTE above
if ( !(gen->first == candidate.index()) )
continue;
if ( startScale <= gen->second->splittingKinematics()->IRCutoff() )
continue;
Energy dScale =
gen->second->splittingKinematics()->dipoleScale(emitter->momentum(),
spectator->momentum());
-
- // in very exceptional cases happening in DIS
+
+ // in very exceptional cases happening in DIS
if ( std::isnan( double(dScale/MeV) ) )
throw RedoShower();
candidate.scale(dScale);
// Calculate the mass of the recoil system
// for decay dipoles
- if (candidate.index().incomingDecayEmitter() || candidate.index().incomingDecaySpectator() ) {
+ if ( candidate.index().incomingDecaySpectator() || candidate.index().incomingDecayEmitter() ) {
Energy recoilMass = gen->second->splittingKinematics()->recoilMassKin(emitter->momentum(),
spectator->momentum());
candidate.recoilMass(recoilMass);
}
+
+ // Store emitter and spectator masses, needed in kinematics
+ if ( candidate.index().emitterData()->mass() != ZERO ) {
+ if ( !candidate.index().offShellEmitter() )
+ candidate.emitterMass( emitter->nominalMass() );
+ else
+ candidate.emitterMass( emitter->mass() );
+ }
+
+ if ( candidate.index().spectatorData()->mass() != ZERO ) {
+ if ( !candidate.index().offShellSpectator() )
+ candidate.spectatorMass( spectator->nominalMass() );
+ else
+ candidate.spectatorMass( spectator->mass() );
+ }
+
candidate.continuesEvolving();
Energy hardScale = evolutionOrdering()->maxPt(startScale,candidate,*(gen->second->splittingKernel()));
Energy maxPossible =
gen->second->splittingKinematics()->ptMax(candidate.scale(),
candidate.emitterX(), candidate.spectatorX(),
candidate,
*gen->second->splittingKernel());
Energy ircutoff =
optCutoff < gen->second->splittingKinematics()->IRCutoff() ?
gen->second->splittingKinematics()->IRCutoff() :
optCutoff;
if ( maxPossible <= ircutoff ) {
continue;
}
if ( maxPossible >= hardScale ){
candidate.hardPt(hardScale);
}
else {
hardScale = maxPossible;
candidate.hardPt(maxPossible);
}
-
+
gen->second->generate(candidate,currentWeights(),optHardPt,optCutoff);
Energy nextScale = evolutionOrdering()->evolutionScale(
gen->second->lastSplitting(),*(gen->second->splittingKernel()));
if ( nextScale > winnerScale ) {
winner.fill(candidate);
gen->second->completeSplitting(winner);
winnerGen = gen;
winnerScale = nextScale;
}
reweight(reweight() * gen->second->splittingWeight());
}
if ( winnerGen == generators().end() ) {
winner.didStopEvolving();
return 0.0*GeV;
}
if ( winner.stoppedEvolving() )
return 0.0*GeV;
return winnerScale;
}
void DipoleShowerHandler::doCascade(unsigned int& emDone,
Energy optHardPt,
Energy optCutoff,
const bool decay) {
if ( nEmissions )
if ( emDone == nEmissions )
return;
DipoleSplittingInfo winner;
DipoleSplittingInfo dipoleWinner;
while ( eventRecord().haveChain() ) {
+ // allow the dipole chain to be rearranged according to arXiv:1801.06113
+ if( _rearrange && ( _rearrangeNEmissions < 0 || _rearrangeNEmissions >= emDone ) ){
+ eventRecord().currentChain().rearrange(_dipmax,_diplong);
+ }
+
if ( verbosity > 2 ) {
generator()->log() << "DipoleShowerHandler selecting splittings for the chain:\n"
<< eventRecord().currentChain() << flush;
}
list<Dipole>::iterator winnerDip = eventRecord().currentChain().dipoles().end();
Energy winnerScale = 0.0*GeV;
Energy nextLeftScale = 0.0*GeV;
Energy nextRightScale = 0.0*GeV;
for ( list<Dipole>::iterator dip = eventRecord().currentChain().dipoles().begin();
dip != eventRecord().currentChain().dipoles().end(); ++dip ) {
nextLeftScale = getWinner(dipoleWinner,*dip,{true,false},optHardPt,optCutoff);
if ( nextLeftScale > winnerScale ) {
winnerScale = nextLeftScale;
winner = dipoleWinner;
winnerDip = dip;
}
nextRightScale = getWinner(dipoleWinner,*dip,{false,true},optHardPt,optCutoff);
if ( nextRightScale > winnerScale ) {
winnerScale = nextRightScale;
winner = dipoleWinner;
winnerDip = dip;
}
if ( evolutionOrdering()->independentDipoles() ) {
Energy dipScale = max(nextLeftScale,nextRightScale);
if ( dip->leftScale() > dipScale )
dip->leftScale(dipScale);
if ( dip->rightScale() > dipScale )
dip->rightScale(dipScale);
}
}
if ( verbosity > 1 ) {
if ( winnerDip != eventRecord().currentChain().dipoles().end() )
generator()->log() << "DipoleShowerHandler selected the splitting:\n"
<< winner << " for the dipole\n"
<< (*winnerDip) << flush;
else
generator()->log() << "DipoleShowerHandler could not select a splitting above the IR cutoff\n"
<< flush;
}
// pop the chain if no dipole did radiate
if ( winnerDip == eventRecord().currentChain().dipoles().end() ) {
eventRecord().popChain();
if ( theEventReweight && eventRecord().chains().empty() )
if ( (theEventReweight->firstInteraction() && firstInteraction()) ||
(theEventReweight->secondaryInteractions() && !firstInteraction()) ) {
double w = theEventReweight->weightCascade(eventRecord().incoming(),
eventRecord().outgoing(),
eventRecord().hard(),theGlobalAlphaS);
reweight(reweight()*w);
}
continue;
}
// otherwise perform the splitting
// but first see if the emission would produce a configuration in the ME region.
if ( theMergingHelper
&& eventHandler()->currentCollision()
&& !decay
&& firstInteraction() ) {
if (theMergingHelper->maxLegs()>eventRecord().outgoing().size()+
eventRecord().hard().size()
+2){//incoming
if (theMergingHelper->mergingScale()<winnerScale &&
theMergingHelper->emissionProbability() < UseRandom::rnd()) {
theMergingHelper->setEmissionProbability(0.);
const bool transparent=true;
if (transparent) {
pair<list<Dipole>::iterator,list<Dipole>::iterator> tmpchildren;
DipoleSplittingInfo tmpwinner=winner;
DipoleChain* tmpfirstChain = nullptr;
DipoleChain* tmpsecondChain = nullptr;
auto New=eventRecord().tmpsplit(winnerDip,tmpwinner,
tmpchildren,tmpfirstChain,
tmpsecondChain);
if (theMergingHelper->matrixElementRegion(New.first,
New.second,
winnerScale,
theMergingHelper->mergingScale())) {
optHardPt=winnerScale;
continue;
}
}else{
optHardPt=winnerScale;
continue;
}
}
}
}
if(theMergingHelper&&firstInteraction())
optHardPt=ZERO;
didRadiate = true;
eventRecord().isMCatNLOSEvent(false);
eventRecord().isMCatNLOHEvent(false);
pair<list<Dipole>::iterator,list<Dipole>::iterator> children;
DipoleChain* firstChain = nullptr;
DipoleChain* secondChain = nullptr;
// Note: the dipoles are updated in eventRecord().split(....) after the splitting,
// hence the entire cascade is handled in doCascade
// The dipole scales are updated in dip->split(....)
if ( decay )
winner.isDecayProc( true );
-
+
eventRecord().split(winnerDip,winner,children,firstChain,secondChain);
assert(firstChain && secondChain);
evolutionOrdering()->setEvolutionScale(winnerScale,winner,*firstChain,children);
if ( !secondChain->dipoles().empty() )
evolutionOrdering()->setEvolutionScale(winnerScale,winner,*secondChain,children);
if ( verbosity > 1 ) {
generator()->log() << "DipoleShowerHandler did split the last selected dipole into:\n"
<< (*children.first) << (*children.second) << flush;
}
if ( verbosity > 2 ) {
generator()->log() << "After splitting the last selected dipole, "
<< "DipoleShowerHandler encountered the following chains:\n"
<< (*firstChain) << (*secondChain) << flush;
}
if ( theEventReweight )
if ( (theEventReweight->firstInteraction() && firstInteraction()) ||
(theEventReweight->secondaryInteractions() && !firstInteraction()) ) {
double w = theEventReweight->weight(eventRecord().incoming(),
eventRecord().outgoing(),
eventRecord().hard(),theGlobalAlphaS);
reweight(reweight()*w);
}
if ( nEmissions )
if ( ++emDone == nEmissions )
return;
}
}
bool DipoleShowerHandler::realign() {
if ( !didRadiate && !intrinsicPtGenerator )
return false;
if ( eventRecord().incoming().first->coloured() ||
eventRecord().incoming().second->coloured() ) {
if ( eventRecord().incoming().first->momentum().perp2()/GeV2 < 1e-10 &&
eventRecord().incoming().second->momentum().perp2()/GeV2 < 1e-10 )
return false;
pair<Lorentz5Momentum,Lorentz5Momentum> inMomenta
(eventRecord().incoming().first->momentum(),
eventRecord().incoming().second->momentum());
SpinOneLorentzRotation transform((inMomenta.first+inMomenta.second).findBoostToCM());
Axis dir = (transform * inMomenta.first).vect().unit();
Axis rot (-dir.y(),dir.x(),0);
double theta = dir.theta();
if ( lastParticles().first->momentum().z() < ZERO )
theta = -theta;
transform.rotate(-theta,rot);
inMomenta.first = transform*inMomenta.first;
inMomenta.second = transform*inMomenta.second;
assert(inMomenta.first.z() > ZERO &&
inMomenta.second.z() < ZERO);
Energy2 sHat =
(eventRecord().incoming().first->momentum() +
eventRecord().incoming().second->momentum()).m2();
pair<Energy,Energy> masses(eventRecord().incoming().first->mass(),
eventRecord().incoming().second->mass());
pair<Energy,Energy> qs;
if ( !eventRecord().incoming().first->coloured() ) {
assert(masses.second == ZERO);
qs.first = eventRecord().incoming().first->momentum().z();
qs.second = (sHat-sqr(masses.first))/(2.*(qs.first+sqrt(sqr(masses.first)+sqr(qs.first))));
} else if ( !eventRecord().incoming().second->coloured() ) {
assert(masses.first == ZERO);
qs.second = eventRecord().incoming().second->momentum().z();
qs.first = (sHat-sqr(masses.second))/(2.*(qs.second+sqrt(sqr(masses.second)+sqr(qs.second))));
} else {
assert(masses.first == ZERO && masses.second == ZERO);
if ( realignmentScheme == 0 ) {
double yX = eventRecord().pX().rapidity();
double yInt = (transform*eventRecord().pX()).rapidity();
double dy = yX-yInt;
qs.first = (sqrt(sHat)/2.)*exp(dy);
qs.second = (sqrt(sHat)/2.)*exp(-dy);
} else if ( realignmentScheme == 1 ) {
Energy sS = sqrt((lastParticles().first->momentum() +
lastParticles().second->momentum()).m2());
qs.first = eventRecord().fractions().first * sS / 2.;
qs.second = eventRecord().fractions().second * sS / 2.;
}
}
double beta =
(qs.first-qs.second) /
( sqrt(sqr(masses.first)+sqr(qs.first)) +
sqrt(sqr(masses.second)+sqr(qs.second)) );
transform.boostZ(beta);
Lorentz5Momentum tmp;
if ( eventRecord().incoming().first->coloured() ) {
tmp = eventRecord().incoming().first->momentum();
tmp = transform * tmp;
eventRecord().incoming().first->set5Momentum(tmp);
}
if ( eventRecord().incoming().second->coloured() ) {
tmp = eventRecord().incoming().second->momentum();
tmp = transform * tmp;
eventRecord().incoming().second->set5Momentum(tmp);
}
eventRecord().transform(transform);
return true;
}
return false;
}
void DipoleShowerHandler::resetAlphaS(Ptr<AlphaSBase>::tptr as) {
for ( auto & k : kernels) {
if ( !k->alphaS() )
k->alphaS(as);
k->renormalizationScaleFreeze(theRenormalizationScaleFreeze);
k->factorizationScaleFreeze(theFactorizationScaleFreeze);
}
// clear the generators to be rebuild
// actually, there shouldn't be any generators
// when this happens.
generators().clear();
}
void DipoleShowerHandler::resetReweight(Ptr<DipoleSplittingReweight>::tptr rw) {
for ( auto & g : generators() )
g.second->splittingReweight(rw);
}
void DipoleShowerHandler::getGenerators(const DipoleIndex& ind,
Ptr<DipoleSplittingReweight>::tptr rw) {
bool gotone = false;
for ( auto & k : kernels ) {
if ( k->canHandle(ind) ) {
if ( verbosity > 0 ) {
generator()->log() << "DipoleShowerHandler encountered the dipole configuration\n"
<< ind << " in event number "
<< eventHandler()->currentEvent()->number()
<< "\nwhich can be handled by the splitting kernel '"
<< k->name() << "'.\n" << flush;
}
gotone = true;
Ptr<DipoleSplittingGenerator>::ptr nGenerator =
new_ptr(DipoleSplittingGenerator());
nGenerator->doCompensate(theDoCompensate);
nGenerator->splittingKernel(k);
if ( renormalizationScaleFactor() != 1. )
nGenerator->splittingKernel()->renormalizationScaleFactor(renormalizationScaleFactor());
if ( factorizationScaleFactor() != 1. )
nGenerator->splittingKernel()->factorizationScaleFactor(factorizationScaleFactor());
if ( !nGenerator->splittingReweight() )
nGenerator->splittingReweight(rw);
nGenerator->splittingKernel()->freezeGrid(theFreezeGrid);
nGenerator->splittingKernel()->detuning(theDetuning);
GeneratorMap::const_iterator equivalent = generators().end();
for ( GeneratorMap::const_iterator eq = generators().begin();
eq != generators().end(); ++eq ) {
if ( !eq->second->wrapping() )
if ( k->canHandleEquivalent(ind,*(eq->second->splittingKernel()),eq->first) ) {
equivalent = eq;
if ( verbosity > 0 ) {
generator()->log() << "The dipole configuration "
<< ind
<< " can equivalently be handled by the existing\n"
<< "generator for configuration "
<< eq->first << " using the kernel '"
<< eq->second->splittingKernel()->name()
<< "'\n" << flush;
}
break;
}
}
if ( equivalent != generators().end() ) {
nGenerator->wrap(equivalent->second);
}
DipoleSplittingInfo dummy;
dummy.index(ind);
nGenerator->prepare(dummy);
generators().insert({ind,nGenerator});
}
}
if ( !gotone ) {
throw Exception()
<< "DipoleShowerHandler could not "
<< "find a splitting kernel which is able "
<< "to handle splittings off the dipole "
<< ind << ".\n"
<< "Please check the input files."
<< Exception::runerror;
}
}
// If needed, insert default implementations of virtual function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void DipoleShowerHandler::doinit() {
ShowerHandler::doinit();
if ( theGlobalAlphaS )
resetAlphaS(theGlobalAlphaS);
+ // copy off-shell particle ids before showering from input vector to the
+ // set used in the simulation
+ if ( theColouredOffShellInShower.empty() ) {
+ for(unsigned int ix=0;ix<theInputColouredOffShellInShower.size();++ix)
+ theColouredOffShellInShower.insert(abs(theInputColouredOffShellInShower[ix]));
+ }
+ // work out which shower phase space to use for the matching
+ bool zChoice0 = false;
+ bool zChoice1 = false;
+ size_t zChoiceOther = false;
+ for ( auto & k : kernels) {
+ if ( k->splittingKinematics()->openZBoundaries() == 0 )
+ zChoice0 = true;
+ else if ( k->splittingKinematics()->openZBoundaries() == 1 )
+ zChoice1 = true;
+ else
+ zChoiceOther = true;
+ // either inconsistent or other option which cannot be handled by the matching
+ if ( zChoice0 && zChoice1 ) {
+ zChoiceOther = true; break;
+ }
+ }
+ if ( zChoiceOther )
+ theZBoundaries = 2;
+ else if ( zChoice1 )
+ theZBoundaries = 1;
+ else if ( zChoice0 )
+ theZBoundaries = 0;
}
void DipoleShowerHandler::dofinish() {
ShowerHandler::dofinish();
}
void DipoleShowerHandler::doinitrun() {
ShowerHandler::doinitrun();
}
void DipoleShowerHandler::persistentOutput(PersistentOStream & os) const {
os << kernels << theEvolutionOrdering
- << constituentReshuffler << intrinsicPtGenerator
- << theGlobalAlphaS << chainOrderVetoScales
- << nEmissions << discardNoEmissions << firstMCatNLOEmission
- << thePowhegDecayEmission
- << realignmentScheme << verbosity << printEvent
- << ounit(theRenormalizationScaleFreeze,GeV)
- << ounit(theFactorizationScaleFreeze,GeV)
- << theShowerApproximation
- << theDoCompensate << theFreezeGrid << theDetuning
- << theEventReweight << theSplittingReweight << ounit(maxPt,GeV)
- << ounit(muPt,GeV)<< theMergingHelper;
+ << constituentReshuffler << intrinsicPtGenerator
+ << theGlobalAlphaS << chainOrderVetoScales
+ << nEmissions << discardNoEmissions << firstMCatNLOEmission
+ << thePowhegDecayEmission
+ << realignmentScheme << verbosity << printEvent
+ << ounit(theRenormalizationScaleFreeze,GeV)
+ << ounit(theFactorizationScaleFreeze,GeV)
+ << theShowerApproximation
+ << theDoCompensate << theFreezeGrid << theDetuning
+ << theEventReweight << theSplittingReweight << ounit(maxPt,GeV)
+ << ounit(muPt,GeV)<< theMergingHelper << theColouredOffShellInShower
+ << theInputColouredOffShellInShower
+ << _rearrange << _dipmax << _diplong << _rearrangeNEmissions << theZBoundaries;
}
void DipoleShowerHandler::persistentInput(PersistentIStream & is, int) {
is >> kernels >> theEvolutionOrdering
- >> constituentReshuffler >> intrinsicPtGenerator
- >> theGlobalAlphaS >> chainOrderVetoScales
- >> nEmissions >> discardNoEmissions >> firstMCatNLOEmission
- >> thePowhegDecayEmission
- >> realignmentScheme >> verbosity >> printEvent
- >> iunit(theRenormalizationScaleFreeze,GeV)
- >> iunit(theFactorizationScaleFreeze,GeV)
- >> theShowerApproximation
- >> theDoCompensate >> theFreezeGrid >> theDetuning
- >> theEventReweight >> theSplittingReweight >> iunit(maxPt,GeV)
- >> iunit(muPt,GeV)>>theMergingHelper;
+ >> constituentReshuffler >> intrinsicPtGenerator
+ >> theGlobalAlphaS >> chainOrderVetoScales
+ >> nEmissions >> discardNoEmissions >> firstMCatNLOEmission
+ >> thePowhegDecayEmission
+ >> realignmentScheme >> verbosity >> printEvent
+ >> iunit(theRenormalizationScaleFreeze,GeV)
+ >> iunit(theFactorizationScaleFreeze,GeV)
+ >> theShowerApproximation
+ >> theDoCompensate >> theFreezeGrid >> theDetuning
+ >> theEventReweight >> theSplittingReweight >> iunit(maxPt,GeV)
+ >> iunit(muPt,GeV)>>theMergingHelper >> theColouredOffShellInShower
+ >> theInputColouredOffShellInShower
+ >> _rearrange >> _dipmax >> _diplong >> _rearrangeNEmissions >> theZBoundaries;
}
ClassDescription<DipoleShowerHandler> DipoleShowerHandler::initDipoleShowerHandler;
// Definition of the static class description member.
void DipoleShowerHandler::Init() {
static ClassDocumentation<DipoleShowerHandler> documentation
("The DipoleShowerHandler class manages the showering using "
"the dipole shower algorithm.",
"The shower evolution was performed using the algorithm described in "
"\\cite{Platzer:2009jq} and \\cite{Platzer:2011bc}.",
"%\\cite{Platzer:2009jq}\n"
"\\bibitem{Platzer:2009jq}\n"
"S.~Platzer and S.~Gieseke,\n"
"``Coherent Parton Showers with Local Recoils,''\n"
" JHEP {\\bf 1101}, 024 (2011)\n"
"arXiv:0909.5593 [hep-ph].\n"
"%%CITATION = ARXIV:0909.5593;%%\n"
"%\\cite{Platzer:2011bc}\n"
"\\bibitem{Platzer:2011bc}\n"
"S.~Platzer and S.~Gieseke,\n"
"``Dipole Showers and Automated NLO Matching in Herwig,''\n"
"arXiv:1109.6256 [hep-ph].\n"
"%%CITATION = ARXIV:1109.6256;%%");
static RefVector<DipoleShowerHandler,DipoleSplittingKernel> interfaceKernels
("Kernels",
"Set the splitting kernels to be used by the dipole shower.",
&DipoleShowerHandler::kernels, -1, false, false, true, false, false);
static Reference<DipoleShowerHandler,DipoleEvolutionOrdering> interfaceEvolutionOrdering
("EvolutionOrdering",
"Set the evolution ordering to be used.",
&DipoleShowerHandler::theEvolutionOrdering, false, false, true, false, false);
static Reference<DipoleShowerHandler,ConstituentReshuffler> interfaceConstituentReshuffler
("ConstituentReshuffler",
"The object to be used to reshuffle partons to their constitutent mass shells.",
&DipoleShowerHandler::constituentReshuffler, false, false, true, true, false);
static Reference<DipoleShowerHandler,IntrinsicPtGenerator> interfaceIntrinsicPtGenerator
("IntrinsicPtGenerator",
"Set the object in charge to generate intrinsic pt for incoming partons.",
&DipoleShowerHandler::intrinsicPtGenerator, false, false, true, true, false);
static Reference<DipoleShowerHandler,AlphaSBase> interfaceGlobalAlphaS
("GlobalAlphaS",
"Set a global strong coupling for all splitting kernels.",
&DipoleShowerHandler::theGlobalAlphaS, false, false, true, true, false);
static Switch<DipoleShowerHandler,int> interfaceRealignmentScheme
("RealignmentScheme",
"The realignment scheme to use.",
&DipoleShowerHandler::realignmentScheme, 0, false, false);
static SwitchOption interfaceRealignmentSchemePreserveRapidity
(interfaceRealignmentScheme,
"PreserveRapidity",
"Preserve the rapidity of non-coloured outgoing system.",
0);
static SwitchOption interfaceRealignmentSchemeEvolutionFractions
(interfaceRealignmentScheme,
"EvolutionFractions",
"Use momentum fractions as generated by the evolution.",
1);
static SwitchOption interfaceRealignmentSchemeCollisionFrame
(interfaceRealignmentScheme,
"CollisionFrame",
"Determine realignment from collision frame.",
2);
static Switch<DipoleShowerHandler,bool> interfaceChainOrderVetoScales
("ChainOrderVetoScales",
"[experimental] Switch the chain ordering for veto scales on or off.",
&DipoleShowerHandler::chainOrderVetoScales, true, false, false);
static SwitchOption interfaceChainOrderVetoScalesYes
(interfaceChainOrderVetoScales,
"Yes",
"Switch on chain ordering for veto scales.",
true);
static SwitchOption interfaceChainOrderVetoScalesNo
(interfaceChainOrderVetoScales,
"No",
"Switch off chain ordering for veto scales.",
false);
interfaceChainOrderVetoScales.rank(-1);
static Parameter<DipoleShowerHandler,unsigned int> interfaceNEmissions
("NEmissions",
"[debug option] Limit the number of emissions to be generated. Zero does not limit the number of emissions.",
&DipoleShowerHandler::nEmissions, 0, 0, 0,
false, false, Interface::lowerlim);
interfaceNEmissions.rank(-1);
static Switch<DipoleShowerHandler,bool> interfaceDiscardNoEmissions
("DiscardNoEmissions",
"[debug option] Discard events without radiation.",
&DipoleShowerHandler::discardNoEmissions, false, false, false);
static SwitchOption interfaceDiscardNoEmissionsYes
(interfaceDiscardNoEmissions,
"Yes",
"Discard events without radiation.",
true);
static SwitchOption interfaceDiscardNoEmissionsNo
(interfaceDiscardNoEmissions,
"No",
"Do not discard events without radiation.",
false);
interfaceDiscardNoEmissions.rank(-1);
static Switch<DipoleShowerHandler,bool> interfaceFirstMCatNLOEmission
("FirstMCatNLOEmission",
"[debug option] Only perform the first MC@NLO emission.",
&DipoleShowerHandler::firstMCatNLOEmission, false, false, false);
static SwitchOption interfaceFirstMCatNLOEmissionYes
(interfaceFirstMCatNLOEmission,
"Yes",
"Perform only the first MC@NLO emission.",
true);
static SwitchOption interfaceFirstMCatNLOEmissionNo
(interfaceFirstMCatNLOEmission,
"No",
"Produce all emissions.",
false);
interfaceFirstMCatNLOEmission.rank(-1);
static Parameter<DipoleShowerHandler,int> interfaceVerbosity
("Verbosity",
"[debug option] Set the level of debug information provided.",
&DipoleShowerHandler::verbosity, 0, 0, 0,
false, false, Interface::lowerlim);
interfaceVerbosity.rank(-1);
static Parameter<DipoleShowerHandler,int> interfacePrintEvent
("PrintEvent",
"[debug option] The number of events for which debugging information should be provided.",
&DipoleShowerHandler::printEvent, 0, 0, 0,
false, false, Interface::lowerlim);
interfacePrintEvent.rank(-1);
static Parameter<DipoleShowerHandler,Energy> interfaceRenormalizationScaleFreeze
("RenormalizationScaleFreeze",
"The freezing scale for the renormalization scale.",
&DipoleShowerHandler::theRenormalizationScaleFreeze, GeV, 1.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Parameter<DipoleShowerHandler,Energy> interfaceFactorizationScaleFreeze
("FactorizationScaleFreeze",
"The freezing scale for the factorization scale.",
&DipoleShowerHandler::theFactorizationScaleFreeze, GeV, 2.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Switch<DipoleShowerHandler,bool> interfaceDoCompensate
("DoCompensate",
"",
&DipoleShowerHandler::theDoCompensate, false, false, false);
static SwitchOption interfaceDoCompensateYes
(interfaceDoCompensate,
"Yes",
"",
true);
static SwitchOption interfaceDoCompensateNo
(interfaceDoCompensate,
"No",
"",
false);
static Parameter<DipoleShowerHandler,unsigned long> interfaceFreezeGrid
("FreezeGrid",
"",
&DipoleShowerHandler::theFreezeGrid, 500000, 1, 0,
false, false, Interface::lowerlim);
static Parameter<DipoleShowerHandler,double> interfaceDetuning
("Detuning",
"A value to detune the overestimate kernel.",
&DipoleShowerHandler::theDetuning, 1.0, 1.0, 0,
false, false, Interface::lowerlim);
static Reference<DipoleShowerHandler,DipoleEventReweight> interfaceEventReweight
("EventReweight",
"",
&DipoleShowerHandler::theEventReweight, false, false, true, true, false);
static Reference<DipoleShowerHandler,DipoleSplittingReweight> interfaceSplittingReweight
("SplittingReweight",
"Set the splitting reweight.",
&DipoleShowerHandler::theSplittingReweight, false, false, true, true, false);
static Switch<DipoleShowerHandler, bool> interfacePowhegDecayEmission
("PowhegDecayEmission",
"Use Powheg style emission for the decays",
&DipoleShowerHandler::thePowhegDecayEmission, true, false, false);
static SwitchOption interfacePowhegDecayEmissionYes
(interfacePowhegDecayEmission,"Yes","Powheg decay emission on", true);
static SwitchOption interfacePowhegDecayEmissionNo
(interfacePowhegDecayEmission,"No","Powheg decay emission off", false);
+
+ static ParVector<DipoleShowerHandler,long> interfaceOffShellInShower
+ ("OffShellInShower",
+ "PDG codes of the coloured particles that can be off-shell in the process.",
+ &DipoleShowerHandler::theInputColouredOffShellInShower, -1, 0l, -10000000l, 10000000l,
+ false, false, Interface::limited);
+
+ static Switch<DipoleShowerHandler, bool> interfacerearrange
+ ("Rearrange",
+ "Allow rearranging of dipole chains according to arXiv:1801.06113",
+ &DipoleShowerHandler::_rearrange, false, false, false);
+
+ static SwitchOption interfacerearrangeYes
+ (interfacerearrange,"Yes","_rearrange on", true);
+
+ static SwitchOption interfacerearrangeNo
+ (interfacerearrange,"No","_rearrange off", false);
+
+ static Parameter<DipoleShowerHandler,unsigned int> interfacedipmax
+ ("DipMax",
+ "Allow rearrangment of color chains with ME including dipmax dipoles.",
+ &DipoleShowerHandler::_dipmax, 0, 0, 0,
+ false, false, Interface::lowerlim);
+
+ static Parameter<DipoleShowerHandler,unsigned int> interfacediplong
+ ("DipLong",
+ "Dipole chains with more than dipmax dipoles are treated as long. \
+ diplong=3 rearranges these chains with eeuugg MEs, \
+ diplong=4 rearranges these chains with eeuuggg MEs (slower), \
+ diplong=5 rearranges these chains with eeuugggg MEs (slow).\
+ Note: Numerically there is no difference between the options. ",
+ &DipoleShowerHandler::_diplong, 0, 0, 0,
+ false, false, Interface::lowerlim);
+
+ static Parameter<DipoleShowerHandler, int> interfacedcorrectNemissions
+ ("RearrangeNEmissions",
+ "Allow rearrangment of color chains up to the nth emission.",
+ &DipoleShowerHandler::_rearrangeNEmissions, 0, 0, 0,
+ false, false, Interface::lowerlim);
+
}
diff --git a/Shower/Dipole/DipoleShowerHandler.h b/Shower/Dipole/DipoleShowerHandler.h
--- a/Shower/Dipole/DipoleShowerHandler.h
+++ b/Shower/Dipole/DipoleShowerHandler.h
@@ -1,554 +1,603 @@
// -*- C++ -*-
//
// DipoleShowerHandler.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_DipoleShowerHandler_H
#define HERWIG_DipoleShowerHandler_H
//
// This is the declaration of the DipoleShowerHandler class.
//
#include "Herwig/Shower/ShowerHandler.h"
#include "Herwig/Shower/Dipole/DipoleShowerHandler.fh"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingReweight.h"
#include "Herwig/Shower/Dipole/Kernels/DipoleSplittingKernel.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleEventRecord.h"
#include "Herwig/Shower/Dipole/Base/DipoleEvolutionOrdering.h"
#include "Herwig/Shower/Dipole/Base/DipoleEventReweight.h"
#include "Herwig/Shower/Dipole/Utility/ConstituentReshuffler.h"
#include "Herwig/Shower/Dipole/Utility/IntrinsicPtGenerator.h"
#include "Herwig/MatrixElement/Matchbox/Base/MergerBase.h"
#include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer, Stephen Webster
*
* \brief The DipoleShowerHandler class manages the showering using
* the dipole shower algorithm.
*
* @see \ref DipoleShowerHandlerInterfaces "The interfaces"
* defined for DipoleShowerHandler.
*/
class DipoleShowerHandler: public ShowerHandler {
friend class Merger;
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
DipoleShowerHandler();
/**
* The destructor.
*/
virtual ~DipoleShowerHandler();
//@}
public:
inline void colourPrint();
/**
* Indicate a problem in the shower.
*/
struct RedoShower {};
/**
* Insert an additional splitting kernel.
*/
void addSplitting(Ptr<DipoleSplittingKernel>::ptr sp) {
kernels.push_back(sp);
}
/**
* Reset the alpha_s for all splitting kernels.
*/
void resetAlphaS(Ptr<AlphaSBase>::tptr);
virtual void cascade(tPVector);
/**
* Reset the splitting reweight for all splitting kernels.
*/
void resetReweight(Ptr<DipoleSplittingReweight>::tptr);
/**
* Return true, if the shower handler can generate a truncated
* shower for POWHEG style events generated using Matchbox
*/
virtual bool canHandleMatchboxTrunc() const { return false; }
/**
* Return true, if this cascade handler will perform reshuffling from hard
* process masses.
*/
virtual bool isReshuffling() const { return false; }
/**
* Return the relevant hard scale to be used in the profile scales
*/
virtual Energy hardScale() const {
return muPt;
}
/**
* Calculate the alpha_s value the shower uses for Q.
*/
double as(Energy Q)const{return theGlobalAlphaS->value(sqr(Q));}
/**
* Return the number of scale dependent active flavours from
* the alpha_s object.
*/
double Nf(Energy Q)const{return theGlobalAlphaS->Nf(sqr(Q));}
/**
* Set the pointer to the Merging Helper.
* Used by the merging factory.
*/
void setMerger(Ptr<MergerBase>::ptr mh){theMergingHelper=mh;}
protected:
typedef multimap<DipoleIndex,Ptr<DipoleSplittingGenerator>::ptr> GeneratorMap;
/**
* The main method which manages the showering of a subprocess.
*/
virtual tPPair cascade(tSubProPtr sub, XCombPtr xcomb) {
return cascade(sub,xcomb,ZERO,ZERO);
}
/**
* The main method which manages the showering of a subprocess.
*/
tPPair cascade(tSubProPtr sub, XCombPtr xcomb,
Energy optHardPt, Energy optCutoff);
/**
* Build splitting generators for the given
* dipole index.
*/
void getGenerators(const DipoleIndex&,
Ptr<DipoleSplittingReweight>::tptr rw =
Ptr<DipoleSplittingReweight>::tptr());
/**
* Setup the hard scales.
*/
void hardScales(Energy2 scale);
/**
* Return the evolution ordering
*/
Ptr<DipoleEvolutionOrdering>::tptr evolutionOrdering() const { return theEvolutionOrdering; }
/**
* Reshuffle to constituent mass shells
*/
void constituentReshuffle();
/**
* Reshuffle to constituent mass shells
*/
void decayConstituentReshuffle( PerturbativeProcessPtr decayProc);
/**
* Access the generator map
*/
GeneratorMap& generators() { return theGenerators; }
/**
* Access the event record
*/
DipoleEventRecord& eventRecord() { return theEventRecord; }
/**
* Return the event record
*/
const DipoleEventRecord& eventRecord() const { return theEventRecord; }
/**
* Return the splitting kernels.
*/
const vector<Ptr<DipoleSplittingKernel>::ptr>& splittingKernels() const {
return kernels;
}
/**
+ * Return the set of offshell parton ids.
+ **/
+ const set<long>& offShellPartons() { return theColouredOffShellInShower; }
+
+ /**
* Realign the event such as to have the incoming partons along thre
* beam axes.
*/
bool realign();
+ /**
+ * The choice of z boundaries; 0 = restricted, 1 = open, 2 = mixed/other
+ */
+ virtual int showerPhaseSpaceOption() const {
+ return theZBoundaries;
+ }
+
protected:
/**
* Perform the cascade.
*/
void doCascade(unsigned int& emDone,
Energy optHardPt = ZERO,
Energy optCutoff = ZERO,
const bool decay = false);
/**
* Set the number of emissions
**/
void setNEmissions(unsigned int n){nEmissions=n;}
/**
* Get the winning splitting for the
* given dipole and configuration.
*/
Energy getWinner(DipoleSplittingInfo& winner,
const Dipole& dip,
pair<bool,bool> conf,
Energy optHardPt = ZERO,
Energy optCutoff = ZERO);
/**
* Get the winning splitting for the
* given dipole and configuration.
*/
Energy getWinner(SubleadingSplittingInfo& winner,
Energy optHardPt = ZERO,
Energy optCutoff = ZERO);
/**
* Get the winning splitting for the
* given dipole and configuration.
*/
Energy getWinner(DipoleSplittingInfo& winner,
const DipoleIndex& index,
double emitterX, double spectatorX,
pair<bool,bool> conf,
tPPtr emitter, tPPtr spectator,
Energy startScale,
Energy optHardPt = ZERO,
Energy optCutoff = ZERO);
-
+
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;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
protected:
/** @name Standard Interfaced functions. */
//@{
/**
* Initialize this object after the setup phase before saving an
* EventGenerator to disk.
* @throws InitException if object could not be initialized properly.
*/
virtual void doinit();
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
/**
* Finalize this object. Called in the run phase just after a
* run has ended. Used eg. to write out statistics.
*/
virtual void dofinish();
//@}
private:
/**
* The splitting kernels to be used.
*/
vector<Ptr<DipoleSplittingKernel>::ptr> kernels;
/**
* The evolution ordering considered
*/
Ptr<DipoleEvolutionOrdering>::ptr theEvolutionOrdering;
/**
* The ConstituentReshuffler to be used
*/
Ptr<ConstituentReshuffler>::ptr constituentReshuffler;
/**
* The intrinsic pt generator to be used.
*/
Ptr<IntrinsicPtGenerator>::ptr intrinsicPtGenerator;
/**
* A global alpha_s to be used for all splitting kernels.
*/
Ptr<AlphaSBase>::ptr theGlobalAlphaS;
/**
* Apply chain ordering to events from matrix
* element corrections.
*/
bool chainOrderVetoScales;
/**
* Limit the number of emissions.
* Limit applied if > 0.
*/
unsigned int nEmissions;
/**
* Discard events which did not radiate.
*/
bool discardNoEmissions;
/**
* Perform the first MC@NLO emission only.
*/
bool firstMCatNLOEmission;
/**
* True if powheg style emissions are to be used in the decays
*/
bool thePowhegDecayEmission;
/**
* The realignment scheme
*/
int realignmentScheme;
private:
/**
* The verbosity level.
* 0 - print no info
* 1 - print diagnostic information on setting up
* splitting generators etc.
* 2 - print detailed event information for up to
* printEvent events.
* 3 - print dipole chains after each splitting.
*/
int verbosity;
/**
* See verbosity.
*/
int printEvent;
private:
/**
* The splitting generators indexed by the dipole
* indices they can work on.
*/
GeneratorMap theGenerators;
/**
* The evnt record used.
*/
DipoleEventRecord theEventRecord;
/**
* The number of shoer tries so far.
*/
unsigned int nTries;
/**
* Whether or not we did radiate anything
*/
bool didRadiate;
/**
* Whether or not we did realign the event
*/
bool didRealign;
private:
/**
* A freezing value for the renormalization scale
*/
Energy theRenormalizationScaleFreeze;
/**
* A freezing value for the factorization scale
*/
Energy theFactorizationScaleFreeze;
/**
* The matching subtraction, if appropriate
*/
Ptr<ShowerApproximation>::tptr theShowerApproximation;
/**
* True, if sampler should apply compensation
*/
bool theDoCompensate;
/**
* Return the number of accepted points after which the grid should
* be frozen
*/
unsigned long theFreezeGrid;
/**
* The detuning factor applied to the sampling overestimate kernel
*/
double theDetuning;
/**
* A pointer to the dipole event reweight object
*/
Ptr<DipoleEventReweight>::ptr theEventReweight;
/**
* A pointer to a global dipole splitting reweight
*/
Ptr<DipoleSplittingReweight>::ptr theSplittingReweight;
/**
* True if no warnings have been issued yet
*/
static bool firstWarn;
/**
* The shower starting scale for the last event encountered
*/
Energy maxPt;
/**
* The shower hard scale for the last event encountered
*/
Energy muPt;
/**
* The merging helper takes care of merging multiple LO and NLO
* cross sections. Here we need to check if an emission would
* radiate in the matrix element region of an other multipicity.
* If so, the emission is vetoed.
*/
Ptr<MergerBase>::ptr theMergingHelper;
+
+
+ /**
+ * PDG codes of the partons which can have an off-shell mass,
+ * this is fast storage for use during running
+ */
+ set<long> theColouredOffShellInShower;
+
+ /**
+ * PDG codes of the partons which can have an off-shell mass,
+ * this is a vector that is interfaced so they can be changed
+ */
+ vector<long> theInputColouredOffShellInShower;
+ /**
+ * Allow the dipole chains to be rearranged
+ */
+ bool _rearrange=false;
+
+ /**
+ * number of maximal ME dipoles in the rearrangement.
+ */
+ unsigned int _dipmax=3;
+
+ /**
+ * If a chain is considered long (more than dipmax dipoles)
+ * ME with diplong dipoles are used to test for rearrangement.
+ */
+ unsigned int _diplong=3;
-
+ /**
+ * Number of emissions to be rearranged.
+ */
+ int _rearrangeNEmissions=-1;
+
+ /**
+ * The choice of z boundaries; 0 = restricted, 1 = open, 2 = mixed/other
+ */
+ int theZBoundaries;
+
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<DipoleShowerHandler> initDipoleShowerHandler;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
DipoleShowerHandler & operator=(const DipoleShowerHandler &);
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of DipoleShowerHandler. */
template <>
struct BaseClassTrait<Herwig::DipoleShowerHandler,1> {
/** Typedef of the first base class of DipoleShowerHandler. */
typedef Herwig::ShowerHandler NthBase;
};
/** This template specialization informs ThePEG about the name of
* the DipoleShowerHandler class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::DipoleShowerHandler>
: public ClassTraitsBase<Herwig::DipoleShowerHandler> {
/** Return a platform-independent class name */
static string className() { return "Herwig::DipoleShowerHandler"; }
/**
* The name of a file containing the dynamic library where the class
* DipoleShowerHandler is implemented. It may also include several, space-separated,
* libraries if the class DipoleShowerHandler depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_DipoleShowerHandler_H */
diff --git a/Shower/Dipole/Kernels/FFMgx2ggxDipoleKernel.cc b/Shower/Dipole/Kernels/FFMgx2ggxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FFMgx2ggxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FFMgx2ggxDipoleKernel.cc
@@ -1,135 +1,142 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFMgx2ggxDipoleKernel class.
//
#include "FFMgx2ggxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FFMgx2ggxDipoleKernel::FFMgx2ggxDipoleKernel()
- : DipoleSplittingKernel(),theSymmetryFactor(0.5) {}
+ : DipoleSplittingKernel(){}
FFMgx2ggxDipoleKernel::~FFMgx2ggxDipoleKernel() {}
IBPtr FFMgx2ggxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FFMgx2ggxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FFMgx2ggxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.emitterData()->id() == ParticleID::g &&
ind.spectatorData()->mass() != ZERO &&
!ind.initialStateEmitter() && !ind.initialStateSpectator() &&
!ind.incomingDecayEmitter() && !ind.incomingDecaySpectator();
}
bool FFMgx2ggxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emitter(b)->id() == ParticleID::g &&
sk.emission(b)->id() == ParticleID::g &&
abs(spectator(a)->mass()) == abs(sk.spectator(b)->mass());
}
tcPDPtr FFMgx2ggxDipoleKernel::emitter(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FFMgx2ggxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FFMgx2ggxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double FFMgx2ggxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
// These are the physical variables as used in the
// standard form of the kernel (i.e. do not redefine variables or kernel)
const double z = split.lastZ();
const Energy pt = split.lastPt();
// Need zPrime to calculate y,
// TODO: Should just store y in the dipole splitting info everywhere anyway!!!
// The only value stored in dInfo.lastSplittingParameters() should be zPrime
const double zPrime = split.lastSplittingParameters()[0];
// Construct mass squared variables
// Construct mass squared variables
- double muj2 = sqr(split.spectatorData()->mass() / split.scale());
+ double muj2 = sqr(split.spectatorMass() / split.scale());
double bar = 1. - muj2;
// Calculate y
double y = sqr(pt)/sqr(split.scale()) / (bar*zPrime*(1.-zPrime));
double vijk = sqrt( sqr(2.*muj2+bar*(1.-y))-4.*muj2 ) / (bar*(1.-y));
double viji = 1.;
double zp = 0.5*(1.+viji*vijk);
double zm = 0.5*(1.-viji*vijk);
// how to choose kappa?
double kappa = 0.;
- ret *= theSymmetryFactor*3.*(1./(1.-z*(1.-y))+1./(1.-(1.-z)*(1.-y)) + (z*(1.-z)-(1.-kappa)*zp*zm-2.)/vijk);
+ double S1=1./(1.-z*(1.-y));
+ double S2=1./(1.-(1.-z)*(1.-y));
+ double NS=(z*(1.-z)-(1.-kappa)*zp*zm-2.)/vijk;
+
+ if( theAsymmetryOption == 0 ){
+ ret *= 3.*( S1 + 0.5 * NS);
+ }else if ( theAsymmetryOption == 1 ){
+ ret *= 3.*z*( S1 +S2 + NS );
+ }else{
+ ret *= 3.*0.5*( S1 + S2 + NS );
+ }
- return ret > 0. ? ret : 0.;
-
+ return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FFMgx2ggxDipoleKernel::persistentOutput(PersistentOStream & os) const {
- os<<theSymmetryFactor;
+ os << theAsymmetryOption;
}
void FFMgx2ggxDipoleKernel::persistentInput(PersistentIStream & is, int) {
- is>>theSymmetryFactor;
+ is >> theAsymmetryOption;
}
ClassDescription<FFMgx2ggxDipoleKernel> FFMgx2ggxDipoleKernel::initFFMgx2ggxDipoleKernel;
// Definition of the static class description member.
void FFMgx2ggxDipoleKernel::Init() {
static ClassDocumentation<FFMgx2ggxDipoleKernel> documentation
("FFMgx2ggxDipoleKernel");
-
- static Parameter<FFMgx2ggxDipoleKernel,double> interfaceSymmetryFactor
- ("SymmetryFactor",
- "The symmetry factor for final state gluon spliitings.",
- &FFMgx2ggxDipoleKernel::theSymmetryFactor, 1.0, 0.0, 0,
- false, false, Interface::lowerlim);
-
+
+ static Parameter<FFMgx2ggxDipoleKernel,int> interfacetheAsymmetryOption
+ ("AsymmetryOption",
+ "The asymmetry option for final state gluon spliitings.",
+ &FFMgx2ggxDipoleKernel::theAsymmetryOption, 1, 0, 0,
+ false, false, Interface::lowerlim);
}
-
diff --git a/Shower/Dipole/Kernels/FFMgx2ggxDipoleKernel.h b/Shower/Dipole/Kernels/FFMgx2ggxDipoleKernel.h
--- a/Shower/Dipole/Kernels/FFMgx2ggxDipoleKernel.h
+++ b/Shower/Dipole/Kernels/FFMgx2ggxDipoleKernel.h
@@ -1,187 +1,187 @@
// -*- C++ -*-
#ifndef HERWIG_FFMgx2ggxDipoleKernel_H
#define HERWIG_FFMgx2ggxDipoleKernel_H
//
// This is the declaration of the FFMgx2ggxDipoleKernel class.
//
#include "DipoleSplittingKernel.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer, Martin Stoll, Stephen Webster
*
* \brief FFMgx2ggxDipoleKernel implements the g -> gg
* splitting off a final-final dipole
*
*/
class FFMgx2ggxDipoleKernel: public DipoleSplittingKernel {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
FFMgx2ggxDipoleKernel();
/**
* The destructor.
*/
virtual ~FFMgx2ggxDipoleKernel();
//@}
public:
/**
* Return true, if this splitting kernel
* applies to the given dipole index.
*/
virtual bool canHandle(const DipoleIndex&) const;
/**
* Return true, if this splitting kernel is
* the same for the given index a, as the given
* splitting kernel for index b.
*/
virtual bool canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const;
/**
* Return the emitter data after splitting, given
* a dipole index.
*/
virtual tcPDPtr emitter(const DipoleIndex&) const;
/**
* Return the emission data after splitting, given
* a dipole index.
*/
virtual tcPDPtr emission(const DipoleIndex&) const;
/**
* Return the spectator data after splitting, given
* a dipole index.
*/
virtual tcPDPtr spectator(const DipoleIndex&) const;
/**
* Evaluate this splitting kernel for the given
* dipole splitting.
*/
virtual double evaluate(const DipoleSplittingInfo&) 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;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
- * Symmetry factor for final state gluon splittings (should be 1/2).
+ * Asymmetry option for final state gluon splittings.
*/
- double theSymmetryFactor;
+ int theAsymmetryOption=1;
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<FFMgx2ggxDipoleKernel> initFFMgx2ggxDipoleKernel;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FFMgx2ggxDipoleKernel & operator=(const FFMgx2ggxDipoleKernel &);
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of FFMgx2ggxDipoleKernel. */
template <>
struct BaseClassTrait<Herwig::FFMgx2ggxDipoleKernel,1> {
/** Typedef of the first base class of FFMgx2ggxDipoleKernel. */
typedef Herwig::DipoleSplittingKernel NthBase;
};
/** This template specialization informs ThePEG about the name of
* the FFMgx2ggxDipoleKernel class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::FFMgx2ggxDipoleKernel>
: public ClassTraitsBase<Herwig::FFMgx2ggxDipoleKernel> {
/** Return a platform-independent class name */
static string className() { return "Herwig::FFMgx2ggxDipoleKernel"; }
/**
* The name of a file containing the dynamic library where the class
* FFMgx2ggxDipoleKernel is implemented. It may also include several, space-separated,
* libraries if the class FFMgx2ggxDipoleKernel depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_FFMgx2ggxDipoleKernel_H */
diff --git a/Shower/Dipole/Kernels/FFMgx2qqxDipoleKernel.cc b/Shower/Dipole/Kernels/FFMgx2qqxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FFMgx2qqxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FFMgx2qqxDipoleKernel.cc
@@ -1,133 +1,133 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFMgx2qqxDipoleKernel class.
//
#include "FFMgx2qqxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FFMgx2qqxDipoleKernel::FFMgx2qqxDipoleKernel()
: DipoleSplittingKernel() {}
FFMgx2qqxDipoleKernel::~FFMgx2qqxDipoleKernel() {}
IBPtr FFMgx2qqxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FFMgx2qqxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FFMgx2qqxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.emitterData()->id() == ParticleID::g &&
!( ind.spectatorData()->mass() == ZERO &&
flavour()->mass() == ZERO ) &&
!ind.initialStateEmitter() && !ind.initialStateSpectator() &&
!ind.incomingDecayEmitter() && !ind.incomingDecaySpectator();
}
bool FFMgx2qqxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emitter(b)->id() + sk.emission(b)->id() == 0 &&
abs(sk.emitter(b)->id()) < 6 &&
emitter(a)->id() == sk.emitter(b)->id() &&
abs(sk.spectator(b)->mass()) == abs(spectator(a)->mass());
}
tcPDPtr FFMgx2qqxDipoleKernel::emitter(const DipoleIndex&) const {
assert(flavour());
assert(abs(flavour()->id()) < 6);
return flavour();
}
tcPDPtr FFMgx2qqxDipoleKernel::emission(const DipoleIndex&) const {
assert(flavour());
assert(abs(flavour()->id()) < 6);
return flavour()->CC();
}
tcPDPtr FFMgx2qqxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double FFMgx2qqxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
// These are the physical variables as used in the
//standard form of the kernel (i.e. do not redefine variables or kernel)
double z = split.lastZ();
Energy pt = split.lastPt();
// Need zPrime to calculate y,
// TODO: Should just store y in the dipole splitting info everywhere anyway!!!
// The only value stored in dInfo.lastSplittingParameters() should be zPrime
//assert(split.lastSplittingParameters().size() == 1 );
double zPrime = split.lastSplittingParameters()[0];
// Construct mass squared variables
double mui2 = sqr(split.emitterData()->mass() / split.scale());
double mu2 = mui2;
- double muj2 = sqr(split.spectatorData()->mass() / split.scale());
+ double muj2 = sqr(split.spectatorMass() / split.scale());
double bar = 1. - mui2 - mu2 - muj2;
// Calculate y
double y = (sqr(pt)/sqr(split.scale())
+ sqr(1.-zPrime)*mui2 + sqr(zPrime)*mu2)
/ (bar*zPrime*(1.-zPrime));
double vijk = sqrt( sqr(2.*muj2+bar*(1.-y))-4.*muj2 ) / (bar*(1.-y));
double viji = sqrt( sqr(bar*y)-4.*sqr(mui2) ) / (bar*y+2.*mui2);
double zp = 0.5*(1.+viji*vijk);
double zm = 0.5*(1.-viji*vijk);
// how to choose kappa??
double kappa = 0.;
ret *= 0.25 / vijk *
( 1. - 2.*( z*(1.-z) - (1.-kappa)*zp*zm
- kappa*mui2/(2.*mui2+(1.-2.*mui2-muj2)*y) ) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FFMgx2qqxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void FFMgx2qqxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<FFMgx2qqxDipoleKernel>
FFMgx2qqxDipoleKernel::initFFMgx2qqxDipoleKernel;
// Definition of the static class description member.
void FFMgx2qqxDipoleKernel::Init() {
static ClassDocumentation<FFMgx2qqxDipoleKernel> documentation
("FFMgx2qqxDipoleKernel");
}
diff --git a/Shower/Dipole/Kernels/FFMqx2qgxDipoleKernel.cc b/Shower/Dipole/Kernels/FFMqx2qgxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FFMqx2qgxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FFMqx2qgxDipoleKernel.cc
@@ -1,124 +1,126 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFMqx2qgxDipoleKernel class.
//
#include "FFMqx2qgxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FFMqx2qgxDipoleKernel::FFMqx2qgxDipoleKernel()
: DipoleSplittingKernel() {}
FFMqx2qgxDipoleKernel::~FFMqx2qgxDipoleKernel() {}
IBPtr FFMqx2qgxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FFMqx2qgxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FFMqx2qgxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
abs(ind.emitterData()->id()) < 7 &&
// 2012-05-01
abs(ind.emitterData()->id()) == abs(flavour()->id()) &&
!( ind.emitterData()->mass() == ZERO &&
ind.spectatorData()->mass() == ZERO ) &&
!ind.initialStateEmitter() && !ind.initialStateSpectator() &&
!ind.incomingDecayEmitter() && !ind.incomingDecaySpectator();
}
bool FFMqx2qgxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emission(b)->id() == ParticleID::g &&
abs(sk.emitter(b)->id()) < 7 &&
abs(sk.emitter(b)->mass()) == abs(emitter(a)->mass()) &&
abs(sk.spectator(b)->mass()) == abs(spectator(a)->mass());
}
// 2012-05-01
tcPDPtr FFMqx2qgxDipoleKernel::emitter(const DipoleIndex& ind) const {
assert(flavour());
assert(abs(flavour()->id())<7);
return ind.emitterData()->id() > 0 ?
(tcPDPtr) flavour() : (tcPDPtr) flavour()->CC();
}
tcPDPtr FFMqx2qgxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FFMqx2qgxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double FFMqx2qgxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
// These are the physical variables as used in the standard
// form of the kernel (i.e. do not redefine variables or kernel)
double z = split.lastZ();
Energy pt = split.lastPt();
// Need zPrime to calculate y,
// TODO: Should just store y in the dipole splitting info everywhere anyway!!!
// The only value stored in dInfo.lastSplittingParameters() should be zPrime
//assert(split.lastSplittingParameters().size() == 1 );
double zPrime = split.lastSplittingParameters()[0];
// Construct mass squared variables
- double mui2 = sqr(split.emitterData()->mass() / split.scale());
- double muj2 = sqr(split.spectatorData()->mass() / split.scale());
+ // Note for q->qg can use the emitterMass
+ // (i.e. mass of emitter before splitting = mass of emitter after)
+ double mui2 = sqr(split.emitterMass() / split.scale());
+ double muj2 = sqr(split.spectatorMass() / split.scale());
double bar = 1. - mui2 - muj2;
// Calculate y
double y = (sqr(pt)/sqr(split.scale()) + sqr(1.-zPrime)*mui2) / (bar*zPrime*(1.-zPrime));
double vijk = sqrt( sqr(2.*muj2 + bar*(1.-y))-4.*muj2 ) / (bar*(1.-y));
double vbar = sqrt( 1.+sqr(mui2)+sqr(muj2)-2.*(mui2+muj2+mui2*muj2) ) / bar;
ret *= (!strictLargeN() ? 4./3. : 3./2.)*( 2./(1.-z*(1.-y)) - vbar/vijk*( 1.+z + mui2*2./(y*(1.-mui2-muj2)) ) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FFMqx2qgxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void FFMqx2qgxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<FFMqx2qgxDipoleKernel> FFMqx2qgxDipoleKernel::initFFMqx2qgxDipoleKernel;
// Definition of the static class description member.
void FFMqx2qgxDipoleKernel::Init() {
static ClassDocumentation<FFMqx2qgxDipoleKernel> documentation
("FFMqx2qgxDipoleKernel");
}
diff --git a/Shower/Dipole/Kernels/FFgx2ggxDipoleKernel.cc b/Shower/Dipole/Kernels/FFgx2ggxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FFgx2ggxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FFgx2ggxDipoleKernel.cc
@@ -1,107 +1,113 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFgx2ggxDipoleKernel class.
//
#include "FFgx2ggxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FFgx2ggxDipoleKernel::FFgx2ggxDipoleKernel()
- : DipoleSplittingKernel(),theSymmetryFactor(0.5){}
+ : DipoleSplittingKernel(){}
FFgx2ggxDipoleKernel::~FFgx2ggxDipoleKernel() {}
IBPtr FFgx2ggxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FFgx2ggxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FFgx2ggxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.emitterData()->id() == ParticleID::g &&
ind.spectatorData()->mass() == ZERO &&
!ind.initialStateEmitter() && !ind.initialStateSpectator();
}
bool FFgx2ggxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emitter(b)->id() == ParticleID::g &&
sk.emission(b)->id() == ParticleID::g;
}
tcPDPtr FFgx2ggxDipoleKernel::emitter(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FFgx2ggxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FFgx2ggxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double FFgx2ggxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
double z = split.lastZ();
double y = sqr(split.lastPt() / split.scale()) / (z*(1.-z));
- ret *=theSymmetryFactor*3.*(1./(1.-z*(1.-y))+1./(1.-(1.-z)*(1.-y))-2.+z*(1.-z));
+ double S1=1./(1.-z*(1.-y));
+ double S2=1./(1.-(1.-z)*(1.-y));
+ double NS=(-2 + z*(1.-z));
-
+ if( theAsymmetryOption == 0 ){
+ ret *= 3.*( S1 + 0.5 * NS);
+ }else if ( theAsymmetryOption == 1 ){
+ ret *= 3.*z*( S1 +S2 + NS );
+ }else{
+ ret *= 3.*0.5*( S1 + S2 + NS );
+ }
+
return ret > 0. ? ret : 0.;
-
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FFgx2ggxDipoleKernel::persistentOutput(PersistentOStream & os) const {
-
- os<<theSymmetryFactor;
+ os << theAsymmetryOption;
}
void FFgx2ggxDipoleKernel::persistentInput(PersistentIStream & is, int) {
- is>>theSymmetryFactor;
+ is >> theAsymmetryOption;
}
ClassDescription<FFgx2ggxDipoleKernel> FFgx2ggxDipoleKernel::initFFgx2ggxDipoleKernel;
// Definition of the static class description member.
void FFgx2ggxDipoleKernel::Init() {
static ClassDocumentation<FFgx2ggxDipoleKernel> documentation
("FFgx2ggxDipoleKernel");
- static Parameter<FFgx2ggxDipoleKernel,double> interfaceSymmetryFactor
- ("SymmetryFactor",
- "The symmetry factor for final state gluon spliitings.",
- &FFgx2ggxDipoleKernel::theSymmetryFactor, 1.0, 0.0, 0,
+ static Parameter<FFgx2ggxDipoleKernel,int> interfacetheAsymmetryOption
+ ("AsymmetryOption",
+ "The asymmetry option for final state gluon spliitings.",
+ &FFgx2ggxDipoleKernel::theAsymmetryOption, 1, 0, 0,
false, false, Interface::lowerlim);
}
-
diff --git a/Shower/Dipole/Kernels/FFgx2ggxDipoleKernel.h b/Shower/Dipole/Kernels/FFgx2ggxDipoleKernel.h
--- a/Shower/Dipole/Kernels/FFgx2ggxDipoleKernel.h
+++ b/Shower/Dipole/Kernels/FFgx2ggxDipoleKernel.h
@@ -1,187 +1,187 @@
// -*- C++ -*-
#ifndef HERWIG_FFgx2ggxDipoleKernel_H
#define HERWIG_FFgx2ggxDipoleKernel_H
//
// This is the declaration of the FFgx2ggxDipoleKernel class.
//
#include "DipoleSplittingKernel.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer
*
* \brief FFgx2ggxDipoleKernel implements the g -> gg
* splitting off a final-final dipole
*
*/
class FFgx2ggxDipoleKernel: public DipoleSplittingKernel {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
FFgx2ggxDipoleKernel();
/**
* The destructor.
*/
virtual ~FFgx2ggxDipoleKernel();
//@}
public:
/**
* Return true, if this splitting kernel
* applies to the given dipole index.
*/
virtual bool canHandle(const DipoleIndex&) const;
/**
* Return true, if this splitting kernel is
* the same for the given index a, as the given
* splitting kernel for index b.
*/
virtual bool canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const;
/**
* Return the emitter data after splitting, given
* a dipole index.
*/
virtual tcPDPtr emitter(const DipoleIndex&) const;
/**
* Return the emission data after splitting, given
* a dipole index.
*/
virtual tcPDPtr emission(const DipoleIndex&) const;
/**
* Return the spectator data after splitting, given
* a dipole index.
*/
virtual tcPDPtr spectator(const DipoleIndex&) const;
/**
* Evaluate this splitting kernel for the given
* dipole splitting.
*/
virtual double evaluate(const DipoleSplittingInfo&) 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;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<FFgx2ggxDipoleKernel> initFFgx2ggxDipoleKernel;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FFgx2ggxDipoleKernel & operator=(const FFgx2ggxDipoleKernel &);
/**
- * Symmetry factor for final state gluon splittings (should be 1/2).
- */
-
- double theSymmetryFactor;
+ * Asymmetry option for final state gluon splittings.
+ */
+
+ int theAsymmetryOption=1;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of FFgx2ggxDipoleKernel. */
template <>
struct BaseClassTrait<Herwig::FFgx2ggxDipoleKernel,1> {
/** Typedef of the first base class of FFgx2ggxDipoleKernel. */
typedef Herwig::DipoleSplittingKernel NthBase;
};
/** This template specialization informs ThePEG about the name of
* the FFgx2ggxDipoleKernel class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::FFgx2ggxDipoleKernel>
: public ClassTraitsBase<Herwig::FFgx2ggxDipoleKernel> {
/** Return a platform-independent class name */
static string className() { return "Herwig::FFgx2ggxDipoleKernel"; }
/**
* The name of a file containing the dynamic library where the class
* FFgx2ggxDipoleKernel is implemented. It may also include several, space-separated,
* libraries if the class FFgx2ggxDipoleKernel depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_FFgx2ggxDipoleKernel_H */
diff --git a/Shower/Dipole/Kernels/FIMDecaygx2ggxDipoleKernel.cc b/Shower/Dipole/Kernels/FIMDecaygx2ggxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FIMDecaygx2ggxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FIMDecaygx2ggxDipoleKernel.cc
@@ -1,150 +1,159 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FIMDecaygx2ggxDipoleKernel class.
//
#include "FIMDecaygx2ggxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FIMDecaygx2ggxDipoleKernel::FIMDecaygx2ggxDipoleKernel()
- : DipoleSplittingKernel(),theSymmetryFactor(0.5){}
+ : DipoleSplittingKernel(){}
FIMDecaygx2ggxDipoleKernel::~FIMDecaygx2ggxDipoleKernel() {}
IBPtr FIMDecaygx2ggxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FIMDecaygx2ggxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FIMDecaygx2ggxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.incomingDecaySpectator() && !ind.incomingDecayEmitter() &&
ind.emitterData()->id() == ParticleID::g &&
!(ind.spectatorData()->mass() == ZERO) &&
// Initial state here refers to the entire event
!ind.initialStateEmitter() && !ind.initialStateSpectator();
}
bool FIMDecaygx2ggxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emission(b)->id() == ParticleID::g &&
sk.emitter(b)->id() == ParticleID::g &&
abs(sk.spectator(b)->mass()) == abs(spectator(a)->mass());
}
tcPDPtr FIMDecaygx2ggxDipoleKernel::emitter(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FIMDecaygx2ggxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FIMDecaygx2ggxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double FIMDecaygx2ggxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
// These are the physical variables as used in the standard form of the kernel (i.e. do not redefine variables or kernel)
double z = split.lastZ();
Energy pt = split.lastPt();
// Need zPrime to calculate y,
// TODO: Should just store y in the dipole splitting info everywhere anyway!!!
// The only value stored in dInfo.lastSplittingParameters() should be zPrime
//assert(split.lastSplittingParameters().size() == 1 );
double zPrime = split.lastSplittingParameters()[0];
// Construct mass squared variables
- double mua2 = sqr( split.spectatorData()->mass() / split.scale() );
+ double mua2 = sqr( split.spectatorMass() / split.scale() );
// Recoil system mass
double muj2 = sqr(split.recoilMass() / split.scale());
double bar = 1. - muj2;
// Calculate y
double y = (sqr(pt)/sqr(split.scale())) / (bar*zPrime*(1.-zPrime));
if( sqr(2.*muj2+bar*(1.-y))-4.*muj2 < 0. ){
generator()->logWarning( Exception()
<< "error in FIMDecaygx2ggxDipoleKernel::evaluate -- " <<
"muj2 " << muj2 << " y " << y << Exception::warning );
return 0.0;
}
double vijk = sqrt( sqr(2.*muj2+bar*(1.-y))-4.*muj2 ) / (bar*(1.-y));
double viji = 1.;
double vbar = 1.;
double zp = 0.5*(1.+viji*vijk);
double zm = 0.5*(1.-viji*vijk);
// how to choose kappa?
double kappa = 0.;
- ret *= theSymmetryFactor * 3.*( (2.*y + 1.)/((1.+y)-z*(1.-y)) + (2.*y + 1.)/((1.+y)-(1.-z)*(1.-y)) + (1./vijk)*( z*(1.-z) - (1.-kappa)*zp*zm - 2. ) )
- +
- (!strictLargeN() ? 4./3. : 3./2.)
- * (
- y/(1.-z*(1.-y)) * ( 2.*(2.*y + 1.)/((1.+y)-z*(1.-y)) - (vbar/vijk)*(2. + theSymmetryFactor*2.*mua2/((1.-z*(1.-y))*bar)) )
- +
- y/(1.-(1.-z)*(1.-y)) * ( 2.*(2.*y + 1.)/((1.+y)-(1.-z)*(1.-y)) - (vbar/vijk)*(2. + theSymmetryFactor*2.*mua2/((1.-(1.-z)*(1.-y))*bar)) )
- );
-
+ double S1 = 0.5*3.*(2.*y + 1.)/((1.+y)-z*(1.-y)) +
+ (!strictLargeN() ? 4./3. : 3./2.)*
+ y/(1.-z*(1.-y)) * ( 2.*(2.*y + 1.)/((1.+y)-z*(1.-y))
+ - (vbar/vijk)*(2. + 2.*mua2/((1.-z*(1.-y))*bar)) );
+ double S2 = 0.5*3.*(2.*y + 1.)/((1.+y)-(1.-z)*(1.-y)) +
+ (!strictLargeN() ? 4./3. : 3./2.)*
+ y/(1.-(1.-z)*(1.-y)) * ( 2.*(2.*y + 1.)/((1.+y)-(1.-z)*(1.-y))
+ - (vbar/vijk)*(2. + 2.*mua2/((1.-(1.-z)*(1.-y))*bar)) );
+ double NS = 0.5*3.*(z*(1.-z)-(1.-kappa)*zp*zm - 2.)/vijk;
+
+
+ if( theAsymmetryOption == 0 ){
+ ret *= 2.*S1 + NS;
+ }else if ( theAsymmetryOption == 1 ){
+ ret *= 2.*z*( S1 + S2 + NS );
+ }else{
+ ret *= S1 + S2 + NS;
+ }
+
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FIMDecaygx2ggxDipoleKernel::persistentOutput(PersistentOStream & os) const {
-
- os<<theSymmetryFactor;
+ os<<theAsymmetryOption;
}
void FIMDecaygx2ggxDipoleKernel::persistentInput(PersistentIStream & is, int) {
-
- is>>theSymmetryFactor;
+ is>>theAsymmetryOption;
}
ClassDescription<FIMDecaygx2ggxDipoleKernel> FIMDecaygx2ggxDipoleKernel::initFIMDecaygx2ggxDipoleKernel;
// Definition of the static class description member.
void FIMDecaygx2ggxDipoleKernel::Init() {
static ClassDocumentation<FIMDecaygx2ggxDipoleKernel> documentation
("FIMDecaygx2ggxDipoleKernel");
- static Parameter<FIMDecaygx2ggxDipoleKernel,double> interfaceSymmetryFactor
- ("SymmetryFactor",
- "The symmetry factor for final state gluon splittings.",
- &FIMDecaygx2ggxDipoleKernel::theSymmetryFactor, 1.0, 0.0, 0,
+ static Parameter<FIMDecaygx2ggxDipoleKernel,int> interfacetheAsymmetryOption
+ ("AsymmetryOption",
+ "The asymmetry option for final state gluon spliitings.",
+ &FIMDecaygx2ggxDipoleKernel::theAsymmetryOption, 0, 0, 0,
false, false, Interface::lowerlim);
+
}
diff --git a/Shower/Dipole/Kernels/FIMDecaygx2ggxDipoleKernel.h b/Shower/Dipole/Kernels/FIMDecaygx2ggxDipoleKernel.h
--- a/Shower/Dipole/Kernels/FIMDecaygx2ggxDipoleKernel.h
+++ b/Shower/Dipole/Kernels/FIMDecaygx2ggxDipoleKernel.h
@@ -1,188 +1,186 @@
// -*- C++ -*-
#ifndef HERWIG_FIMDecaygx2ggxDipoleKernel_H
#define HERWIG_FIMDecaygx2ggxDipoleKernel_H
//
// This is the declaration of the FIMDecaygx2ggxDipoleKernel class.
//
#include "DipoleSplittingKernel.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Stephen Webster
*
* \brief FIMDecaygx2ggxDipoleKernel implements the g -> gg
* splitting off a final-initial decay dipole and includes the
* contribution from the splitting of the intial / decay particle
*
*/
class FIMDecaygx2ggxDipoleKernel: public DipoleSplittingKernel {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
FIMDecaygx2ggxDipoleKernel();
/**
* The destructor.
*/
virtual ~FIMDecaygx2ggxDipoleKernel();
//@}
public:
/**
* Return true, if this splitting kernel
* applies to the given dipole index.
*/
virtual bool canHandle(const DipoleIndex&) const;
/**
* Return true, if this splitting kernel is
* the same for the given index a, as the given
* splitting kernel for index b.
*/
virtual bool canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const;
/**
* Return the emitter data after splitting, given
* a dipole index.
*/
virtual tcPDPtr emitter(const DipoleIndex&) const;
/**
* Return the emission data after splitting, given
* a dipole index.
*/
virtual tcPDPtr emission(const DipoleIndex&) const;
/**
* Return the spectator data after splitting, given
* a dipole index.
*/
virtual tcPDPtr spectator(const DipoleIndex&) const;
/**
* Evaluate this splitting kernel for the given
* dipole splitting.
*/
virtual double evaluate(const DipoleSplittingInfo&) 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;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
- * Symmetry factor for final state gluon splittings (should be 1/2).
- */
-
- double theSymmetryFactor;
-
- /**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<FIMDecaygx2ggxDipoleKernel> initFIMDecaygx2ggxDipoleKernel;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FIMDecaygx2ggxDipoleKernel & operator=(const FIMDecaygx2ggxDipoleKernel &);
+ /**
+ * Asymmetry option for final state gluon splittings.
+ */
+ int theAsymmetryOption=0;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of FIMDecaygx2ggxDipoleKernel. */
template <>
struct BaseClassTrait<Herwig::FIMDecaygx2ggxDipoleKernel,1> {
/** Typedef of the first base class of FIMDecaygx2ggxDipoleKernel. */
typedef Herwig::DipoleSplittingKernel NthBase;
};
/** This template specialization informs ThePEG about the name of
* the FIMDecaygx2ggxDipoleKernel class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::FIMDecaygx2ggxDipoleKernel>
: public ClassTraitsBase<Herwig::FIMDecaygx2ggxDipoleKernel> {
/** Return a platform-independent class name */
static string className() { return "Herwig::FIMDecaygx2ggxDipoleKernel"; }
/**
* The name of a file containing the dynamic library where the class
* FIMDecaygx2ggxDipoleKernel is implemented. It may also include several, space-separated,
* libraries if the class FIMDecaygx2ggxDipoleKernel depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_FIMDecaygx2ggxDipoleKernel_H */
diff --git a/Shower/Dipole/Kernels/FIMDecaygx2qqxDipoleKernel.cc b/Shower/Dipole/Kernels/FIMDecaygx2qqxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FIMDecaygx2qqxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FIMDecaygx2qqxDipoleKernel.cc
@@ -1,143 +1,142 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FIMDecaygx2qqxDipoleKernel class.
//
#include "FIMDecaygx2qqxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FIMDecaygx2qqxDipoleKernel::FIMDecaygx2qqxDipoleKernel()
: DipoleSplittingKernel() {}
FIMDecaygx2qqxDipoleKernel::~FIMDecaygx2qqxDipoleKernel() {}
IBPtr FIMDecaygx2qqxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FIMDecaygx2qqxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FIMDecaygx2qqxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.incomingDecaySpectator() && !ind.incomingDecayEmitter() &&
ind.emitterData()->id() == ParticleID::g &&
!(ind.spectatorData()->mass() == ZERO) &&
// Initial state here refers to the entire event
!ind.initialStateEmitter() && !ind.initialStateSpectator();
}
bool FIMDecaygx2qqxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emitter(b)->id() + sk.emission(b)->id() == 0 &&
abs(sk.emitter(b)->id()) < 6 &&
emitter(a)->id() == sk.emitter(b)->id() &&
abs(sk.spectator(b)->mass()) == abs(spectator(a)->mass());
}
tcPDPtr FIMDecaygx2qqxDipoleKernel::emitter(const DipoleIndex&) const {
assert(flavour());
assert(abs(flavour()->id()) < 6);
return flavour();
}
tcPDPtr FIMDecaygx2qqxDipoleKernel::emission(const DipoleIndex&) const {
assert(flavour());
assert(abs(flavour()->id()) < 6);
return flavour()->CC();
}
tcPDPtr FIMDecaygx2qqxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double FIMDecaygx2qqxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
// These are the physical variables as used in the standard form of the kernel (i.e. do not redefine variables or kernel)
double z = split.lastZ();
Energy pt = split.lastPt();
// Need zPrime to calculate y,
// TODO: Should just store y in the dipole splitting info everywhere anyway!!!
// The only value stored in dInfo.lastSplittingParameters() should be zPrime
//assert(split.lastSplittingParameters().size() == 1 );
double zPrime = split.lastSplittingParameters()[0];
// Construct mass squared variables
- double mua2 = sqr( split.spectatorData()->mass() / split.scale() );
double mui2 = sqr(split.emitterData()->mass() / split.scale());
double mu2 = mui2;
+ //double mua2 = sqr( split.spectatorMass() / split.scale() );
// Recoil system mass
double muj2 = sqr(split.recoilMass() / split.scale());
double bar = 1. - mui2 - mu2 - muj2;
// Calculate y
double y = (sqr(pt)/sqr(split.scale()) + sqr(1.-zPrime)*mui2 + sqr(zPrime)*mu2) / (bar*zPrime*(1.-zPrime));
if( sqr(2.*muj2+bar*(1.-y))-4.*muj2 < 0. ){
generator()->logWarning( Exception()
<< "error in FIMDecaygx2qqxDipoleKernel::evaluate -- " <<
"muj2 " << muj2 << " mui2 " << mui2 << " y " << y << Exception::warning );
return 0.0;
}
double vijk = sqrt( sqr(2.*muj2+bar*(1.-y))-4.*muj2 ) / (bar*(1.-y));
double viji = sqrt( sqr(bar*y)-4.*sqr(mui2) ) / (bar*y+2.*mui2);
- double vbar = sqrt( 1.+sqr(mui2)+sqr(muj2)-2.*(mui2+muj2+mui2*muj2) ) / bar;
+ //double vbar = sqrt( 1.+sqr(mui2)+sqr(muj2)-2.*(mui2+muj2+mui2*muj2) ) / bar;
double zp = 0.5*(1.+viji*vijk);
double zm = 0.5*(1.-viji*vijk);
// how to choose kappa?
double kappa = 0.;
- ret *= 0.25 / vijk * ( 1. - 2.*( z*(1.-z) - (1.-kappa)*zp*zm - kappa*mui2/(2*mui2+bar*y) ) )
- + (!strictLargeN() ? 4./3. : 3./2.) * y/(1.-z*(1.-y)) * (-1.*(vbar/vijk)*2.*mua2/((1.-z*(1.-y))*bar) );
+ ret *= 0.25 / vijk * ( 1. - 2.*( z*(1.-z) - (1.-kappa)*zp*zm - kappa*mui2/(2*mui2+bar*y) ) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FIMDecaygx2qqxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void FIMDecaygx2qqxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<FIMDecaygx2qqxDipoleKernel> FIMDecaygx2qqxDipoleKernel::initFIMDecaygx2qqxDipoleKernel;
// Definition of the static class description member.
void FIMDecaygx2qqxDipoleKernel::Init() {
static ClassDocumentation<FIMDecaygx2qqxDipoleKernel> documentation
("FIMDecaygx2qqxDipoleKernel");
}
diff --git a/Shower/Dipole/Kernels/FIMDecayqx2qgxDipoleKernel.cc b/Shower/Dipole/Kernels/FIMDecayqx2qgxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FIMDecayqx2qgxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FIMDecayqx2qgxDipoleKernel.cc
@@ -1,136 +1,144 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FIMDecayqx2qgxDipoleKernel class.
//
#include "FIMDecayqx2qgxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FIMDecayqx2qgxDipoleKernel::FIMDecayqx2qgxDipoleKernel() : DipoleSplittingKernel() {}
FIMDecayqx2qgxDipoleKernel::~FIMDecayqx2qgxDipoleKernel() {}
IBPtr FIMDecayqx2qgxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FIMDecayqx2qgxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FIMDecayqx2qgxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.incomingDecaySpectator() && !ind.incomingDecayEmitter() &&
abs(ind.emitterData()->id()) < 7 &&
// This line matches to the kernel declared in a .in file for the given emitter flavour
abs(ind.emitterData()->id()) == abs(flavour()->id()) &&
!(ind.spectatorData()->mass() == ZERO) &&
// Initial state here refers to the entire event
!ind.initialStateEmitter() && !ind.initialStateSpectator();
}
bool FIMDecayqx2qgxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emission(b)->id() == ParticleID::g &&
abs(sk.emitter(b)->id()) < 7 &&
abs(sk.emitter(b)->mass()) == abs(emitter(a)->mass()) &&
abs(sk.spectator(b)->mass()) == abs(spectator(a)->mass());
}
tcPDPtr FIMDecayqx2qgxDipoleKernel::emitter(const DipoleIndex& ind) const {
assert(flavour());
assert(abs(flavour()->id()) < 7);
return ind.emitterData()->id() > 0 ?
(tcPDPtr) flavour() : (tcPDPtr) flavour()->CC();
}
tcPDPtr FIMDecayqx2qgxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FIMDecayqx2qgxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double FIMDecayqx2qgxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
// These are the physical variables as used in the standard form of the kernel (i.e. do not redefine variables or kernel)
double z = split.lastZ();
Energy pt = split.lastPt();
// Need zPrime to calculate y,
// TODO: Should just store y in the dipole splitting info everywhere anyway!!!
// The only value stored in dInfo.lastSplittingParameters() should be zPrime
//assert(split.lastSplittingParameters().size() == 1 );
double zPrime = split.lastSplittingParameters()[0];
// Construct mass squared variables
- double mui2 = sqr(split.emitterData()->mass() / split.scale());
+ // Note for q->qg can use the emitterMass
+ // (i.e. mass of emitter before splitting = mass of emitter after)
+ double mui2 = sqr(split.emitterMass() / split.scale());
// Recoil system mass
double muj2 = sqr(split.recoilMass() / split.scale());
- double mua2 = sqr( split.spectatorData()->mass() / split.scale() );
+ // This should be equal to one
+ double mua2 = sqr( split.spectatorMass() / split.scale() );
double bar = 1. - mui2 - muj2;
// Calculate y
double y = (sqr(pt)/sqr(split.scale()) + sqr(1.-zPrime)*mui2) / (bar*zPrime*(1.-zPrime));
if( sqr(2.*muj2+bar*(1.-y))-4.*muj2 < 0. ){
generator()->logWarning( Exception()
<< "error in FIMDecayqx2qgxDipoleKernel::evaluate -- " <<
"muj2 " << muj2 << " mui2 " << mui2 << " y " << y << Exception::warning );
return 0.0;
}
double vijk = sqrt( sqr(2.*muj2 + bar*(1.-y))-4.*muj2 ) / (bar*(1.-y));
double vbar = sqrt( 1.+sqr(mui2)+sqr(muj2)-2.*(mui2+muj2+mui2*muj2) ) / bar;
- ret *= (!strictLargeN() ? 4./3. : 3./2.) * ( ( 2.*(2.*mui2/bar + 2.*y + 1.)/((1.+y)-z*(1.-y)) - (vbar/vijk)*((1.+z) + 2.*mui2/(y*bar)) ) + y/(1.-z*(1.-y)) * ( 2.*(2.*mui2/bar + 2.*y + 1.)/((1.+y)-z*(1.-y)) - (vbar/vijk)*(2. + 2.*mua2/((1.-z*(1.-y))*bar)) ) );
+ ret *=
+ (!strictLargeN() ? 4./3. : 3./2.)
+ * ( ( 2.*(2.*mui2/bar + 2.*y + 1.)/((1.+y)-z*(1.-y))
+ - (vbar/vijk)*((1.+z) + 2.*mui2/(y*bar)) )
+ + y/(1.-z*(1.-y)) * ( 2.*(2.*mui2/bar + 2.*y + 1.)/((1.+y)-z*(1.-y))
+ - (vbar/vijk)*(2. + 2.*mua2/((1.-z*(1.-y))*bar)) ) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FIMDecayqx2qgxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void FIMDecayqx2qgxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<FIMDecayqx2qgxDipoleKernel> FIMDecayqx2qgxDipoleKernel::initFIMDecayqx2qgxDipoleKernel;
// Definition of the static class description member.
void FIMDecayqx2qgxDipoleKernel::Init() {
static ClassDocumentation<FIMDecayqx2qgxDipoleKernel> documentation
("FIMDecayqx2qgxDipoleKernel");
}
diff --git a/Shower/Dipole/Kernels/FIMqx2qgxDipoleKernel.cc b/Shower/Dipole/Kernels/FIMqx2qgxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FIMqx2qgxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FIMqx2qgxDipoleKernel.cc
@@ -1,113 +1,113 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FIMqx2qgxDipoleKernel class.
//
#include "FIMqx2qgxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FIMqx2qgxDipoleKernel::FIMqx2qgxDipoleKernel()
: DipoleSplittingKernel() {}
FIMqx2qgxDipoleKernel::~FIMqx2qgxDipoleKernel() {}
IBPtr FIMqx2qgxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FIMqx2qgxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FIMqx2qgxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
abs(ind.emitterData()->id()) < 7 &&
abs(ind.emitterData()->id())==abs(flavour()->id()) &&
ind.emitterData()->mass() != ZERO &&
ind.spectatorData()->mass() == ZERO &&
!ind.initialStateEmitter() && ind.initialStateSpectator();
}
bool FIMqx2qgxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emission(b)->id() == ParticleID::g &&
abs(sk.emitter(b)->id()) < 7 &&
sk.emitter(b)->mass() == emitter(a)->mass() &&
a.spectatorPDF() == b.spectatorPDF();
}
tcPDPtr FIMqx2qgxDipoleKernel::emitter(const DipoleIndex& ind) const {
assert(flavour());
assert(abs(flavour()->id())<7 && flavour()->mass() != ZERO);
return ind.emitterData()->id() > 0 ?
(tcPDPtr) flavour() : (tcPDPtr) flavour()->CC();
}
tcPDPtr FIMqx2qgxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FIMqx2qgxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
// TODO
// split.scale() should be sqrt(sbar) = sqrt( Mi2 - Q2 ) !!!
double FIMqx2qgxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
// Mi=mi=mQ, m=0, Mj=mj=0
- Energy2 mQ2 = sqr(split.emitterData()->mass());
+ Energy2 mQ2 = sqr(split.emitterMass());
double z = split.lastZ();
double x = 1. / ( 1. +
( sqr(split.lastPt()) + sqr(1.-z)*mQ2 ) /
( z*(1.-z) * sqr(split.scale()) ) );
// Simon has extra terms
ret *= (!strictLargeN() ? 4./3. : 3./2.) *
( 2./(1.-z+(1.-x)) -(1.+z) - mQ2/sqr(split.scale()) * 2.*x/(1.-x) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FIMqx2qgxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void FIMqx2qgxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<FIMqx2qgxDipoleKernel> FIMqx2qgxDipoleKernel::initFIMqx2qgxDipoleKernel;
// Definition of the static class description member.
void FIMqx2qgxDipoleKernel::Init() {
static ClassDocumentation<FIMqx2qgxDipoleKernel> documentation
("FIMqx2qgxDipoleKernel");
}
diff --git a/Shower/Dipole/Kernels/FIgx2ggxDipoleKernel.cc b/Shower/Dipole/Kernels/FIgx2ggxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/FIgx2ggxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/FIgx2ggxDipoleKernel.cc
@@ -1,106 +1,116 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FIgx2ggxDipoleKernel class.
//
#include "FIgx2ggxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
FIgx2ggxDipoleKernel::FIgx2ggxDipoleKernel()
- : DipoleSplittingKernel(),theSymmetryFactor(0.5) {}
+ : DipoleSplittingKernel() {}
FIgx2ggxDipoleKernel::~FIgx2ggxDipoleKernel() {}
IBPtr FIgx2ggxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr FIgx2ggxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool FIgx2ggxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.emitterData()->id() == ParticleID::g &&
ind.spectatorData()->mass() == ZERO &&
!ind.initialStateEmitter() && ind.initialStateSpectator();
}
bool FIgx2ggxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emitter(b)->id() == ParticleID::g &&
sk.emission(b)->id() == ParticleID::g &&
a.spectatorPDF() == b.spectatorPDF();
}
tcPDPtr FIgx2ggxDipoleKernel::emitter(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FIgx2ggxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr FIgx2ggxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double FIgx2ggxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
double z = split.lastZ();
double x = 1. / ( 1. + sqr(split.lastPt()/split.scale()) / (z*(1.-z)) );
- ret *=theSymmetryFactor* 3. * ( 1./(1.-z+(1.-x)) + 1./(z+(1.-x)) - 2.+z*(1.-z) + (1.-x)*(1.+x*z*(1.-z)) );
-
+ double S1=1./(1.-z*(1.-x));
+ double S2=1./(1.-(1.-z)*(1.-x));
+ double NS=(-2 + z*(1.-z)+(1.-x)*(1.+x*z*(1.-z)));
+
+ if( theAsymmetryOption == 0 ){
+ ret *= 3.*( S1 + 0.5 * NS);
+ }else if ( theAsymmetryOption == 1 ){
+ ret *= 3.*z*( S1 +S2 + NS );
+ }else{
+ ret *= 3.*0.5*( S1 + S2 + NS );
+ }
+
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FIgx2ggxDipoleKernel::persistentOutput(PersistentOStream & os) const {
- os<<theSymmetryFactor;
+ os << theAsymmetryOption;
}
void FIgx2ggxDipoleKernel::persistentInput(PersistentIStream & is, int) {
- is>>theSymmetryFactor;
+ is >> theAsymmetryOption;
}
ClassDescription<FIgx2ggxDipoleKernel> FIgx2ggxDipoleKernel::initFIgx2ggxDipoleKernel;
// Definition of the static class description member.
void FIgx2ggxDipoleKernel::Init() {
static ClassDocumentation<FIgx2ggxDipoleKernel> documentation
("FIgx2ggxDipoleKernel");
- static Parameter<FIgx2ggxDipoleKernel,double> interfaceSymmetryFactor
- ("SymmetryFactor",
- "The symmetry factor for final state gluon spliitings.",
- &FIgx2ggxDipoleKernel::theSymmetryFactor, 1.0, 0.0, 0,
- false, false, Interface::lowerlim);
+ static Parameter<FIgx2ggxDipoleKernel,int> interfacetheAsymmetryOption
+ ("AsymmetryOption",
+ "The asymmetry option for final state gluon spliitings.",
+ &FIgx2ggxDipoleKernel::theAsymmetryOption, 1, 0, 0,
+ false, false, Interface::lowerlim);
}
diff --git a/Shower/Dipole/Kernels/FIgx2ggxDipoleKernel.h b/Shower/Dipole/Kernels/FIgx2ggxDipoleKernel.h
--- a/Shower/Dipole/Kernels/FIgx2ggxDipoleKernel.h
+++ b/Shower/Dipole/Kernels/FIgx2ggxDipoleKernel.h
@@ -1,186 +1,186 @@
// -*- C++ -*-
#ifndef HERWIG_FIgx2ggxDipoleKernel_H
#define HERWIG_FIgx2ggxDipoleKernel_H
//
// This is the declaration of the FIgx2ggxDipoleKernel class.
//
#include "DipoleSplittingKernel.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer
*
* \brief FIgx2ggxDipoleKernel implements the g -> gg
* splitting off a final-initial dipole
*
*/
class FIgx2ggxDipoleKernel: public DipoleSplittingKernel {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
FIgx2ggxDipoleKernel();
/**
* The destructor.
*/
virtual ~FIgx2ggxDipoleKernel();
//@}
public:
/**
* Return true, if this splitting kernel
* applies to the given dipole index.
*/
virtual bool canHandle(const DipoleIndex&) const;
/**
* Return true, if this splitting kernel is
* the same for the given index a, as the given
* splitting kernel for index b.
*/
virtual bool canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const;
/**
* Return the emitter data after splitting, given
* a dipole index.
*/
virtual tcPDPtr emitter(const DipoleIndex&) const;
/**
* Return the emission data after splitting, given
* a dipole index.
*/
virtual tcPDPtr emission(const DipoleIndex&) const;
/**
* Return the spectator data after splitting, given
* a dipole index.
*/
virtual tcPDPtr spectator(const DipoleIndex&) const;
/**
* Evaluate this splitting kernel for the given
* dipole splitting.
*/
virtual double evaluate(const DipoleSplittingInfo&) 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;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
- * Symmetry factor for final state gluon splittings (should be 1/2).
- */
-
- double theSymmetryFactor;
+ * Asymmetry option for final state gluon splittings.
+ */
+
+ int theAsymmetryOption=1;
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<FIgx2ggxDipoleKernel> initFIgx2ggxDipoleKernel;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FIgx2ggxDipoleKernel & operator=(const FIgx2ggxDipoleKernel &);
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of FIgx2ggxDipoleKernel. */
template <>
struct BaseClassTrait<Herwig::FIgx2ggxDipoleKernel,1> {
/** Typedef of the first base class of FIgx2ggxDipoleKernel. */
typedef Herwig::DipoleSplittingKernel NthBase;
};
/** This template specialization informs ThePEG about the name of
* the FIgx2ggxDipoleKernel class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::FIgx2ggxDipoleKernel>
: public ClassTraitsBase<Herwig::FIgx2ggxDipoleKernel> {
/** Return a platform-independent class name */
static string className() { return "Herwig::FIgx2ggxDipoleKernel"; }
/**
* The name of a file containing the dynamic library where the class
* FIgx2ggxDipoleKernel is implemented. It may also include several, space-separated,
* libraries if the class FIgx2ggxDipoleKernel depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_FIgx2ggxDipoleKernel_H */
diff --git a/Shower/Dipole/Kernels/IFMgx2ggxDipoleKernel.cc b/Shower/Dipole/Kernels/IFMgx2ggxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/IFMgx2ggxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/IFMgx2ggxDipoleKernel.cc
@@ -1,109 +1,109 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the IFMgx2ggxDipoleKernel class.
//
#include "IFMgx2ggxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
IFMgx2ggxDipoleKernel::IFMgx2ggxDipoleKernel()
: DipoleSplittingKernel() {}
IFMgx2ggxDipoleKernel::~IFMgx2ggxDipoleKernel() {}
IBPtr IFMgx2ggxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr IFMgx2ggxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool IFMgx2ggxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.emitterData()->id() == ParticleID::g &&
ind.spectatorData()->mass() != ZERO &&
ind.initialStateEmitter() && !ind.initialStateSpectator();
}
bool IFMgx2ggxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
sk.emitter(b)->id() == ParticleID::g &&
sk.emission(b)->id() == ParticleID::g &&
a.emitterPDF() == b.emitterPDF() &&
sk.spectator(b)->mass() == spectator(a)->mass();
}
tcPDPtr IFMgx2ggxDipoleKernel::emitter(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr IFMgx2ggxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr IFMgx2ggxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double IFMgx2ggxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
double z = split.lastZ();
Energy pt = split.lastPt();
double ratio = sqr(pt/split.scale());
- double muk2 = sqr(split.spectatorData()->mass()/split.scale());
+ double muk2 = sqr(split.spectatorMass()/split.scale());
// Calculate x and u
double rho = 1. - 4.*ratio*(1.-muk2)*z*(1.-z)/sqr(1.-z+ratio);
double x = 0.5*((1.-z+ratio)/(ratio*(1.-muk2))) * (1. - sqrt(rho));
double u = x*ratio / (1.-z);
// NOTE - The definition of muk used in the kinematics differs from that in CS
double muk2CS = x*muk2;
ret *= 3. * ( 1./(1.-x+u) - 1. + x*(1.-x) + (1.-x)/x - muk2CS*u/(x*(1.-u)) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void IFMgx2ggxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void IFMgx2ggxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<IFMgx2ggxDipoleKernel> IFMgx2ggxDipoleKernel::initIFMgx2ggxDipoleKernel;
// Definition of the static class description member.
void IFMgx2ggxDipoleKernel::Init() {
static ClassDocumentation<IFMgx2ggxDipoleKernel> documentation
("IFMgx2ggxDipoleKernelv");
}
diff --git a/Shower/Dipole/Kernels/IFMgx2qqxDipoleKernel.cc b/Shower/Dipole/Kernels/IFMgx2qqxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/IFMgx2qqxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/IFMgx2qqxDipoleKernel.cc
@@ -1,115 +1,115 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the IFMgx2qqxDipoleKernel class.
//
#include "IFMgx2qqxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
IFMgx2qqxDipoleKernel::IFMgx2qqxDipoleKernel()
: DipoleSplittingKernel() {}
IFMgx2qqxDipoleKernel::~IFMgx2qqxDipoleKernel() {}
IBPtr IFMgx2qqxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr IFMgx2qqxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool IFMgx2qqxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
ind.emitterData()->id() == ParticleID::g &&
ind.spectatorData()->mass() != ZERO &&
flavour()->mass() == ZERO &&
ind.initialStateEmitter() && !ind.initialStateSpectator();
}
bool IFMgx2qqxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
flavour() == sk.flavour() &&
abs(flavour()->id()) < 6 &&
flavour()->mass() == ZERO &&
spectator(a)->mass() == sk.spectator(b)->mass() &&
a.emitterPDF() == b.emitterPDF();
}
tcPDPtr IFMgx2qqxDipoleKernel::emitter(const DipoleIndex&) const {
assert(flavour());
assert(abs(flavour()->id()) < 6 && flavour()->mass() == ZERO);
return flavour();
}
tcPDPtr IFMgx2qqxDipoleKernel::emission(const DipoleIndex&) const {
assert(flavour());
assert(abs(flavour()->id()) < 6 && flavour()->mass() == ZERO);
return flavour();
}
tcPDPtr IFMgx2qqxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double IFMgx2qqxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
double z = split.lastZ();
Energy pt = split.lastPt();
double ratio = sqr(pt/split.scale());
- double muk2 = sqr(split.spectatorData()->mass()/split.scale());
+ double muk2 = sqr(split.spectatorMass()/split.scale());
// Calculate x and u
double rho = 1. - 4.*ratio*(1.-muk2)*z*(1.-z)/sqr(1.-z+ratio);
double x = 0.5*((1.-z+ratio)/(ratio*(1.-muk2))) * (1. - sqrt(rho));
double u = x*ratio / (1.-z);
// NOTE - The definition of muk used in the kinematics differs from that in CS
double muk2CS = x*muk2;
ret *= 0.5 * (!strictLargeN() ? 4./3. : 3./2.) *
( x + 2.*(1.-x)/x - 2.*muk2CS/x*u/(1.-u) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void IFMgx2qqxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void IFMgx2qqxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<IFMgx2qqxDipoleKernel> IFMgx2qqxDipoleKernel::initIFMgx2qqxDipoleKernel;
// Definition of the static class description member.
void IFMgx2qqxDipoleKernel::Init() {
static ClassDocumentation<IFMgx2qqxDipoleKernel> documentation
("IFMgx2qqxDipoleKernel");
}
diff --git a/Shower/Dipole/Kernels/IFMqx2gqxDipoleKernel.cc b/Shower/Dipole/Kernels/IFMqx2gqxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/IFMqx2gqxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/IFMqx2gqxDipoleKernel.cc
@@ -1,107 +1,107 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the IFMqx2gqxDipoleKernel class.
//
#include "IFMqx2gqxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
IFMqx2gqxDipoleKernel::IFMqx2gqxDipoleKernel()
: DipoleSplittingKernel() {}
IFMqx2gqxDipoleKernel::~IFMqx2gqxDipoleKernel() {}
IBPtr IFMqx2gqxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr IFMqx2gqxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool IFMqx2gqxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
abs(ind.emitterData()->id()) < 6 &&
ind.emitterData()->mass() == ZERO &&
ind.spectatorData()->mass() != ZERO &&
ind.initialStateEmitter() && !ind.initialStateSpectator();
}
bool IFMqx2gqxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
a.emitterData() == b.emitterData() &&
emitter(a) == sk.emitter(b) &&
spectator(a)->mass() == sk.spectator(b)->mass() &&
a.emitterPDF() == b.emitterPDF();
}
tcPDPtr IFMqx2gqxDipoleKernel::emitter(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr IFMqx2gqxDipoleKernel::emission(const DipoleIndex& ind) const {
return ind.emitterData()->CC();
}
tcPDPtr IFMqx2gqxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double IFMqx2gqxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
double z = split.lastZ();
Energy pt = split.lastPt();
double ratio = sqr(pt/split.scale());
- double muk2 = sqr(split.spectatorData()->mass()/split.scale());
+ double muk2 = sqr(split.spectatorMass()/split.scale());
// Calculate x
double rho = 1. - 4.*ratio*(1.-muk2)*z*(1.-z)/sqr(1.-z+ratio);
double x = 0.5*((1.-z+ratio)/(ratio*(1.-muk2))) * (1. - sqrt(rho));
ret *= .5 * ( 1.-2.*x*(1.-x) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void IFMqx2gqxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void IFMqx2gqxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<IFMqx2gqxDipoleKernel> IFMqx2gqxDipoleKernel::initIFMqx2gqxDipoleKernel;
// Definition of the static class description member.
void IFMqx2gqxDipoleKernel::Init() {
static ClassDocumentation<IFMqx2gqxDipoleKernel> documentation
("IFMqx2gqxDipoleKernel");
}
diff --git a/Shower/Dipole/Kernels/IFMqx2qgxDipoleKernel.cc b/Shower/Dipole/Kernels/IFMqx2qgxDipoleKernel.cc
--- a/Shower/Dipole/Kernels/IFMqx2qgxDipoleKernel.cc
+++ b/Shower/Dipole/Kernels/IFMqx2qgxDipoleKernel.cc
@@ -1,109 +1,109 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the IFMqx2qgxDipoleKernel class.
//
#include "IFMqx2qgxDipoleKernel.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
using namespace Herwig;
IFMqx2qgxDipoleKernel::IFMqx2qgxDipoleKernel()
: DipoleSplittingKernel() {}
IFMqx2qgxDipoleKernel::~IFMqx2qgxDipoleKernel() {}
IBPtr IFMqx2qgxDipoleKernel::clone() const {
return new_ptr(*this);
}
IBPtr IFMqx2qgxDipoleKernel::fullclone() const {
return new_ptr(*this);
}
bool IFMqx2qgxDipoleKernel::canHandle(const DipoleIndex& ind) const {
return
useThisKernel() &&
abs(ind.emitterData()->id()) < 6 &&
ind.emitterData()->mass() == ZERO &&
ind.spectatorData()->mass() != ZERO &&
ind.initialStateEmitter() && !ind.initialStateSpectator();
}
bool IFMqx2qgxDipoleKernel::canHandleEquivalent(const DipoleIndex& a,
const DipoleSplittingKernel& sk,
const DipoleIndex& b) const {
assert(canHandle(a));
if ( !canHandle(b) )
return false;
return
emitter(a) == sk.emitter(b) &&
emission(a) == sk.emission(b) &&
spectator(a)->mass() == sk.spectator(b)->mass() &&
a.emitterPDF() == b.emitterPDF();
}
tcPDPtr IFMqx2qgxDipoleKernel::emitter(const DipoleIndex& ind) const {
return ind.emitterData();
}
tcPDPtr IFMqx2qgxDipoleKernel::emission(const DipoleIndex&) const {
return getParticleData(ParticleID::g);
}
tcPDPtr IFMqx2qgxDipoleKernel::spectator(const DipoleIndex& ind) const {
return ind.spectatorData();
}
double IFMqx2qgxDipoleKernel::evaluate(const DipoleSplittingInfo& split) const {
double ret = alphaPDF(split);
double z = split.lastZ();
Energy pt = split.lastPt();
double ratio = sqr(pt/split.scale());
- double muk2 = sqr(split.spectatorData()->mass()/split.scale());
+ double muk2 = sqr(split.spectatorMass()/split.scale());
// Calculate x and u
double rho = 1. - 4.*ratio*(1.-muk2)*z*(1.-z)/sqr(1.-z+ratio);
double x = 0.5*((1.-z+ratio)/(ratio*(1.-muk2))) * (1. - sqrt(rho));
double u = x*ratio / (1.-z);
// 19/01/2017 - SW: Removed finite term as its effect on
// the ratio of -ve/+ve kernels is small
ret *= (!strictLargeN() ? 4./3. : 3./2.) * ( 2./(1.-x+u) - (1.+x) );
return ret > 0. ? ret : 0.;
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void IFMqx2qgxDipoleKernel::persistentOutput(PersistentOStream & ) const {
}
void IFMqx2qgxDipoleKernel::persistentInput(PersistentIStream & , int) {
}
ClassDescription<IFMqx2qgxDipoleKernel> IFMqx2qgxDipoleKernel::initIFMqx2qgxDipoleKernel;
// Definition of the static class description member.
void IFMqx2qgxDipoleKernel::Init() {
static ClassDocumentation<IFMqx2qgxDipoleKernel> documentation
("IFMqx2qgxDipoleKernel");
}
diff --git a/Shower/Dipole/Kinematics/DipoleSplittingKinematics.cc b/Shower/Dipole/Kinematics/DipoleSplittingKinematics.cc
--- a/Shower/Dipole/Kinematics/DipoleSplittingKinematics.cc
+++ b/Shower/Dipole/Kinematics/DipoleSplittingKinematics.cc
@@ -1,311 +1,327 @@
// -*- C++ -*-
//
// DipoleSplittingKinematics.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.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the DipoleSplittingKinematics class.
//
#include "DipoleSplittingKinematics.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/RandomHelpers.h"
#include <limits>
using namespace Herwig;
DipoleSplittingKinematics::DipoleSplittingKinematics()
: HandlerBase(), theIRCutoff(1.0*GeV),
theXMin(1.e-5), theJacobian(0.0),
theLastPt(0.0*GeV), theLastZ(0.0), theLastPhi(0.0),
theLastEmitterZ(1.0), theLastSpectatorZ(1.0),
- theLastSplittingParameters(),theOpenZBoundaries(0) {}
+ theLastSplittingParameters(),theOpenZBoundaries(1) {}
DipoleSplittingKinematics::~DipoleSplittingKinematics() {}
void DipoleSplittingKinematics::persistentOutput(PersistentOStream & os) const {
os << ounit(theIRCutoff,GeV) << theXMin << theMCCheck<<theOpenZBoundaries;
}
void DipoleSplittingKinematics::persistentInput(PersistentIStream & is, int) {
is >> iunit(theIRCutoff,GeV) >> theXMin >> theMCCheck>>theOpenZBoundaries;
}
void DipoleSplittingKinematics::prepareSplitting(DipoleSplittingInfo& dInfo) {
dInfo.splittingKinematics(this);
if ( lastPt() > IRCutoff() )
dInfo.lastPt(lastPt());
else {
dInfo.lastPt(0.0*GeV);
dInfo.didStopEvolving();
}
dInfo.lastZ(lastZ());
dInfo.lastPhi(lastPhi());
dInfo.lastEmitterZ(lastEmitterZ());
dInfo.lastSpectatorZ(lastSpectatorZ());
dInfo.splittingParameters().resize(lastSplittingParameters().size());
copy(lastSplittingParameters().begin(),lastSplittingParameters().end(),
dInfo.splittingParameters().begin());
}
Energy DipoleSplittingKinematics::ptMax(Energy dScale,
double emX, double specX,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const {
return ptMax(dScale, emX, specX, dInfo.index(), split);
}
+Energy DipoleSplittingKinematics::ptMax(Energy dScale,
+ double emX, double specX,
+ const DipoleIndex& dIndex,
+ const DipoleSplittingKernel& split,
+ tPPtr, tPPtr) const {
+ return ptMax(dScale, emX, specX, dIndex, split);
+}
+
Energy DipoleSplittingKinematics::QMax(Energy dScale,
double emX, double specX,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const {
return QMax(dScale, emX, specX, dInfo.index(), split);
}
+Energy DipoleSplittingKinematics::QMax(Energy dScale,
+ double emX, double specX,
+ const DipoleIndex& dIndex,
+ const DipoleSplittingKernel& split,
+ tPPtr, tPPtr) const {
+ return QMax(dScale, emX, specX, dIndex, split);
+}
+
Energy DipoleSplittingKinematics::generatePt(double r, Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel& split,
double& weight) const {
Energy maxPt = ptMax(dScale,emX,specX,dIndex,split);
if ( maxPt <= IRCutoff() ) {
weight = 0.0;
return ZERO;
}
weight *= log(sqr(maxPt/IRCutoff()));
return IRCutoff()*pow(maxPt/IRCutoff(),r);
}
double DipoleSplittingKinematics::ptToRandom(Energy pt, Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel& split) const {
Energy maxPt = ptMax(dScale,emX,specX,dIndex,split);
assert(pt >= IRCutoff() && pt <= maxPt);
return log(pt/IRCutoff())/log(maxPt/IRCutoff());
}
double DipoleSplittingKinematics::generateZ(double r, Energy pt, int sampling,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split,
double& weight) const {
pair<double,double> zLims = zBoundaries(pt,dInfo,split);
if(zLims.first==zLims.second){
weight = 0.0;
return 0.0;
}
using namespace RandomHelpers;
if ( sampling == FlatZ ) {
pair<double,double> kw = generate(flat(zLims.first,zLims.second),r);
if ( kw.second != 0. ) {
weight *= kw.second;
return kw.first;
}
else {
assert( kw.first < zLims.first || kw.first > zLims.second );
weight *= kw.second;
return -1.;
}
}
if ( sampling == OneOverZ ) {
pair<double,double> kw = generate(inverse(0.0,zLims.first,zLims.second),r);
if ( kw.second != 0. ) {
weight *= kw.second;
return kw.first;
}
else {
assert( kw.first < zLims.first || kw.first > zLims.second );
weight *= kw.second;
return -1.;
}
}
if ( sampling == OneOverOneMinusZ ) {
pair<double,double> kw = generate(inverse(1.0,zLims.first,zLims.second),r);
if ( kw.second != 0. ) {
weight *= kw.second;
return kw.first;
}
else {
assert( kw.first < zLims.first || kw.first > zLims.second );
weight *= kw.second;
return -1.;
}
}
if ( sampling == OneOverZOneMinusZ ) {
pair<double,double> kw = generate(inverse(0.0,zLims.first,zLims.second) +
inverse(1.0,zLims.first,zLims.second),r);
if ( kw.second != 0. ) {
weight *= kw.second;
return kw.first;
}
else {
assert( kw.first < zLims.first || kw.first > zLims.second );
weight *= kw.second;
return -1.;
}
}
weight = 0.0;
return 0.0;
}
Lorentz5Momentum DipoleSplittingKinematics::getKt(const Lorentz5Momentum& p1,
const Lorentz5Momentum& p2,
Energy pt,
double phi,
bool spacelike) const {
Lorentz5Momentum P;
if ( !spacelike )
P = p1 + p2;
else
P = p1 - p2;
Energy2 Q2 = abs(P.m2());
Lorentz5Momentum Q =
!spacelike ?
Lorentz5Momentum(ZERO,ZERO,ZERO,sqrt(Q2),sqrt(Q2)) :
Lorentz5Momentum(ZERO,ZERO,sqrt(Q2),ZERO,-sqrt(Q2));
if ( spacelike && Q.z() < P.z() )
Q.setZ(-Q.z());
bool boost =
abs((P-Q).vect().mag2()/GeV2) > 1e-10 ||
abs((P-Q).t()/GeV) > 1e-5;
boost &= (P*Q-Q.mass2())/GeV2 > 1e-8;
Lorentz5Momentum inFrame1;
if ( boost )
inFrame1 = p1 + ((P*p1-Q*p1)/(P*Q-Q.mass2()))*(P-Q);
else
inFrame1 = p1;
Energy ptx = inFrame1.x();
Energy pty = inFrame1.y();
Energy q = 2.*inFrame1.z();
Energy Qp = sqrt(4.*(sqr(ptx)+sqr(pty))+sqr(q));
Energy Qy = sqrt(4.*sqr(pty)+sqr(q));
double cPhi = cos(phi);
double sPhi = sqrt(1.-sqr(cPhi));
if ( phi > Constants::pi )
sPhi = -sPhi;
Lorentz5Momentum kt;
if ( !spacelike ) {
kt.setT(ZERO);
kt.setX(pt*Qy*cPhi/Qp);
kt.setY(-pt*(4*ptx*pty*cPhi/Qp+q*sPhi)/Qy);
kt.setZ(2.*pt*(-ptx*q*cPhi/Qp + pty*sPhi)/Qy);
} else {
kt.setT(2.*pt*(ptx*q*cPhi+pty*Qp*sPhi)/(q*Qy));
kt.setX(pt*(Qp*q*cPhi+4.*ptx*pty*sPhi)/(q*Qy));
kt.setY(pt*Qy*sPhi/q);
kt.setZ(ZERO);
}
if ( boost )
kt = kt + ((P*kt-Q*kt)/(P*Q-Q.mass2()))*(P-Q);
kt.setMass(-pt);
kt.rescaleRho();
return kt;
}
// If needed, insert default implementations of virtual function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
AbstractClassDescription<DipoleSplittingKinematics> DipoleSplittingKinematics::initDipoleSplittingKinematics;
// Definition of the static class description member.
void DipoleSplittingKinematics::Init() {
static ClassDocumentation<DipoleSplittingKinematics> documentation
("DipoleSplittingKinematics is the base class for dipole splittings "
"as performed in the dipole shower.");
static Parameter<DipoleSplittingKinematics,Energy> interfaceIRCutoff
("IRCutoff",
"The IR cutoff to be used by this splitting kinematics.",
&DipoleSplittingKinematics::theIRCutoff, GeV, 1.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Parameter<DipoleSplittingKinematics,double> interfaceXMin
("XMin",
"The minimum momentum fraction for incoming partons",
&DipoleSplittingKinematics::theXMin, 1.0e-5, 0.0, 1.0,
false, false, Interface::limited);
static Reference<DipoleSplittingKinematics,DipoleMCCheck> interfaceMCCheck
("MCCheck",
"[debug option] MCCheck",
&DipoleSplittingKinematics::theMCCheck, false, false, true, true, false);
interfaceMCCheck.rank(-1);
static Switch<DipoleSplittingKinematics,int> interfaceOpenZBoundaries
("OpenZBoundaries", "",
&DipoleSplittingKinematics::theOpenZBoundaries, 0, false, false);
static SwitchOption interfaceOpenZBoundarieshardScale
(interfaceOpenZBoundaries, "Hard", "", 0);
static SwitchOption interfaceOpenZBoundariesfull
(interfaceOpenZBoundaries, "Full", "", 1);
static SwitchOption interfaceOpenZBoundariesDipoleScale
(interfaceOpenZBoundaries, "DipoleScale", "", 2);
}
diff --git a/Shower/Dipole/Kinematics/DipoleSplittingKinematics.h b/Shower/Dipole/Kinematics/DipoleSplittingKinematics.h
--- a/Shower/Dipole/Kinematics/DipoleSplittingKinematics.h
+++ b/Shower/Dipole/Kinematics/DipoleSplittingKinematics.h
@@ -1,630 +1,643 @@
// -*- C++ -*-
//
// DipoleSplittingKinematics.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_DipoleSplittingKinematics_H
#define HERWIG_DipoleSplittingKinematics_H
//
// This is the declaration of the DipoleSplittingKinematics class.
//
#include "ThePEG/Handlers/HandlerBase.h"
#include "ThePEG/Vectors/Lorentz5Vector.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Utilities/UtilityBase.h"
#include "Herwig/Shower/Dipole/Utility/DipoleMCCheck.h"
namespace Herwig {
using namespace ThePEG;
class DipoleIndex;
class DipoleSplittingInfo;
class DipoleSplittingKernel;
/**
* \ingroup DipoleShower
* \author Simon Platzer
*
* \brief DipoleSplittingKinematics is the base class for dipole splittings
* as performed in the dipole shower.
*
* @see \ref DipoleSplittingKinematicsInterfaces "The interfaces"
* defined for DipoleSplittingKinematics.
*/
class DipoleSplittingKinematics: public HandlerBase {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
DipoleSplittingKinematics();
/**
* The destructor.
*/
virtual ~DipoleSplittingKinematics();
//@}
public:
/**
* Return the boundaries in between the evolution
* variable random number is to be sampled; the lower
* cuoff is assumed to correspond to the infrared cutoff.
*/
virtual pair<double,double> kappaSupport(const DipoleSplittingInfo&) const {
return {0.0,1.0};
}
/**
* Return the boundaries in between the momentum
* fraction random number is to be sampled.
*/
virtual pair<double,double> xiSupport(const DipoleSplittingInfo&) const {
return {0.0,1.0};
}
/**
* Return the dipole scale associated to the
* given pair of emitter and spectator. This
* should be the invariant mass or absolute value
* final/final or initial/initial and the absolute
* value of the momentum transfer for intial/final or
* final/initial dipoles.
*/
virtual Energy dipoleScale(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const {
// MEMinBias produces non-zero zeros.
if(abs(pEmitter*pSpectator)<0.0000001*GeV2)return ZERO;
assert(pEmitter*pSpectator >= ZERO);
return sqrt(2.*pEmitter*pSpectator);
}
/**
* Return the mass of the system absorbing
* the recoil in the dipole splitting.
* This is overloaded in the decay dipoles.
*/
virtual Energy recoilMassKin(const Lorentz5Momentum&,
const Lorentz5Momentum& pSpectator) const {
return pSpectator.m();
}
/**
* Return the maximum pt for the given dipole scale.
*/
virtual Energy ptMax(Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel& split) const =0;
/**
* Return the maximum pt for the given dipole scale.
*/
virtual Energy ptMax(Energy dScale,
double emX, double specX,
const DipoleSplittingInfo& dInfo,
- const DipoleSplittingKernel& split) const;
+ const DipoleSplittingKernel& split) const;
+
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy dScale,
+ double emX, double specX,
+ const DipoleIndex& dIndex,
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr spectator) const;
/**
* Return the maximum virtuality for the given dipole scale.
*/
virtual Energy QMax(Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel& split) const =0;
/**
* Return the maximum virtuality for the given dipole scale.
*/
virtual Energy QMax(Energy dScale,
double emX, double specX,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const;
/**
+ * Return the maximum virtuality for the given dipole scale.
+ */
+ virtual Energy QMax(Energy dScale,
+ double emX, double specX,
+ const DipoleIndex& dIndex,
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr spectator) const;
+
+ /**
* Return the pt given a virtuality.
*/
virtual Energy PtFromQ(Energy scale, const DipoleSplittingInfo&) const = 0;
/**
* Return the virtuality given a pt.
*/
virtual Energy QFromPt(Energy scale, const DipoleSplittingInfo&) const = 0;
/**
* Return the infrared cutoff.
*/
virtual Energy IRCutoff() const { return theIRCutoff; }
/**
* Return the minimum momentum fraction for
* incoming partons
*/
double xMin() const { return theXMin; }
/**
* Generate a pt
*/
Energy generatePt(double r, Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel& split,
double& weight) const;
/**
* Return the random number associated to
* the given pt.
*/
virtual double ptToRandom(Energy pt, Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel& split) const;
/**
* Return the boundaries on the momentum fraction
*/
virtual pair<double,double> zBoundaries(Energy pt,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const = 0;
/**
* Enumerate the variants of sampling z
*/
enum ZSamplingOptions {
FlatZ = 0,
OneOverZ,
OneOverOneMinusZ,
OneOverZOneMinusZ
};
/**
* Generate a z value flat
*/
double generateZ(double r, Energy pt, int sampling,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split,
double& weight) const;
/**
* Generate splitting variables given three random numbers
* and the momentum fractions of the emitter and spectator.
* Return true on success.
*/
virtual bool generateSplitting(double kappa, double xi, double phi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel&) = 0;
/**
* Get the splitting phasespace weight associated to
* the last call to generateSplitting. This is taken to
* be the single particle phasespace times 16 \pi^2 divided
* by the relevant propagator invariant.
*/
double jacobian() const { return theJacobian; }
/**
* Return true, if this splitting kinematics
* class is capable of delivering an overestimate
* to the jacobian.
*/
virtual bool haveOverestimate() const { return false; }
/**
* Return the overestimated jacobian for the
* last generated parameters.
*/
virtual double jacobianOverestimate() const { return -1.; }
/**
* Return the last generated pt
*/
Energy lastPt() const { return theLastPt; }
/**
* Return the last generated momentum fraction.
*/
double lastZ() const { return theLastZ; }
/**
* Return the last calculated zPrime for massive FF and decay dipoles.
*/
// Do not need in current implementation,
// using lastSplittingParameters instead.
//double lastZPrime() const { return theLastZPrime; }
/**
* Return the last generated azimuthal angle.
*/
double lastPhi() const { return theLastPhi; }
/**
* Return the momentum fraction, by which the emitter's
* momentum fraction should be divided after the splitting.
*/
double lastEmitterZ() const { return theLastEmitterZ; }
/**
* Return the momentum fraction, by which the spectator's
* momentum fraction should be divided after the splitting.
*/
double lastSpectatorZ() const { return theLastSpectatorZ; }
/**
* Return any additional parameters needed to
* evaluate the splitting kernel or to generate the
* full splitting.
*/
const vector<double>& lastSplittingParameters() const { return theLastSplittingParameters; }
/**
* Complete a DipoleSplittingInfo object with
* the parameters generated by the last call to
* generateSplitting()
*/
void prepareSplitting(DipoleSplittingInfo& dInfo);
public:
/**
* Generate the full kinematics given emitter and
* spectator momentum and a previously completeted
* DipoleSplittingInfo object.
*/
virtual void generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) = 0;
/**
* Return the emitter's momentum after the splitting.
*/
const Lorentz5Momentum& lastEmitterMomentum() const { return theEmitterMomentum; }
/**
* Return the spectator's momentum after the splitting.
*/
const Lorentz5Momentum& lastSpectatorMomentum() const { return theSpectatorMomentum; }
/**
* Return the emission's momentum.
*/
const Lorentz5Momentum& lastEmissionMomentum() const { return theEmissionMomentum; }
/*
* Return true, if there is a transformation which should
* be applied to all other final state particles except the ones
* involved in the splitting after having performed the splitting.
*/
virtual bool doesTransform () const { return false; }
/*
+ * Use the Dipole scale instead of hardpt for z-boundaries.
+ */
+ int openZBoundaries() const { return theOpenZBoundaries; }
+
+ /*
* perform the transformation if required.
*/
virtual Lorentz5Momentum transform (const Lorentz5Momentum& p) const { return p; }
/*
* Return true if this splitting is of a dipole which contains
* a decayed parton and requires the remnant to absorb the recoil.
*/
virtual bool isDecay() const { return false; }
/**
* Perform the recoil in the case of a decayed parton
*/
//virtual Lorentz5Momentum decayRecoil ( const Lorentz5Momentum& p, const int) { return p; }
/**
* Perform the recoil in the case of a decayed parton
*/
virtual void decayRecoil ( PList& ) {};
// {;}
protected:
/**
* Calculate a transverse momentum for the given momenta,
* invariant pt and azimuth.
*/
Lorentz5Momentum getKt(const Lorentz5Momentum& p1,
const Lorentz5Momentum& p2,
Energy pt,
double phi,
bool spacelike = false) const;
/**
* Set the splitting phasespace weight associated to
* the last call to generateSplitting. This is taken to
* be the single particle phasespace times 16 \pi^2 divided
* by the relevant propagator invariant.
*/
void jacobian(double w) { theJacobian = w; }
/**
* Set the last generated pt
*/
void lastPt(Energy p) { theLastPt = p; }
/**
* Set the last generated momentum fraction.
*/
void lastZ(double z) { theLastZ = z; }
/**
* Set the last calculated zPrime for massive FF and decay dipoles.
*/
// Do not need in current implementation,
// using lastSplittingParameters instead.
//void lastZPrime(double zPrime) { theLastZPrime = zPrime; }
/**
* Set the last generated azimuthal angle.
*/
void lastPhi(double p) { theLastPhi = p; }
/**
* Set the momentum fraction, by which the emitter's
* momentum fraction should be divided after the splitting.
*/
void lastEmitterZ(double z) { theLastEmitterZ = z; }
/**
* Set the momentum fraction, by which the spectator's
* momentum fraction should be divided after the splitting.
*/
void lastSpectatorZ(double z) { theLastSpectatorZ = z; }
/**
* Access any additional parameters needed to
* evaluate the splitting kernel or to generate the
* full splitting.
*/
vector<double>& splittingParameters() { return theLastSplittingParameters; }
/**
* Set the emitter's momentum after the splitting.
*/
void emitterMomentum(const Lorentz5Momentum& p) { theEmitterMomentum = p; }
/**
* Set the spectator's momentum after the splitting.
*/
void spectatorMomentum(const Lorentz5Momentum& p) { theSpectatorMomentum = p; }
/**
* Set the emission's momentum.
*/
void emissionMomentum(const Lorentz5Momentum& p) { theEmissionMomentum = p; }
/**
* Set the momentum of the recoil system before the splitting.
* 25/05/2016 - Not currently used.
*/
//void recoilMomentum( const Lorentz5Momentum& mom ) { theRecoilMomentum = mom; }
/**
* Set the momentum of the recoil system after the splitting.
*/
void splitRecoilMomentum( const Lorentz5Momentum& mom ) { theSplitRecoilMomentum = mom; }
/**
* Return the momentum of the recoil system before splitting.
* 25/05/2016 - Not currently used.
*/
//const Lorentz5Momentum& recoilMomentum() const { return theRecoilMomentum; }
/**
* Return the momentum of the recoil system after splitting.
*/
const Lorentz5Momentum& splitRecoilMomentum() const { return theSplitRecoilMomentum; }
-
-
- /*
- * Use the Dipole scale instead of hardpt for z-boundaries.
- */
-
- int openZBoundaries() const { return theOpenZBoundaries; }
-
-
-
public:
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
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);
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* The infrared cutoff associated to this
* splitting kinematics.
*/
Energy theIRCutoff;
/**
* The minimum momentum fraction for
* incoming partons
*/
double theXMin;
/**
* The last calculated splitting phase space weight.
*/
double theJacobian;
/**
* The last generated pt
*/
Energy theLastPt;
/**
* The last generated momentum fraction.
*/
double theLastZ;
/**
* The last calculated zPrime required for massive FF
* and decay kinematics dipoles.
* zPrime := qi.nk / (qi+qj).nk (qj = emission momentum)
*/
// Do not need in current implementation,
// using lastSplittingParameters instead.
//double theLastZPrime;
/**
* The last generated azimuthal angle.
*/
double theLastPhi;
/**
* The momentum fraction, by which the emitter's
* momentum fraction should be divided after the splitting.
*/
double theLastEmitterZ;
/**
* The momentum fraction, by which the spectator's
* momentum fraction should be divided after the splitting.
*/
double theLastSpectatorZ;
/**
* Any additional parameters needed to
* evaluate the splitting kernel or to generate the
* full splitting.
*/
vector<double> theLastSplittingParameters;
/**
* The emitter's momentum after the splitting.
*/
Lorentz5Momentum theEmitterMomentum;
/**
* The emission's momentum after the splitting.
*/
Lorentz5Momentum theEmissionMomentum;
/**
* The spectator's momentum after the splitting.
*/
Lorentz5Momentum theSpectatorMomentum;
/**
* The momentum of the recoil system used in decay dipole kinematics.
* 25/05/2016 - Not currently used
*/
//Lorentz5Momentum theRecoilMomentum;
/**
* The momentum of the recoil system after the splitting, used in decay dipole kinematics.
*/
Lorentz5Momentum theSplitRecoilMomentum;
int theOpenZBoundaries;
protected:
/**
* Pointer to a check histogram object
*/
Ptr<DipoleMCCheck>::ptr theMCCheck;
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is an abstract class.
*/
static AbstractClassDescription<DipoleSplittingKinematics> initDipoleSplittingKinematics;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
DipoleSplittingKinematics & operator=(const DipoleSplittingKinematics &);
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of DipoleSplittingKinematics. */
template <>
struct BaseClassTrait<Herwig::DipoleSplittingKinematics,1> {
/** Typedef of the first base class of DipoleSplittingKinematics. */
typedef HandlerBase NthBase;
};
/** This template specialization informs ThePEG about the name of
* the DipoleSplittingKinematics class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::DipoleSplittingKinematics>
: public ClassTraitsBase<Herwig::DipoleSplittingKinematics> {
/** Return a platform-independent class name */
static string className() { return "Herwig::DipoleSplittingKinematics"; }
/**
* The name of a file containing the dynamic library where the class
* DipoleSplittingKinematics is implemented. It may also include several, space-separated,
* libraries if the class DipoleSplittingKinematics depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_DipoleSplittingKinematics_H */
diff --git a/Shower/Dipole/Kinematics/FFLightKinematics.cc b/Shower/Dipole/Kinematics/FFLightKinematics.cc
--- a/Shower/Dipole/Kinematics/FFLightKinematics.cc
+++ b/Shower/Dipole/Kinematics/FFLightKinematics.cc
@@ -1,175 +1,176 @@
// -*- C++ -*-
//
// FFLightKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFLightKinematics class.
//
#include "FFLightKinematics.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
using namespace Herwig;
FFLightKinematics::FFLightKinematics()
: DipoleSplittingKinematics() {}
FFLightKinematics::~FFLightKinematics() {}
IBPtr FFLightKinematics::clone() const {
return new_ptr(*this);
}
IBPtr FFLightKinematics::fullclone() const {
return new_ptr(*this);
}
Energy FFLightKinematics::ptMax(Energy dScale,
double, double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return dScale/2.;
}
Energy FFLightKinematics::QMax(Energy dScale,
double, double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return dScale;
}
Energy FFLightKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale*sqrt(z*(1.-z));
}
Energy FFLightKinematics::QFromPt(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale/sqrt(z*(1.-z));
}
pair<double,double> FFLightKinematics::zBoundaries(Energy pt,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel&) const {
Energy hard=dInfo.hardPt();
if(openZBoundaries()>0)hard=dInfo.scale()/2.;
const double s = sqrt(1.-sqr(pt/hard));
return {0.5*(1.-s),0.5*(1.+s)};
}
bool FFLightKinematics::generateSplitting(double kappa, double xi, double rphi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel& split) {
double weight = 1.0;
Energy pt = generatePt(kappa,info.scale(),
info.emitterX(),info.spectatorX(),
info.index(),split,
weight);
if ( pt < IRCutoff() || pt > info.hardPt() ) {
jacobian(0.0);
return false;
}
double z = 0.0;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emissionData()->id() != ParticleID::g ) {
z = generateZ(xi,pt,FlatZ,
info,split,weight);
} else {
z = generateZ(xi,pt,OneOverZOneMinusZ,
info,split,weight);
}
} else {
z = generateZ(xi,pt,OneOverOneMinusZ,
info,split,weight);
}
double y = sqr(pt/info.scale())/(z*(1.-z));
if ( z < 0.0 || z > 1.0 ||
y < 0.0 || y > 1.0 ) {
jacobian(0.0);
return false;
}
double phi = 2.*Constants::pi*rphi;
jacobian(weight*(1.-y));
lastPt(pt);
lastZ(z);
lastPhi(phi);
if ( theMCCheck )
theMCCheck->book(1.,1.,info.scale(),info.hardPt(),pt,z,jacobian());
return true;
}
void FFLightKinematics::generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) {
double z = dInfo.lastZ();
Energy pt = dInfo.lastPt();
double y = sqr(pt / (pEmitter+pSpectator).m()) / (z*(1.-z));
Lorentz5Momentum kt =
getKt(pEmitter, pSpectator, pt, dInfo.lastPhi());
Lorentz5Momentum em = z*pEmitter + y*(1.-z)*pSpectator + kt;
- em.setMass(0.*GeV);
+ Lorentz5Momentum emm = (1.-z)*pEmitter + z*y*pSpectator - kt;
+ Lorentz5Momentum spe = (1.-y)*pSpectator;
+
+ em.setMass(ZERO);
em.rescaleEnergy();
- Lorentz5Momentum emm = (1.-z)*pEmitter + z*y*pSpectator - kt;
- emm.setMass(0.*GeV);
+ emm.setMass(ZERO);
emm.rescaleEnergy();
-
- Lorentz5Momentum spe = (1.-y)*pSpectator;
- spe.setMass(0.*GeV);
+
+ spe.setMass(ZERO);
spe.rescaleEnergy();
emitterMomentum(em);
emissionMomentum(emm);
spectatorMomentum(spe);
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FFLightKinematics::persistentOutput(PersistentOStream & ) const {
}
void FFLightKinematics::persistentInput(PersistentIStream & , int) {
}
ClassDescription<FFLightKinematics> FFLightKinematics::initFFLightKinematics;
// Definition of the static class description member.
void FFLightKinematics::Init() {
static ClassDocumentation<FFLightKinematics> documentation
("FFLightKinematics implements massless splittings "
"off a final-final dipole.");
}
diff --git a/Shower/Dipole/Kinematics/FFMassiveKinematics.cc b/Shower/Dipole/Kinematics/FFMassiveKinematics.cc
--- a/Shower/Dipole/Kinematics/FFMassiveKinematics.cc
+++ b/Shower/Dipole/Kinematics/FFMassiveKinematics.cc
@@ -1,425 +1,503 @@
// -*- C++ -*-
//
// FFMassiveKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FFMassiveKinematics class.
//
#include "FFMassiveKinematics.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
#include "Herwig/Shower/Dipole/Kernels/DipoleSplittingKernel.h"
#include "ThePEG/Interface/Switch.h"
// TODO: remove after verification
// only for checking for NaN or inf
#include <gsl/gsl_math.h>
using namespace Herwig;
FFMassiveKinematics::FFMassiveKinematics()
: DipoleSplittingKinematics(),
theFullJacobian(true) {}
FFMassiveKinematics::~FFMassiveKinematics() {}
IBPtr FFMassiveKinematics::clone() const {
return new_ptr(*this);
}
IBPtr FFMassiveKinematics::fullclone() const {
return new_ptr(*this);
}
pair<double,double> FFMassiveKinematics::kappaSupport(const DipoleSplittingInfo&) const {
return {0.0,1.0};
}
pair<double,double> FFMassiveKinematics::xiSupport(const DipoleSplittingInfo& split) const {
double c = sqrt(1.-4.*sqr(IRCutoff()/generator()->maximumCMEnergy()));
if ( split.index().emitterData()->id() == ParticleID::g ) {
if ( split.emissionData()->id() != ParticleID::g )
return {0.5*(1.-c),0.5*(1.+c)};
double b = log((1.+c)/(1.-c));
return {-b,b};
}
return {-log(0.5*(1.+c)),-log(0.5*(1.-c))};
}
Energy FFMassiveKinematics::dipoleScale(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const {
return (pEmitter+pSpectator).m();
}
Energy FFMassiveKinematics::ptMax(Energy dScale,
double, double,
- const DipoleIndex& ind,
+ const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const {
- double mui = split.emitter(ind)->mass() / dScale;
- double mu = split.emission(ind)->mass() / dScale;
- double muj = split.spectator(ind)->mass() / dScale;
- double mui2 = sqr( mui ), mu2 = sqr( mu );
+ DipoleIndex ind = dInfo.index();
+ double mui2 = 0.;
+
+ // g->gg and g->qqbar
+ if ( abs(split.emitter(ind)->id()) == abs(split.emission(ind)->id()) ) {
+ mui2 = sqr(split.emitter(ind)->mass() / dScale);
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mui2 = sqr(dInfo.emitterMass()/dScale);
+ }
+
+ double mu2 = sqr(split.emission(ind)->mass() / dScale);
+ double muj = dInfo.spectatorMass()/dScale;
+
return rootOfKallen( mui2, mu2, sqr(1.-muj) ) / ( 2.-2.*muj ) * dScale;
}
+
+Energy FFMassiveKinematics::ptMax(Energy dScale,
+ double, double,
+ const DipoleIndex& ind,
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr spectator) const {
+ double mui2 = 0.;
+ // g->gg and g->qqbar
+ if ( abs(split.emitter(ind)->id()) == abs(split.emission(ind)->id()) ) {
+ mui2 = sqr(split.emitter(ind)->mass() / dScale);
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mui2 = sqr(emitter->mass()/dScale);
+ }
+ double mu2 = sqr(split.emission(ind)->mass() / dScale);
+ double muj = spectator->mass()/dScale;
+
+ return rootOfKallen( mui2, mu2, sqr(1.-muj) ) / ( 2.-2.*muj ) * dScale;
+}
+
+
Energy FFMassiveKinematics::QMax(Energy dScale,
double, double,
- const DipoleIndex& ind,
+ const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel&) const {
assert(false && "implementation missing");
- double Muj = ind.spectatorData()->mass() / dScale;
+ double Muj = dInfo.spectatorMass() / dScale;
return dScale * ( 1.-2.*Muj+sqr(Muj) );
}
// The name of this function is misleading
// scale here is defined as sqr(scale) = sqr(qi+qj)
// Here, scale is Q
Energy FFMassiveKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const {
double zPrime=split.lastSplittingParameters()[0];
- Energy mi = split.emitterData()->mass();
- Energy m = split.emissionData()->mass();
- Energy2 pt2 = zPrime*(1.-zPrime)*sqr(scale) - (1-zPrime)*sqr(mi) - zPrime*sqr(m);
+
+ // masses
+ Energy2 mi2 = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(split.emitterData()->id()) == abs(split.emissionData()->id()) ) {
+ mi2 = sqr(split.emitterData()->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = sqr(split.emitterMass());
+ }
+ Energy2 m2 = sqr(split.emissionData()->mass());
+
+ Energy2 pt2 = zPrime*(1.-zPrime)*sqr(scale) - (1-zPrime)*mi2 - zPrime*m2;
assert(pt2 >= ZERO);
return sqrt(pt2);
}
// This is simply the inverse of PtFromQ
Energy FFMassiveKinematics::QFromPt(Energy pt, const DipoleSplittingInfo& split) const {
double zPrime=split.lastSplittingParameters()[0];
- Energy mi = split.emitterData()->mass();
- Energy m = split.emissionData()->mass();
- Energy2 Q2 = (sqr(pt) + (1-zPrime)*sqr(mi) + zPrime*sqr(m))/(zPrime*(1.-zPrime));
+
+
+ // masses
+ Energy2 mi2 = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(split.emitterData()->id()) == abs(split.emissionData()->id()) ) {
+ mi2 = sqr( split.emitterData()->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = sqr(split.emitterMass());
+ }
+ Energy2 m2 = sqr(split.emissionData()->mass());
+
+ Energy2 Q2 = (sqr(pt) + (1-zPrime)*mi2 + zPrime*m2)/(zPrime*(1.-zPrime));
return sqrt(Q2);
}
double FFMassiveKinematics::ptToRandom(Energy pt, Energy,
double,double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return log(pt/IRCutoff()) / log(0.5 * generator()->maximumCMEnergy()/IRCutoff());
}
// TODO - SW: Implement if statement to check
// for spectator mass when tidying up the notation.
bool FFMassiveKinematics::generateSplitting(double kappa, double xi, double rphi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel&) {
-
+
// scaled masses
- double mui2 = sqr( info.emitterData()->mass() / info.scale() );
- double mu2 = sqr( info.emissionData()->mass() / info.scale() );
- double muj2 = sqr( info.spectatorData()->mass() / info.scale() );
-
- double Mui2 = 0.;
- if ( info.emitterData()->id() + info.emissionData()->id() == 0 ) Mui2 = 0.; // gluon
- else Mui2 = mui2; // (anti)quark
- double Muj2 = muj2;
+ double Mui2 = sqr(info.emitterMass() / info.scale());
+ double Muj2 = sqr(info.spectatorMass() / info.scale());
+ double muj2 = Muj2;
+
+ double mui2 = 0.;
+ // g->gg and g->qqbar
+ if ( abs(info.emitterData()->id()) == abs(info.emissionData()->id()) ) {
+ mui2 = sqr(info.emitterData()->mass()/info.scale());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mui2 = Mui2;
+ }
+ double mu2 = sqr(info.emissionData()->mass()/info.scale() );
// To solve issue with scale during presampling
// need to enforce that Qijk-mij2-mk2 = 2*pij.pk > 0,
// so combine checks by comparing against square root.
if ( 1.-Mui2-Muj2 < sqrt(4.*Mui2*Muj2) ) {
jacobian(0.0);
return false;
}
Energy2 Qijk = sqr(info.scale());
double suijk = 0.5*( 1. - Mui2 - Muj2 + sqrt( sqr(1.-Mui2-Muj2) - 4.*Mui2*Muj2 ) );
// Calculate pt
Energy pt = IRCutoff() * pow(0.5 * generator()->maximumCMEnergy()/IRCutoff(),kappa);
Energy2 pt2 = sqr(pt);
if ( pt > info.hardPt() || pt < IRCutoff() ) {
jacobian(0.0);
return false;
}
// Generate zPrime (i.e. the new definition of z specific to massive FF)
double zPrime;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emissionData()->id() != ParticleID::g ) {
zPrime = xi;
}
else {
zPrime = exp(xi)/(1.+exp(xi));
}
}
else {
zPrime = 1.-exp(-xi);
}
// new: 2011-08-31
// 2011-11-08: this does happen
if( sqrt(mui2)+sqrt(mu2)+sqrt(muj2) > 1. ){
jacobian(0.0);
return false;
}
// These apply to zPrime
// phasespace constraint to incorporate ptMax
Energy hard = info.hardPt();
if(openZBoundaries()>0){
// From ptMax(..)
hard = rootOfKallen( mui2, mu2, sqr(1.-sqrt(muj2)) ) /
( 2.-2.*sqrt(muj2) ) * info.scale();
assert(pt<=hard);
}
double ptRatio = sqrt(1.-sqr(pt/hard));
double zp1 = ( 1.+mui2-mu2+muj2-2.*sqrt(muj2) +
rootOfKallen(mui2,mu2,sqr(1-sqrt(muj2))) * ptRatio) /
( 2.*sqr(1.-sqrt(muj2)) );
double zm1 = ( 1.+mui2-mu2+muj2-2.*sqrt(muj2) -
rootOfKallen(mui2,mu2,sqr(1-sqrt(muj2))) * ptRatio) /
( 2.*sqr(1.-sqrt(muj2)) );
if ( zPrime > zp1 || zPrime < zm1 ) {
jacobian(0.0);
return false;
}
// Calculate A:=xij*w
double A = (1./(suijk*zPrime*(1.-zPrime))) * ( pt2/Qijk + zPrime*mu2 + (1.-zPrime)*mui2 - zPrime*(1.-zPrime)*Mui2 );
// Calculate y from A (can also write explicitly in terms of qt, zPrime and masses however we need A anyway)
double bar = 1.-mui2-mu2-muj2;
double y = (1./bar) * (A*suijk + Mui2 - mui2 - mu2 );
// kinematic phasespace boundaries for y
// same as in Dittmaier hep-ph/9904440v2 (equivalent to CS)
double ym = 2.*sqrt(mui2)*sqrt(mu2)/bar;
double yp = 1. - 2.*sqrt(muj2)*(1.-sqrt(muj2))/bar;
if ( y < ym || y > yp ) {
jacobian(0.0);
return false;
}
// Calculate xk and xij
double lambdaK = 1. + (Muj2/suijk);
double lambdaIJ = 1. + (Mui2/suijk);
double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muj2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muj2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muj2/suijk) );
double xij = 1. - ( (Muj2/suijk) * (1.-xk) / xk );
// Transform to standard z definition as used in the kernels (i.e. that used in CS and standard sudakov parametrisations)
double z = ( (zPrime*xij*xk*suijk/2.) + (Muj2/ ( 2.*xk*xij*suijk*zPrime))*(pt2/Qijk + mui2) ) /
( (xij*xk*suijk/2.) + (Muj2/(2.*xk*xij))*(Mui2/suijk + A) );
// These apply to z, not zPrime
double zm = ( (2.*mui2+bar*y)*(1.-y) - sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) /
( 2.*(1.-y)*(mui2+mu2+bar*y) );
double zp = ( (2.*mui2+bar*y)*(1.-y) + sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) /
( 2.*(1.-y)*(mui2+mu2+bar*y) );
if ( z < zm || z > zp ) {
jacobian(0.0);
return false;
}
double phi = 2.*Constants::pi*rphi;
double mapZJacobian;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emissionData()->id() != ParticleID::g ) {
mapZJacobian = 1.;
}
else {
mapZJacobian = z*(1.-z);
}
}
else {
mapZJacobian = 1.-z;
}
// Compute and store the jacobian
double jac = 0.0;
double propCntrb = 1./ ( 1. + (mui2+mu2-Mui2)/(bar*y) );
// TODO - SW - Tidy up notation everywhere alongside writing for the manual
// The full jacobian including the z->zprime jacobian
if ( theFullJacobian && info.spectatorData()->mass() != ZERO ) {
// Sort out variables
Energy2 sbar = Qijk*bar;
Energy2 sijk = Qijk*suijk;
Energy2 mi2 = Qijk*mui2;
Energy2 mj2 = Qijk*mu2;
Energy2 mk2 = Qijk*muj2;
// Compute dy/dzPrime and pt2* dy/dpt2
double dyBydzPrime = (1./sbar) * ( -pt2*(1.-2.*zPrime)/sqr(zPrime*(1.-zPrime)) - mi2/sqr(zPrime) + mj2/sqr(1.-zPrime) );
InvEnergy2 dyBydpt2 = 1./(sbar*zPrime*(1.-zPrime));
// Compute dA/dzPrime and dA/dpt2
double dABydzPrime = (sbar/sijk) * dyBydzPrime;
InvEnergy2 dABydpt2 = (sbar/sijk) * dyBydpt2;
// Compute dxk/dzPrime, dxk/dpt2, dxij/dzPrime and dxij/dpt2
double factor = (0.5/lambdaK) * (-1. - (1./sqrt( sqr(lambdaK + (mk2/sijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*mk2/sijk)) * (lambdaK + (mk2/sijk)*lambdaIJ - A));
double dxkBydzPrime = factor * dABydzPrime;
InvEnergy2 dxkBydpt2 = factor * dABydpt2;
double dxijBydzPrime = (mk2/sijk) * (1./sqr(xk)) * dxkBydzPrime;
InvEnergy2 dxijBydpt2 = (mk2/sijk) * (1./sqr(xk)) * dxkBydpt2;
Energy2 dqiDotqkBydzPrime = xij*xk*0.5*sijk + zPrime*dxijBydzPrime*xk*0.5*sijk + zPrime*xij*dxkBydzPrime*0.5*sijk
+ 0.5*(mk2/sijk)*(pt2 + mi2) * (-1./(xk*xij*sqr(zPrime)) - dxkBydzPrime/(zPrime*xij*sqr(xk)) - dxijBydzPrime/(zPrime*xk*sqr(xij)));
double dqiDotqkBydpt2 = dxijBydpt2*zPrime*xk*0.5*sijk + zPrime*xij*dxkBydpt2*0.5*sijk
+ (0.5*mk2/sijk) * (1./(zPrime*xk*xij)) * (1. + (pt2+mi2)*(-dxkBydpt2/xk - dxijBydpt2/xij) );
// Compute dzBydzPrime and dzBydpt2
Energy2 qiDotqk = (zPrime*xij*xk*sijk*0.5) + (mk2/ ( 2.*xk*xij*sijk*zPrime))*(pt2 + mi2);
double dzBydzPrime = (1./sbar) * ( 2.*qiDotqk*dyBydzPrime/sqr(1.-y) + (1./(1.-y)) * 2.*dqiDotqkBydzPrime );
InvEnergy2 dzBydpt2 = (1./sbar) * ( 2.*qiDotqk*dyBydpt2/sqr(1.-y) + (1./(1.-y)) * 2.*dqiDotqkBydpt2 );
double pt2Jac = pt2*abs(dzBydpt2*dyBydzPrime - dzBydzPrime*dyBydpt2);
// Include the other terms and calculate the jacobian
jac = propCntrb * bar / rootOfKallen(1.,Mui2,Muj2) * (1.-y)/y * pt2Jac;
}
// the exact result when the spectator is massless.
else {
double jacPt2 = 1. / ( 1. + sqr(1.-zPrime)*Qijk*mui2/pt2 + zPrime*zPrime*Qijk*mu2/pt2 );
jac = propCntrb * bar / rootOfKallen(1.,Mui2,Muj2) * (1.-y) * jacPt2;
}
jacobian(jac * mapZJacobian * 2. * log(0.5 * generator()->maximumCMEnergy()/IRCutoff()) );
// Record the physical variables, as used by the CS kernel definitions
lastPt(pt);
lastZ(z);
lastPhi(phi);
// Record zPrime for use in kinematics generation and kernel evaluation
splittingParameters().clear();
splittingParameters().push_back(zPrime);
if ( theMCCheck ) {
theMCCheck->book(1.,1.,info.scale(),info.hardPt(),pt,z,jacobian());
}
return true;
}
// revised 2011-08-22
// revised 2011-11-06
// revised with new FF kinematics in 2016 - SW
void FFMassiveKinematics::generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) {
// The only value stored in dInfo.lastSplittingParameters() should be zPrime
assert(dInfo.lastSplittingParameters().size() == 1 );
double zPrime = dInfo.lastSplittingParameters()[0];
Energy pt = dInfo.lastPt();
Energy2 pt2 = sqr(pt);
// scaled masses
- double mui2 = sqr( dInfo.emitterData()->mass() / dInfo.scale() );
- double mu2 = sqr( dInfo.emissionData()->mass() / dInfo.scale() );
- double muj2 = sqr( dInfo.spectatorData()->mass() / dInfo.scale() );
+ double Mui2 = sqr(dInfo.emitterMass() / dInfo.scale());
+ double Muk2 = sqr(dInfo.spectatorMass() / dInfo.scale());
+ //double muk2 = Muk2;
- double Mui2 = 0.;
- if ( dInfo.emitterData()->id() + dInfo.emissionData()->id() == 0 ) Mui2 = 0.; // gluon
- else Mui2 = mui2; // (anti)quark
- double Muj2 = muj2;
+ Energy mi = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(dInfo.emitterData()->id()) == abs(dInfo.emissionData()->id()) ) {
+ mi = dInfo.emitterData()->mass();
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi = dInfo.emitterMass();
+ }
+ double mui2 = sqr(mi/dInfo.scale());
+ double mu2 = sqr(dInfo.emissionData()->mass() / dInfo.scale() );
Energy2 Qijk = sqr(dInfo.scale());
- double suijk = 0.5*( 1. - Mui2 - Muj2 + sqrt( sqr(1.-Mui2-Muj2) - 4.*Mui2*Muj2 ) );
+ double suijk = 0.5*( 1. - Mui2 - Muk2 + sqrt( sqr(1.-Mui2-Muk2) - 4.*Mui2*Muk2 ) );
double suijk2 = sqr(suijk);
// Calculate A:=xij*w
double A = (1./(suijk*zPrime*(1.-zPrime))) * ( pt2/Qijk + zPrime*mu2 + (1.-zPrime)*mui2 - zPrime*(1.-zPrime)*Mui2 );
// Calculate the scaling factors, xk and xij
- double lambdaK = 1. + (Muj2/suijk);
+ double lambdaK = 1. + (Muk2/suijk);
double lambdaIJ = 1. + (Mui2/suijk);
- double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muj2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muj2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muj2/suijk) );
- double xij = 1. - ( (Muj2/suijk) * (1.-xk) / xk );
+ double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muk2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muk2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muk2/suijk) );
+ double xij = 1. - ( (Muk2/suijk) * (1.-xk) / xk );
// Construct reference momenta nk, nij, nt
- Lorentz5Momentum nij = ( suijk2 / (suijk2-Mui2*Muj2) ) * (pEmitter - (Mui2/suijk)*pSpectator);
- Lorentz5Momentum nk = ( suijk2 / (suijk2-Mui2*Muj2) ) * (pSpectator - (Muj2/suijk)*pEmitter);
+ Lorentz5Momentum nij = ( suijk2 / (suijk2-Mui2*Muk2) ) * (pEmitter - (Mui2/suijk)*pSpectator);
+ Lorentz5Momentum nk = ( suijk2 / (suijk2-Mui2*Muk2) ) * (pSpectator - (Muk2/suijk)*pEmitter);
// Following notation in notes, qt = sqrt(wt)*nt
Lorentz5Momentum qt = getKt(nij,nk,pt,dInfo.lastPhi());
// Construct qij, qk, qi and qj
Lorentz5Momentum qij = xij*nij + (Mui2/(xij*suijk))*nk;
- Lorentz5Momentum qk = xk*nk + (Muj2/(xk*suijk))*nij;
+ Lorentz5Momentum qk = xk*nk + (Muk2/(xk*suijk))*nij;
// For clarity, following notation in notes:
//Lorentz5Momentum qi = zPrime*qij + ((pt2 + mi2 - zPrime*zPrime*mij2)/(xij*sijk*zPrime))*nk + sqrt(wt)*nt;
//Lorentz5Momentum qj = (1.-zPrime)*qij + ((pt2 + mj2 - sqr(1.-zPrime)*mij2)/(xij*sijk*(1.-zPrime)))*nk - sqrt(wt)*nt;
// No need to actually calculate nt and wt:
Lorentz5Momentum qi = zPrime*qij + ((pt2/Qijk + mui2 - zPrime*zPrime*Mui2)/(xij*suijk*zPrime))*nk + qt;
Lorentz5Momentum qj = (1.-zPrime)*qij + ((pt2/Qijk + mu2 - sqr(1.-zPrime)*Mui2)/(xij*suijk*(1.-zPrime)))*nk - qt;
+ qi.setMass(mi);
+ qi.rescaleEnergy();
+
+ qj.setMass(dInfo.emissionData()->mass());
+ qj.rescaleEnergy();
+
+ qk.setMass(dInfo.spectatorMass());
+ qk.rescaleEnergy();
+
emitterMomentum(qi);
emissionMomentum(qj);
spectatorMomentum(qk);
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FFMassiveKinematics::persistentOutput(PersistentOStream & os) const {
os << theFullJacobian;
}
void FFMassiveKinematics::persistentInput(PersistentIStream & is, int) {
is >> theFullJacobian;
}
ClassDescription<FFMassiveKinematics> FFMassiveKinematics::initFFMassiveKinematics;
// Definition of the static class description member.
void FFMassiveKinematics::Init() {
static ClassDocumentation<FFMassiveKinematics> documentation
("FFMassiveKinematics implements massive splittings "
"off a final-final dipole.");
static Switch<FFMassiveKinematics,bool> interfaceFullJacobian
("FullJacobian",
"Use the full jacobian expression for the FF kinematics.",
&FFMassiveKinematics::theFullJacobian, true, false, false);
static SwitchOption interfaceFullJacobianYes
(interfaceFullJacobian,
"Yes",
"Use the full jacobian.",
true);
static SwitchOption interfaceFullJacobianNo
(interfaceFullJacobian,
"No",
"Do not use the full jacobian.",
false);
interfaceFullJacobian.rank(-1);
}
diff --git a/Shower/Dipole/Kinematics/FFMassiveKinematics.h b/Shower/Dipole/Kinematics/FFMassiveKinematics.h
--- a/Shower/Dipole/Kinematics/FFMassiveKinematics.h
+++ b/Shower/Dipole/Kinematics/FFMassiveKinematics.h
@@ -1,268 +1,303 @@
// -*- C++ -*-
//
// FFMassiveKinematics.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_FFMassiveKinematics_H
#define HERWIG_FFMassiveKinematics_H
//
// This is the declaration of the FFMassiveKinematics class.
//
#include "DipoleSplittingKinematics.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer, Stephen Webster
*
* \brief FFMassiveKinematics implements massive splittings
* off a final-final dipole.
*
*/
class FFMassiveKinematics: public DipoleSplittingKinematics {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
FFMassiveKinematics();
/**
* The destructor.
*/
virtual ~FFMassiveKinematics();
//@}
public:
/**
* Return the boundaries in between the evolution
* variable random number is to be sampled; the lower
* cuoff is assumed to correspond to the infrared cutoff.
*/
virtual pair<double,double> kappaSupport(const DipoleSplittingInfo& dIndex) const;
/**
* Return the boundaries in between the momentum
* fraction random number is to be sampled.
*/
virtual pair<double,double> xiSupport(const DipoleSplittingInfo& dIndex) const;
/**
* Return the boundaries on the momentum fraction
*/
virtual pair<double,double> zBoundaries(Energy,
const DipoleSplittingInfo&,
const DipoleSplittingKernel&) const {
return {0.0,1.0};
}
/**
* Return the dipole scale associated to the
* given pair of emitter and spectator. This
* should be the invariant mass or absolute value
* final/final or initial/initial and the absolute
* value of the momentum transfer for intial/final or
* final/initial dipoles.
*/
virtual Energy dipoleScale(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const;
- /**
- * Return the maximum pt for the given dipole scale.
- */
- virtual Energy ptMax(Energy dScale,
- double emX, double specX,
- const DipoleIndex& ind,
- const DipoleSplittingKernel& split) const;
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy dScale,
+ double emX, double specX,
+ const DipoleSplittingInfo& dInfo,
+ const DipoleSplittingKernel& split) const;
- /**
- * Return the maximum virtuality for the given dipole scale.
- */
- virtual Energy QMax(Energy dScale,
- double emX, double specX,
- const DipoleIndex& dIndex,
- const DipoleSplittingKernel& split) const;
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy dScale,
+ double, double,
+ const DipoleIndex& dIndex,
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr spectator) const;
+
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy,
+ double, double,
+ const DipoleIndex&,
+ const DipoleSplittingKernel&) const {
+ // Only the DipoleSplittingInfo version should be used for massive
+ // dipoles, for now anyway.
+ assert(false);
+ return ZERO;
+ }
+
+ /**
+ * Return the maximum virtuality for the given dipole scale.
+ */
+ virtual Energy QMax(Energy dScale,
+ double emX, double specX,
+ const DipoleSplittingInfo& dInfo,
+ const DipoleSplittingKernel& split) const;
+
+ /**
+ * Return the maximum virtuality for the given dipole scale.
+ */
+ virtual Energy QMax(Energy,
+ double, double,
+ const DipoleIndex&,
+ const DipoleSplittingKernel&) const {
+ // Only the DipoleSplittingInfo version should be used for massive
+ // dipoles, for now anyway.
+ assert(false);
+ return ZERO;
+ }
/**
* Return the pt given a virtuality.
*/
virtual Energy PtFromQ(Energy scale, const DipoleSplittingInfo&) const;
/**
* Return the virtuality given a pt.
*/
virtual Energy QFromPt(Energy scale, const DipoleSplittingInfo&) const;
/**
* Return the random number associated to
* the given pt.
*/
virtual double ptToRandom(Energy pt, Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel& split) const;
/**
* Generate splitting variables given three random numbers
* and the momentum fractions of the emitter and spectator.
* Return true on success.
*/
virtual bool generateSplitting(double kappa, double xi, double phi,
DipoleSplittingInfo& dIndex,
const DipoleSplittingKernel& split);
/**
* Generate the full kinematics given emitter and
* spectator momentum and a previously completeted
* DipoleSplittingInfo object.
*/
virtual void generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo);
public:
/**
* Triangular / Kallen function
*/
template <class T>
inline double rootOfKallen (T a, T b, T c) const {
double sres=a*a + b*b + c*c - 2.*( a*b+a*c+b*c );
return sres>0.?sqrt( sres ):0.; }
/**
* Perform a rotation on both momenta such that the first one will
* point along the (positive) z axis. Rotate back to the original
* reference frame by applying rotateUz(returnedVector) to each momentum.
*/
ThreeVector<double> rotateToZ (Lorentz5Momentum& pTarget, Lorentz5Momentum& p1){
ThreeVector<double> oldAxis = pTarget.vect().unit();
double ct = oldAxis.z(); double st = sqrt( 1.-sqr(ct) ); // cos,sin(theta)
double cp = oldAxis.x()/st; double sp = oldAxis.y()/st; // cos,sin(phi)
pTarget.setZ( pTarget.vect().mag() ); pTarget.setX( 0.*GeV ); pTarget.setY( 0.*GeV );
Lorentz5Momentum p1old = p1;
p1.setX( sp*p1old.x() - cp*p1old.y() );
p1.setY( ct*cp*p1old.x() + ct*sp*p1old.y() - st*p1old.z() );
p1.setZ( st*cp*p1old.x() + st*sp*p1old.y() + ct*p1old.z() );
return oldAxis;
}
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;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<FFMassiveKinematics> initFFMassiveKinematics;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FFMassiveKinematics & operator=(const FFMassiveKinematics &);
/**
* Option to use the full jacobian, including the z->zprime jacobian.
**/
bool theFullJacobian;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of FFMassiveKinematics. */
template <>
struct BaseClassTrait<Herwig::FFMassiveKinematics,1> {
/** Typedef of the first base class of FFMassiveKinematics. */
typedef Herwig::DipoleSplittingKinematics NthBase;
};
/** This template specialization informs ThePEG about the name of
* the FFMassiveKinematics class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::FFMassiveKinematics>
: public ClassTraitsBase<Herwig::FFMassiveKinematics> {
/** Return a platform-independent class name */
static string className() { return "Herwig::FFMassiveKinematics"; }
/**
* The name of a file containing the dynamic library where the class
* FFMassiveKinematics is implemented. It may also include several, space-separated,
* libraries if the class FFMassiveKinematics depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_FFMassiveKinematics_H */
diff --git a/Shower/Dipole/Kinematics/FILightKinematics.cc b/Shower/Dipole/Kinematics/FILightKinematics.cc
--- a/Shower/Dipole/Kinematics/FILightKinematics.cc
+++ b/Shower/Dipole/Kinematics/FILightKinematics.cc
@@ -1,186 +1,187 @@
// -*- C++ -*-
//
// FILightKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FILightKinematics class.
//
#include "FILightKinematics.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
using namespace Herwig;
FILightKinematics::FILightKinematics()
: DipoleSplittingKinematics() {}
FILightKinematics::~FILightKinematics() {}
IBPtr FILightKinematics::clone() const {
return new_ptr(*this);
}
IBPtr FILightKinematics::fullclone() const {
return new_ptr(*this);
}
Energy FILightKinematics::ptMax(Energy dScale,
double, double specX,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return dScale * sqrt((1.-specX)/specX) /2.;
}
Energy FILightKinematics::QMax(Energy dScale,
double, double specX,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return dScale * sqrt((1.-specX)/specX);
}
Energy FILightKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale*sqrt(z*(1.-z));
}
Energy FILightKinematics::QFromPt(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale/sqrt(z*(1.-z));
}
pair<double,double> FILightKinematics::zBoundaries(Energy pt,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel&) const {
Energy hard=dInfo.hardPt();
if(openZBoundaries()==1)
- hard=dInfo.scale()*sqrt((1.-dInfo.spectatorX())/dInfo.spectatorX()/2.);
+ hard=dInfo.scale()*sqrt((1.-dInfo.spectatorX())/dInfo.spectatorX())/2.;
if(openZBoundaries()==2)
- hard=dInfo.scale()*min(1.,sqrt((1.-dInfo.spectatorX())/dInfo.spectatorX())/2.);
+ hard=dInfo.scale()*min(1.,sqrt((1.-dInfo.spectatorX())/dInfo.spectatorX())/2.);
if(hard<pt)return {0.5,0.5};
double s = sqrt(1.-sqr(pt/hard));
return {0.5*(1.-s),0.5*(1.+s)};
}
bool FILightKinematics::generateSplitting(double kappa, double xi, double rphi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel& split) {
if ( info.spectatorX() < xMin() ) {
jacobian(0.0);
return false;
}
double weight = 1.0;
Energy pt = generatePt(kappa,info.scale(),
info.emitterX(),info.spectatorX(),
info.index(),split,
weight);
if ( pt < IRCutoff() || pt > info.hardPt() ) {
jacobian(0.0);
return false;
}
double z = 0.0;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emissionData()->id() != ParticleID::g ) {
z = generateZ(xi,pt,FlatZ,
info,split,weight);
} else {
z = generateZ(xi,pt,OneOverZOneMinusZ,
info,split,weight);
}
} else {
z = generateZ(xi,pt,OneOverOneMinusZ,
info,split,weight);
}
double x = 1./(1.+sqr(pt/info.scale())/(z*(1.-z)));
if ( z < 0.0 || z > 1.0 ||
x < info.spectatorX() || x > 1.0 ) {
jacobian(0.0);
return false;
}
double phi = 2.*Constants::pi*rphi;
jacobian(weight);
lastPt(pt);
lastZ(z);
lastPhi(phi);
lastSpectatorZ(x);
if ( theMCCheck )
theMCCheck->book(1.,info.spectatorX(),info.scale(),info.hardPt(),pt,z,jacobian());
return true;
}
void FILightKinematics::generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) {
Energy pt = dInfo.lastPt();
double z = dInfo.lastZ();
double x = 1./(1.+sqr(pt/dInfo.scale())/(z*(1.-z)));
Lorentz5Momentum kt =
getKt (pSpectator, pEmitter, pt, dInfo.lastPhi(),true);
Lorentz5Momentum em = z*pEmitter + (1.-z)*((1.-x)/x)*pSpectator + kt;
- em.setMass(0.*GeV);
+ Lorentz5Momentum emm = (1.-z)*pEmitter + z*((1.-x)/x)*pSpectator - kt;
+ Lorentz5Momentum spe = (1./x)*pSpectator;
+
+ em.setMass(ZERO);
em.rescaleEnergy();
- Lorentz5Momentum emm = (1.-z)*pEmitter + z*((1.-x)/x)*pSpectator - kt;
- emm.setMass(0.*GeV);
+ emm.setMass(ZERO);
emm.rescaleEnergy();
-
- Lorentz5Momentum spe = (1./x)*pSpectator;
- spe.setMass(0.*GeV);
+
+ spe.setMass(ZERO);
spe.rescaleEnergy();
emitterMomentum(em);
emissionMomentum(emm);
spectatorMomentum(spe);
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FILightKinematics::persistentOutput(PersistentOStream & ) const {
}
void FILightKinematics::persistentInput(PersistentIStream & , int) {
}
ClassDescription<FILightKinematics> FILightKinematics::initFILightKinematics;
// Definition of the static class description member.
void FILightKinematics::Init() {
static ClassDocumentation<FILightKinematics> documentation
("FILightKinematics implements massless splittings "
"off a final-initial dipole.");
}
diff --git a/Shower/Dipole/Kinematics/FIMassiveDecayKinematics.cc b/Shower/Dipole/Kinematics/FIMassiveDecayKinematics.cc
--- a/Shower/Dipole/Kinematics/FIMassiveDecayKinematics.cc
+++ b/Shower/Dipole/Kinematics/FIMassiveDecayKinematics.cc
@@ -1,431 +1,512 @@
// -*- C++ -*-
//
// FIMassiveDecayKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FIMassiveDecayKinematics class.
//
#include "FIMassiveDecayKinematics.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
#include "Herwig/Shower/Dipole/Kernels/DipoleSplittingKernel.h"
#include "ThePEG/Interface/Switch.h"
using namespace Herwig;
FIMassiveDecayKinematics::FIMassiveDecayKinematics()
: DipoleSplittingKinematics(), theFullJacobian(true) {}
FIMassiveDecayKinematics::~FIMassiveDecayKinematics() {}
IBPtr FIMassiveDecayKinematics::clone() const {
return new_ptr(*this);
}
IBPtr FIMassiveDecayKinematics::fullclone() const {
return new_ptr(*this);
}
pair<double,double> FIMassiveDecayKinematics::kappaSupport(const DipoleSplittingInfo&) const {
return {0.0,1.0};
}
pair<double,double> FIMassiveDecayKinematics::xiSupport(const DipoleSplittingInfo& split) const {
double c = sqrt(1.-4.*sqr(IRCutoff()/generator()->maximumCMEnergy()));
if ( split.index().emitterData()->id() == ParticleID::g ) {
if ( split.emissionData()->id() != ParticleID::g ){
return {0.5*(1.-c),0.5*(1.+c)};
}
double b = log((1.+c)/(1.-c));
return {-b,b};
}
return {-log(0.5*(1.+c)),-log(0.5*(1.-c))};
}
Energy FIMassiveDecayKinematics::dipoleScale(const Lorentz5Momentum&,
const Lorentz5Momentum& pSpectator) const {
return pSpectator.m();
}
Energy FIMassiveDecayKinematics::recoilMassKin(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const {
Lorentz5Momentum pk = pSpectator - pEmitter;
Energy pkmass = pk.m();
return pkmass;
}
Energy FIMassiveDecayKinematics::ptMax(Energy dScale,
double, double,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const {
DipoleIndex ind = dInfo.index();
+ double mui2 = 0.;
- double mui2 = sqr( split.emitter(ind)->mass() / dScale );
- double mu2 = sqr( split.emission(ind)->mass() / dScale );
+ // g->gg and g->qqbar
+ if ( abs(split.emitter(ind)->id()) == abs(split.emission(ind)->id()) ) {
+ mui2 = sqr(split.emitter(ind)->mass() / dScale);
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mui2 = sqr(dInfo.emitterMass()/dScale);
+ }
+ double mu2 = sqr(split.emission(ind)->mass() / dScale);
// Mass of recoil system
- double muj2 = sqr( dInfo.recoilMass() / dScale );
- double muj = sqrt( muj2 );
+ double muj = dInfo.recoilMass() / dScale;
return rootOfKallen( mui2, mu2, sqr(1.-muj) ) / ( 2.-2.*muj ) * dScale;
}
+
+Energy FIMassiveDecayKinematics::ptMax(Energy dScale,
+ double, double,
+ const DipoleIndex& ind,
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr spectator) const {
+ double mui2 = 0.;
+ // g->gg and g->qqbar
+ if ( abs(split.emitter(ind)->id()) == abs(split.emission(ind)->id()) ) {
+ mui2 = sqr(split.emitter(ind)->mass() / dScale);
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mui2 = sqr(emitter->mass()/dScale);
+ }
+ double mu2 = sqr(split.emission(ind)->mass() / dScale);
+
+ // Mass of recoil system
+ double muj = recoilMassKin(emitter->momentum(),spectator->momentum()) / dScale;
+
+ return rootOfKallen( mui2, mu2, sqr(1.-muj) ) / ( 2.-2.*muj ) * dScale;
+}
+
+
Energy FIMassiveDecayKinematics::QMax(Energy dScale,
double, double,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel&) const {
assert(false && "implementation missing");
// Mass of recoil system
double Muj2 = sqr( dInfo.recoilMass() / dScale );
double Muj = sqrt( Muj2 );
return dScale * ( 1.-2.*Muj+Muj2 );
}
// The name of this function is misleading
// scale here is defined as sqr(scale) = sqr(qi+qj)
// Here, scale is Q
Energy FIMassiveDecayKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const {
double zPrime = split.lastSplittingParameters()[0];
- Energy mi = split.emitterData()->mass();
- Energy m = split.emissionData()->mass();
- Energy2 pt2 = zPrime*(1.-zPrime)*sqr(scale) - (1-zPrime)*sqr(mi) - zPrime*sqr(m);
+
+ // masses
+ Energy2 mi2 = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(split.emitterData()->id()) == abs(split.emissionData()->id()) ) {
+ mi2 = sqr( split.emitterData()->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = sqr(split.emitterMass());
+ }
+ Energy2 m2 = sqr(split.emissionData()->mass());
+
+ Energy2 pt2 = zPrime*(1.-zPrime)*sqr(scale) - (1-zPrime)*mi2 - zPrime*m2;
assert(pt2 >= ZERO);
return sqrt(pt2);
}
// This is simply the inverse of PtFromQ
Energy FIMassiveDecayKinematics::QFromPt(Energy pt, const DipoleSplittingInfo& split) const {
double zPrime = split.lastSplittingParameters()[0];
- Energy mi = split.emitterData()->mass();
- Energy m = split.emissionData()->mass();
- Energy2 Q2 = (sqr(pt) + (1-zPrime)*sqr(mi) + zPrime*sqr(m))/(zPrime*(1.-zPrime));
+
+ // masses
+ Energy2 mi2 = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(split.emitterData()->id()) == abs(split.emissionData()->id()) ) {
+ mi2 = sqr( split.emitterData()->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = sqr(split.emitterMass());
+ }
+ Energy2 m2 = sqr(split.emissionData()->mass());
+
+ Energy2 Q2 = (sqr(pt) + (1-zPrime)*mi2 + zPrime*m2)/(zPrime*(1.-zPrime));
return sqrt(Q2);
}
double FIMassiveDecayKinematics::ptToRandom(Energy pt, Energy,
double,double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return log(pt/IRCutoff()) / log(0.5 * generator()->maximumCMEnergy()/IRCutoff());
}
bool FIMassiveDecayKinematics::generateSplitting(double kappa, double xi, double rphi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel&) {
// scaled masses
- double mui2 = sqr( info.emitterData()->mass() / info.scale() );
- double mu2 = sqr( info.emissionData()->mass() / info.scale() );
- double muj2 = sqr( info.recoilMass() / info.scale() );
+ double Mui2 = sqr(info.emitterMass() / info.scale());
+ double Muj2 = sqr(info.recoilMass() / info.scale());
+ double muj2 = Muj2;
- double Mui2 = 0.;
- if ( info.emitterData()->id() + info.emissionData()->id() == 0 ) Mui2 = 0.; // gluon
- else Mui2 = mui2; // (anti)quark
- double Muj2 = muj2;
+ double mui2 = 0.;
+ // g->gg and g->qqbar
+ if ( abs(info.emitterData()->id()) == abs(info.emissionData()->id()) ) {
+ mui2 = sqr(info.emitterData()->mass()/info.scale());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mui2 = Mui2;
+ }
+ double mu2 = sqr(info.emissionData()->mass()/info.scale() );
+
// To solve issue with scale during presampling
// need to enforce that Qijk-mij2-mk2 = 2*pij.pk > 0,
// so combine checks by comparing against square root.
if ( 1.-Mui2-Muj2 < sqrt(4.*Mui2*Muj2) ) {
jacobian(0.0);
return false;
}
Energy2 Qijk = sqr(info.scale());
double suijk = 0.5*( 1. - Mui2 - Muj2 + sqrt( sqr(1.-Mui2-Muj2) - 4.*Mui2*Muj2 ) );
// Calculate pt
Energy pt = IRCutoff() * pow(0.5 * generator()->maximumCMEnergy()/IRCutoff(),kappa);
Energy2 pt2 = sqr(pt);
if ( pt > info.hardPt() || pt < IRCutoff() ) {
jacobian(0.0);
return false;
}
// Generate zPrime (i.e. the new definition of z specific to massive FF and decays)
double zPrime;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emissionData()->id() != ParticleID::g ) {
zPrime = xi;
}
else {
zPrime = exp(xi)/(1.+exp(xi));
}
}
else {
zPrime = 1.-exp(-xi);
}
// new: 2011-08-31
// 2011-11-08: this does happen
if( sqrt(mui2)+sqrt(mu2)+sqrt(muj2) > 1. ){
jacobian(0.0);
return false;
}
// Have derived and checked the equations for zp1 and zm1, these apply to zPrime
// phasespace constraint to incorporate ptMax
- Energy hard=info.hardPt();
+ Energy hard = info.hardPt();
+
+ if(openZBoundaries()>0){
+ // From ptMax(..)
+ hard = rootOfKallen( mui2, mu2, sqr(1.-sqrt(muj2)) ) /
+ ( 2.-2.*sqrt(muj2) ) * info.scale();
+ assert(pt<=hard);
+ }
+
double ptRatio = sqrt(1.-sqr(pt/hard));
double zp1 = ( 1.+mui2-mu2+muj2-2.*sqrt(muj2) +
rootOfKallen(mui2,mu2,sqr(1-sqrt(muj2))) * ptRatio) /
( 2.*sqr(1.-sqrt(muj2)) );
double zm1 = ( 1.+mui2-mu2+muj2-2.*sqrt(muj2) -
rootOfKallen(mui2,mu2,sqr(1-sqrt(muj2))) * ptRatio) /
( 2.*sqr(1.-sqrt(muj2)) );
if ( zPrime > zp1 || zPrime < zm1 ) {
jacobian(0.0);
return false;
}
// Calculate A:=xij*w
double A = (1./(suijk*zPrime*(1.-zPrime))) * ( pt2/Qijk + zPrime*mu2 + (1.-zPrime)*mui2 - zPrime*(1.-zPrime)*Mui2 );
// Calculate y from A (can also write explicitly in terms of qt, zPrime and masses however we need A anyway)
double bar = 1.-mui2-mu2-muj2;
double y = (1./bar) * (A*suijk + Mui2 - mui2 - mu2 );
// kinematic phasespace boundaries for y
// same as in Dittmaier hep-ph/9904440v2 (equivalent to CS)
double ym = 2.*sqrt(mui2)*sqrt(mu2)/bar;
double yp = 1. - 2.*sqrt(muj2)*(1.-sqrt(muj2))/bar;
if ( y < ym || y > yp ) {
jacobian(0.0);
return false;
}
// Calculate xk and xij
double lambdaK = 1. + (Muj2/suijk);
double lambdaIJ = 1. + (Mui2/suijk);
double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muj2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muj2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muj2/suijk) );
double xij = 1. - ( (Muj2/suijk) * (1.-xk) / xk );
// Transform to standard z definition as used in the kernels (i.e. that used in CS and standard sudakov parametrisations)
double z = ( (zPrime*xij*xk*suijk/2.) + (Muj2/ ( 2.*xk*xij*suijk*zPrime))*(pt2/Qijk + mui2) ) /
( (xij*xk*suijk/2.) + (Muj2/(2.*xk*xij))*(Mui2/suijk + A) );
// These apply to z, not zPrime
double zm = ( (2.*mui2+bar*y)*(1.-y) - sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) /
( 2.*(1.-y)*(mui2+mu2+bar*y) );
double zp = ( (2.*mui2+bar*y)*(1.-y) + sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) /
( 2.*(1.-y)*(mui2+mu2+bar*y) );
if ( z < zm || z > zp ) {
jacobian(0.0);
return false;
}
double phi = 2.*Constants::pi*rphi;
double mapZJacobian;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emissionData()->id() != ParticleID::g ) {
mapZJacobian = 1.;
}
else {
mapZJacobian = z*(1.-z);
}
}
else {
mapZJacobian = 1.-z;
}
// Compute and store the jacobian
double jac = 0.0;
double propCntrb = 1./ ( 1. + (mui2+mu2-Mui2)/(bar*y) );
// TODO - SW - Tidy up notation everywhere alongside writing for the manual
// The full jacobian including the z->zprime jacobian
if ( theFullJacobian ) {
// Sort out variables
Energy2 sbar = Qijk*bar;
Energy2 sijk = Qijk*suijk;
Energy2 mi2 = Qijk*mui2;
Energy2 mj2 = Qijk*mu2;
Energy2 mk2 = Qijk*muj2;
// Compute dy/dzPrime and pt2* dy/dpt2
double dyBydzPrime = (1./sbar) * ( -pt2*(1.-2.*zPrime)/sqr(zPrime*(1.-zPrime)) - mi2/sqr(zPrime) + mj2/sqr(1.-zPrime) );
InvEnergy2 dyBydpt2 = 1./(sbar*zPrime*(1.-zPrime));
// Compute dA/dzPrime and dA/dpt2
double dABydzPrime = (sbar/sijk) * dyBydzPrime;
InvEnergy2 dABydpt2 = (sbar/sijk) * dyBydpt2;
// Compute dxk/dzPrime, dxk/dpt2, dxij/dzPrime and dxij/dpt2
double factor = (0.5/lambdaK) * (-1. - (1./sqrt( sqr(lambdaK + (mk2/sijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*mk2/sijk)) * (lambdaK + (mk2/sijk)*lambdaIJ - A));
double dxkBydzPrime = factor * dABydzPrime;
InvEnergy2 dxkBydpt2 = factor * dABydpt2;
double dxijBydzPrime = (mk2/sijk) * (1./sqr(xk)) * dxkBydzPrime;
InvEnergy2 dxijBydpt2 = (mk2/sijk) * (1./sqr(xk)) * dxkBydpt2;
Energy2 dqiDotqkBydzPrime = xij*xk*0.5*sijk + zPrime*dxijBydzPrime*xk*0.5*sijk + zPrime*xij*dxkBydzPrime*0.5*sijk
+ 0.5*(mk2/sijk)*(pt2 + mi2) * (-1./(xk*xij*sqr(zPrime)) - dxkBydzPrime/(zPrime*xij*sqr(xk)) - dxijBydzPrime/(zPrime*xk*sqr(xij)));
double dqiDotqkBydpt2 = dxijBydpt2*zPrime*xk*0.5*sijk + zPrime*xij*dxkBydpt2*0.5*sijk
+ (0.5*mk2/sijk) * (1./(zPrime*xk*xij)) * (1. + (pt2+mi2)*(-dxkBydpt2/xk - dxijBydpt2/xij) );
// Compute dzBydzPrime and dzBydpt2
Energy2 qiDotqk = (zPrime*xij*xk*sijk*0.5) + (mk2/ ( 2.*xk*xij*sijk*zPrime))*(pt2 + mi2);
double dzBydzPrime = (1./sbar) * ( 2.*qiDotqk*dyBydzPrime/sqr(1.-y) + (1./(1.-y)) * 2.*dqiDotqkBydzPrime );
InvEnergy2 dzBydpt2 = (1./sbar) * ( 2.*qiDotqk*dyBydpt2/sqr(1.-y) + (1./(1.-y)) * 2.*dqiDotqkBydpt2 );
double pt2Jac = pt2*abs(dzBydpt2*dyBydzPrime - dzBydzPrime*dyBydpt2);
// Include the other terms and calculate the jacobian
jac = propCntrb * bar / rootOfKallen(1.,Mui2,Muj2) * (1.-y)/y * pt2Jac;
}
else {
double jacPt2 = 1. / ( 1. + sqr(1.-zPrime)*Qijk*mui2/pt2 + zPrime*zPrime*Qijk*mu2/pt2 );
jac = propCntrb * bar / rootOfKallen(1.,Mui2,Muj2) * (1.-y) * jacPt2;
}
jacobian(jac * mapZJacobian * 2. * log(0.5 * generator()->maximumCMEnergy()/IRCutoff()) );
// Record the physical variables, as used by the CS kernel definitions
lastPt(pt);
lastZ(z);
lastPhi(phi);
// Record zPrime for use in kinematics generation
splittingParameters().clear();
splittingParameters().push_back(zPrime);
if ( theMCCheck ) {
theMCCheck->book(1.,1.,info.scale(),info.hardPt(),pt,z,jacobian());
}
return true;
}
void FIMassiveDecayKinematics::generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) {
-
// The only value stored in dInfo.lastSplittingParameters() should be zPrime
assert(dInfo.lastSplittingParameters().size() == 1 );
double zPrime = dInfo.lastSplittingParameters()[0];
Energy pt = dInfo.lastPt();
Energy2 pt2 = sqr(pt);
// Momentum of the recoil system
Lorentz5Momentum pk = pSpectator - pEmitter;
Lorentz5Momentum pij = pEmitter;
+
+ // scaled masses
+ double Mui2 = sqr(dInfo.emitterMass() / dInfo.scale());
+ double Muk2 = sqr(dInfo.recoilMass() / dInfo.scale());
+ //double muk2 = Muk2;
- // scaled masses
- double mui2 = sqr( dInfo.emitterData()->mass() / dInfo.scale() );
- double mu2 = sqr( dInfo.emissionData()->mass() / dInfo.scale() );
- double muj2 = sqr( dInfo.recoilMass() / dInfo.scale() );
-
- double Mui2 = 0.;
- if ( dInfo.emitterData()->id() + dInfo.emissionData()->id() == 0 ) Mui2 = 0.; // gluon
- else Mui2 = mui2; // (anti)quark
- double Muj2 = muj2;
+ Energy mi = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(dInfo.emitterData()->id()) == abs(dInfo.emissionData()->id()) ) {
+ mi = dInfo.emitterData()->mass();
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi = dInfo.emitterMass();
+ }
+ double mui2 = sqr(mi/dInfo.scale());
+ double mu2 = sqr(dInfo.emissionData()->mass()/dInfo.scale() );
Energy2 Qijk = sqr(dInfo.scale());
- double suijk = 0.5*( 1. - Mui2 - Muj2 + sqrt( sqr(1.-Mui2-Muj2) - 4.*Mui2*Muj2 ) );
+ double suijk = 0.5*( 1. - Mui2 - Muk2 + sqrt( sqr(1.-Mui2-Muk2) - 4.*Mui2*Muk2 ) );
double suijk2 = sqr(suijk);
// Calculate A:=xij*w
double A = (1./(suijk*zPrime*(1.-zPrime))) * ( pt2/Qijk + zPrime*mu2 + (1.-zPrime)*mui2 - zPrime*(1.-zPrime)*Mui2 );
// Calculate the scaling factors, xk and xij
- double lambdaK = 1. + (Muj2/suijk);
+ double lambdaK = 1. + (Muk2/suijk);
double lambdaIJ = 1. + (Mui2/suijk);
- double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muj2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muj2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muj2/suijk) );
- double xij = 1. - ( (Muj2/suijk) * (1.-xk) / xk );
+ double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muk2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muk2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muk2/suijk) );
+ double xij = 1. - ( (Muk2/suijk) * (1.-xk) / xk );
// Construct reference momenta nk, nij, nt
- Lorentz5Momentum nij = ( suijk2 / (suijk2-Mui2*Muj2) ) * (pij - (Mui2/suijk)*pk);
- Lorentz5Momentum nk = ( suijk2 / (suijk2-Mui2*Muj2) ) * (pk - (Muj2/suijk)*pij);
+ Lorentz5Momentum nij = ( suijk2 / (suijk2-Mui2*Muk2) ) * (pij - (Mui2/suijk)*pk);
+ Lorentz5Momentum nk = ( suijk2 / (suijk2-Mui2*Muk2) ) * (pk - (Muk2/suijk)*pij);
// Following notation in notes, qt = sqrt(wt)*nt
Lorentz5Momentum qt = getKt(nij,nk,pt,dInfo.lastPhi());
// Construct qij, qk, qi and qj
Lorentz5Momentum qij = xij*nij + (Mui2/(xij*suijk))*nk;
- Lorentz5Momentum qk = xk*nk + (Muj2/(xk*suijk))*nij;
+ Lorentz5Momentum qk = xk*nk + (Muk2/(xk*suijk))*nij;
// No need to actually calculate nt and wt:
Lorentz5Momentum qi = zPrime*qij + ((pt2/Qijk + mui2 - zPrime*zPrime*Mui2)/(xij*suijk*zPrime))*nk + qt;
Lorentz5Momentum qj = (1.-zPrime)*qij + ((pt2/Qijk + mu2 - sqr(1.-zPrime)*Mui2)/(xij*suijk*(1.-zPrime)))*nk - qt;
+
+ qi.setMass(mi);
+ qi.rescaleEnergy();
+
+ qj.setMass(dInfo.emissionData()->mass());
+ qj.rescaleEnergy();
+
emitterMomentum(qi);
emissionMomentum(qj);
spectatorMomentum(pSpectator);
// Required for absorbing recoil in DipoleEventRecord::update
splitRecoilMomentum(qk);
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FIMassiveDecayKinematics::persistentOutput(PersistentOStream & os) const {
os << theFullJacobian;
}
void FIMassiveDecayKinematics::persistentInput(PersistentIStream & is, int) {
is >> theFullJacobian;
}
ClassDescription<FIMassiveDecayKinematics> FIMassiveDecayKinematics::initFIMassiveDecayKinematics;
// Definition of the static class description member.
void FIMassiveDecayKinematics::Init() {
static ClassDocumentation<FIMassiveDecayKinematics> documentation
("FIMassiveDecayKinematics implements implements massive splittings "
"off a final-initial decay dipole.");
static Switch<FIMassiveDecayKinematics,bool> interfaceFullJacobian
("FullJacobian",
"Use the full jacobian expression for the FI Decay kinematics.",
&FIMassiveDecayKinematics::theFullJacobian, true, false, false);
static SwitchOption interfaceFullJacobianYes
(interfaceFullJacobian,
"Yes",
"Use the full jacobian.",
true);
static SwitchOption interfaceFullJacobianNo
(interfaceFullJacobian,
"No",
"Do not use the full jacobian.",
false);
interfaceFullJacobian.rank(-1);
}
diff --git a/Shower/Dipole/Kinematics/FIMassiveDecayKinematics.h b/Shower/Dipole/Kinematics/FIMassiveDecayKinematics.h
--- a/Shower/Dipole/Kinematics/FIMassiveDecayKinematics.h
+++ b/Shower/Dipole/Kinematics/FIMassiveDecayKinematics.h
@@ -1,300 +1,309 @@
// -*- C++ -*-
//
// FIMassiveDecayKinematics.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_FIMassiveDecayKinematics_H
#define HERWIG_FIMassiveDecayKinematics_H
//
// This is the declaration of the FIMassiveDecayKinematics class.
//
#include "DipoleSplittingKinematics.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Utilities/UtilityBase.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Stephen Webster
*
* \brief FIMassiveDecayKinematics implements massive splittings
* off a final-initial decay dipole.
*
*/
class FIMassiveDecayKinematics: public DipoleSplittingKinematics {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
FIMassiveDecayKinematics();
/**
* The destructor.
*/
virtual ~FIMassiveDecayKinematics();
//@}
public:
/**
* Return the boundaries in between the evolution
* variable random number is to be sampled; the lower
* cuoff is assumed to correspond to the infrared cutoff.
*/
virtual pair<double,double> kappaSupport(const DipoleSplittingInfo& dIndex) const;
/**
* Return the boundaries in between the momentum
* fraction random number is to be sampled.
*/
virtual pair<double,double> xiSupport(const DipoleSplittingInfo& dIndex) const;
/**
* Return the boundaries on the momentum fraction
*/
virtual pair<double,double> zBoundaries(Energy,
const DipoleSplittingInfo&,
const DipoleSplittingKernel&) const {
return {0.0,1.0};
}
/**
* Return the dipole scale associated to the
* given pair of emitter and spectator. This
* should be the invariant mass or absolute value
* final/final or initial/initial and the absolute
* value of the momentum transfer for intial/final or
* final/initial dipoles.
*/
virtual Energy dipoleScale(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const;
/**
* Return the mass of the system absorbing
* the recoil in the dipole splitting.
* This is only used in decay dipoles.
*/
virtual Energy recoilMassKin(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const;
/**
* Return the maximum pt for the given dipole scale.
*/
virtual Energy ptMax(Energy dScale,
double emX, double specX,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const;
-
+
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy dScale,
+ double, double,
+ const DipoleIndex& dIndex,
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr spectator) const;
+
/**
* Return the maximum virtuality for the given dipole scale.
*/
virtual Energy QMax(Energy dScale,
double emX, double specX,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const;
/**
* Return the maximum pt for the given dipole scale.
*/
virtual Energy ptMax(Energy,
double, double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
// Only the DipoleSplittingInfo version should be used for the decays.
assert(false);
return ZERO;
}
/**
* Return the maximum virtuality for the given dipole scale.
*/
virtual Energy QMax(Energy,
double, double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
// Only the DipoleSplittingInfo version should be used for the decays.
assert(false);
return ZERO;
}
/**
* Return the pt given a virtuality.
*/
virtual Energy PtFromQ(Energy scale, const DipoleSplittingInfo&) const;
/**
* Return the virtuality given a pt.
*/
virtual Energy QFromPt(Energy scale, const DipoleSplittingInfo&) const;
/**
* Return the random number associated to
* the given pt.
*/
virtual double ptToRandom(Energy pt, Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel& split) const;
/**
* Generate splitting variables given three random numbers
* and the momentum fractions of the emitter and spectator.
* Return true on success.
*/
virtual bool generateSplitting(double kappa, double xi, double phi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel& split);
/**
* Generate the full kinematics given emitter and
* spectator momentum and a previously completeted
* DipoleSplittingInfo object.
*/
virtual void generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo);
/*
* Return true if this splitting is of a dipole which contains
* a decayed parton and requires the remnant to absorb the recoil.
*/
virtual bool isDecay() const { return true; }
/**
* Perform the recoil in the case of a decayed parton
*/
virtual void decayRecoil ( PList& recoilSystem ) {
PList::iterator beginRecoil = recoilSystem.begin();
PList::iterator endRecoil = recoilSystem.end();
const ThreeVector<Energy> transformMom = splitRecoilMomentum().vect();
ThePEG::UtilityBase::setMomentum(beginRecoil, endRecoil, transformMom );
}
public:
/**
* Triangular / Kallen function
*/
template <class T>
inline double rootOfKallen (T a, T b, T c) const {
double sres=a*a + b*b + c*c - 2.*( a*b+a*c+b*c );
return sres>0.?sqrt( sres ):0.; }
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<FIMassiveDecayKinematics> initFIMassiveDecayKinematics;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FIMassiveDecayKinematics & operator=(const FIMassiveDecayKinematics &);
/**
* Option to use the full jacobian, including the z->zprime jacobian.
**/
bool theFullJacobian;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of FIMassiveDecayKinematics. */
template <>
struct BaseClassTrait<Herwig::FIMassiveDecayKinematics,1> {
/** Typedef of the first base class of FIMassiveDecayKinematics. */
typedef Herwig::DipoleSplittingKinematics NthBase;
};
/** This template specialization informs ThePEG about the name of
* the FIMassiveDecayKinematics class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::FIMassiveDecayKinematics>
: public ClassTraitsBase<Herwig::FIMassiveDecayKinematics> {
/** Return a platform-independent class name */
static string className() { return "Herwig::FIMassiveDecayKinematics"; }
/**
* The name of a file containing the dynamic library where the class
* FIMassiveDecayKinematics is implemented. It may also include several, space-separated,
* libraries if the class FIMassiveDecayKinematics depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_FIMassiveDecayKinematics_H */
diff --git a/Shower/Dipole/Kinematics/FIMassiveKinematics.cc b/Shower/Dipole/Kinematics/FIMassiveKinematics.cc
--- a/Shower/Dipole/Kinematics/FIMassiveKinematics.cc
+++ b/Shower/Dipole/Kinematics/FIMassiveKinematics.cc
@@ -1,312 +1,385 @@
// -*- C++ -*-
//
// FIMassiveKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FIMassiveKinematics class.
//
#include "FIMassiveKinematics.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
#include "Herwig/Shower/Dipole/Kernels/DipoleSplittingKernel.h"
using namespace Herwig;
FIMassiveKinematics::FIMassiveKinematics()
: DipoleSplittingKinematics() {}
FIMassiveKinematics::~FIMassiveKinematics() {}
IBPtr FIMassiveKinematics::clone() const {
return new_ptr(*this);
}
IBPtr FIMassiveKinematics::fullclone() const {
return new_ptr(*this);
}
pair<double,double> FIMassiveKinematics::kappaSupport(const DipoleSplittingInfo&) const {
return {0.0,1.0};
}
pair<double,double> FIMassiveKinematics::xiSupport(const DipoleSplittingInfo& split) const {
double c = sqrt(1.-4.*sqr(IRCutoff()/generator()->maximumCMEnergy()));
if ( split.index().emitterData()->id() == ParticleID::g ) {
if ( split.emissionData()->id() != ParticleID::g )
return {0.5*(1.-c),0.5*(1.+c)};
double b = log((1.+c)/(1.-c));
return {-b,b};
}
return {-log(0.5*(1.+c)),-log(0.5*(1.-c))};
}
// sbar
Energy FIMassiveKinematics::dipoleScale(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const {
return sqrt(2.*(pEmitter*pSpectator));
}
Energy FIMassiveKinematics::ptMax(Energy dScale,
- double, double specX,
- const DipoleIndex& ind,
- const DipoleSplittingKernel& split) const {
- Energy mi = split.emitter(ind)->mass(), mj = split.emission(ind)->mass();
- Energy2 mi2 = sqr(mi), mj2 = sqr(mj);
- Energy2 mij2 = split.emitter(ind)->id() + split.emission(ind)->id() == 0 ?
- 0.*GeV2 : mi2;
+ double, double specX,
+ const DipoleSplittingInfo& dInfo,
+ const DipoleSplittingKernel& split) const {
+
+ DipoleIndex ind = dInfo.index();
+
+ Energy2 mij2 = sqr(dInfo.emitterMass());
+ Energy2 mi2 = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(split.emitter(ind)->id()) == abs(split.emission(ind)->id()) ) {
+ mi2 = sqr(split.emitter(ind)->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = mij2;
+ }
+
+ Energy2 mj2 = sqr(split.emission(ind)->mass());
Energy2 sPrime = sqr(dScale) * (1.-specX)/specX + mij2;
return .5 * sqrt(sPrime) * rootOfKallen( sPrime/sPrime, mi2/sPrime, mj2/sPrime );
}
-// what is this? in FF it is given by y+*dScale = sqrt( 2qi*q / bar )->max
+
+Energy FIMassiveKinematics::ptMax(Energy dScale,
+ double, double specX,
+ const DipoleIndex& ind,
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr) const {
+
+ Energy2 mij2 = sqr(emitter->mass());
+ Energy2 mi2 = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(split.emitter(ind)->id()) == abs(split.emission(ind)->id()) ) {
+ mi2 = sqr(split.emitter(ind)->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = mij2;
+ }
+ Energy2 mj2 = sqr(split.emission(ind)->mass());
+
+ Energy2 sPrime = sqr(dScale) * (1.-specX)/specX + mij2;
+ return .5 * sqrt(sPrime) * rootOfKallen( sPrime/sPrime, mi2/sPrime, mj2/sPrime );
+}
+
+
+
Energy FIMassiveKinematics::QMax(Energy dScale,
- double, double specX,
- const DipoleIndex&,
- const DipoleSplittingKernel&) const {
+ double, double specX,
+ const DipoleSplittingInfo&,
+ const DipoleSplittingKernel&) const {
generator()->log() << "FIMassiveKinematics::QMax called.\n" << flush;
assert(false && "implementation missing");
// this is sqrt( 2qi*q ) -> max;
return dScale * sqrt((1.-specX)/specX);
}
Energy FIMassiveKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const {
// from Martin's thesis
double z = split.lastZ();
- Energy mi = split.emitterData()->mass();
- Energy mj = split.emissionData()->mass();
- Energy2 pt2 = z*(1.-z)*sqr(scale) - (1-z)*sqr(mi) - z*sqr(mj);
+
+ // masses
+ Energy2 mi2 = ZERO;;
+ if ( abs(split.emitterData()->id()) == abs(split.emissionData()->id()) ) {
+ mi2 = sqr(split.emitterData()->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = sqr(split.emitterMass());
+ }
+ Energy2 mj2 = sqr(split.emissionData()->mass());
+
+ Energy2 pt2 = z*(1.-z)*sqr(scale) - (1-z)*mi2 - z*mj2;
assert(pt2 >= ZERO);
return sqrt(pt2);
}
Energy FIMassiveKinematics::QFromPt(Energy pt, const DipoleSplittingInfo& split) const {
// from Martin's thesis
double z = split.lastZ();
- Energy mi = split.emitterData()->mass();
- Energy mj = split.emissionData()->mass();
- Energy2 Q2 = (sqr(pt) + (1-z)*sqr(mi) + z*sqr(mj))/(z*(1.-z));
+
+ // masses
+ Energy2 mi2 = ZERO;;
+ if ( abs(split.emitterData()->id()) == abs(split.emissionData()->id()) ) {
+ mi2 = sqr(split.emitterData()->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = sqr(split.emitterMass());
+ }
+ Energy2 mj2 = sqr(split.emissionData()->mass());
+
+ Energy2 Q2 = (sqr(pt) + (1-z)*mi2 + z*mj2)/(z*(1.-z));
return sqrt(Q2);
}
double FIMassiveKinematics::ptToRandom(Energy pt, Energy,
double,double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return log(pt/IRCutoff()) / log(0.5 * generator()->maximumCMEnergy()/IRCutoff());
}
bool FIMassiveKinematics::generateSplitting(double kappa, double xi, double rphi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel&) {
if ( info.spectatorX() < xMin() ) {
jacobian(0.0);
return false;
}
Energy pt = IRCutoff() * pow(0.5 * generator()->maximumCMEnergy()/IRCutoff(),kappa);
if ( pt > info.hardPt() || pt < IRCutoff() ) {
jacobian(0.0);
return false;
}
double z;
double mapZJacobian;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emissionData()->id() != ParticleID::g ) {
z = xi;
mapZJacobian = 1.;
} else {
z = exp(xi)/(1.+exp(xi));
mapZJacobian = z*(1.-z);
}
} else {
z = 1.-exp(-xi);
mapZJacobian = 1.-z;
}
// Construct mass squared variables
- Energy2 mi2 = sqr(info.emitterData()->mass());
+ Energy2 mij2 = sqr(info.emitterMass());
+ Energy2 mi2 = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(info.emitterData()->id()) == abs(info.emissionData()->id()) ) {
+ mi2 = sqr(info.emitterData()->mass());
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi2 = mij2;
+ }
Energy2 mj2 = sqr(info.emissionData()->mass());
- Energy2 mij2 = info.emitterData()->id()+info.emissionData()->id() == 0 ?
- 0.*GeV2 : mi2;
+
Energy2 pt2 = sqr(pt);
// 2 pij.pb
Energy2 sbar = sqr(info.scale());
// Compute x
double x = 1. / ( 1. +
( pt2 + (1.-z)*mi2 + z*mj2 - z*(1.-z)*mij2 ) /
( z*(1.-z)*sbar ) );
// Check the limit on x
double xs = info.spectatorX();
if ( x < xs ) {
jacobian(0.0);
return false;
}
// Compute and check the z limits
Energy2 sPrime = sbar * (1.-xs)/xs + mij2;
Energy hard=info.hardPt();
if(openZBoundaries()==1){
hard=.5 * sqrt(sPrime) * rootOfKallen( sPrime/sPrime, mi2/sPrime, mj2/sPrime );
}
if(openZBoundaries()==2){
Energy2 s = mij2 - sbar;
hard=min(0.5*sqrt(sPrime) *
rootOfKallen( sPrime/sPrime, mi2/sPrime, mj2/sPrime ) ,
0.5*sqrt(s) *
rootOfKallen( s/s, mi2/s, mj2/s ));
}
double ptRatio = sqrt(1.-sqr(pt/hard));
double zm1 = .5*( 1.+(mi2-mj2)/sPrime - rootOfKallen(sPrime/sPrime,mi2/sPrime,mj2/sPrime) * ptRatio);
double zp1 = .5*( 1.+(mi2-mj2)/sPrime + rootOfKallen(sPrime/sPrime,mi2/sPrime,mj2/sPrime) * ptRatio);
if ( z > zp1 || z < zm1 ) {
jacobian(0.0);
return false;
}
// additional purely kinematic constraints from
// the integration limits in Catani-Seymour
double mui2CS = x*mi2/sbar;
double muj2CS = x*mj2/sbar;
double muij2CS = x*mij2/sbar;
// Limit on x
double xp = 1. + muij2CS - sqr(sqrt(mui2CS)+sqrt(muj2CS));
if (x > xp ) {
jacobian(0.0);
return false;
}
// Limit on z
double root = sqr(1.-x+muij2CS-mui2CS-muj2CS)-4.*mui2CS*muj2CS;
if( root < 0. && root>-1e-10 ) {
// assert(false);
root = 0.;
}
else if (root <0. ) {
jacobian(0.0);
return false;
}
root = sqrt(root);
double zm2 = .5*( 1.-x+muij2CS+mui2CS-muj2CS - root ) / (1.-x+muij2CS);
double zp2 = .5*( 1.-x+muij2CS+mui2CS-muj2CS + root ) / (1.-x+muij2CS);
if ( z > zp2 || z < zm2 ) {
jacobian(0.0);
return false;
}
// Store the splitting variables
double phi = 2.*Constants::pi*rphi;
// Compute and store the jacobian
double jacPt2 = 1. / ( 1. + (1.-z)*mi2/pt2 + z*mj2/pt2 - z*(1.-z)*mij2/pt2 );
jacobian( jacPt2 * mapZJacobian * 2.*log(0.5 * generator()->maximumCMEnergy()/IRCutoff()));
lastPt(pt);
lastZ(z);
lastPhi(phi);
lastSpectatorZ(x);
if ( theMCCheck )
theMCCheck->book(1.,info.spectatorX(),info.scale(),info.hardPt(),pt,z,jacobian());
return true;
}
void FIMassiveKinematics::generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) {
-
+
// Get splitting variables
Energy pt = dInfo.lastPt();
double z = dInfo.lastZ();
// Compute sqr scales
Energy2 pt2 = sqr(pt);
Energy2 sbar = sqr(dInfo.scale());
Lorentz5Momentum kt =
getKt (pSpectator, pEmitter, pt, dInfo.lastPhi(),true);
- Energy2 mi2 = sqr(dInfo.emitterData()->mass());
+ // Construct mass squared variables
+ Energy2 mij2 = sqr(dInfo.emitterMass());
+ Energy mi = ZERO;
+ // g->gg and g->qqbar
+ if ( abs(dInfo.emitterData()->id()) == abs(dInfo.emissionData()->id()) ) {
+ mi = dInfo.emitterData()->mass();
+ }
+ // Otherwise have X->Xg (should work for SUSY)
+ else {
+ mi = dInfo.emitterMass();
+ }
+ Energy2 mi2 = sqr(mi);
Energy2 mj2 = sqr(dInfo.emissionData()->mass());
- Energy2 mij2 = dInfo.emitterData()->id() + dInfo.emissionData()->id() == 0 ?
- 0.*GeV2 : mi2;
-
+
double xInv = ( 1. +
(pt2+(1.-z)*mi2+z*mj2-z*(1.-z)*mij2) /
(z*(1.-z)*sbar) );
Lorentz5Momentum em = z*pEmitter +
(pt2+mi2-z*z*mij2)/(z*sbar)*pSpectator + kt;
- em.setMass(sqrt(mi2));
+ Lorentz5Momentum emm = (1.-z)*pEmitter +
+ (pt2+mj2-sqr(1.-z)*mij2)/((1.-z)*sbar)*pSpectator - kt;
+ Lorentz5Momentum spe = xInv*pSpectator;
+
+ em.setMass(mi);
em.rescaleEnergy();
- Lorentz5Momentum emm = (1.-z)*pEmitter +
- (pt2+mj2-sqr(1.-z)*mij2)/((1.-z)*sbar)*pSpectator - kt;
- emm.setMass(sqrt(mj2));
+ emm.setMass(dInfo.emissionData()->mass());
emm.rescaleEnergy();
-
- Lorentz5Momentum spe = xInv*pSpectator;
+
spe.setMass(ZERO);
spe.rescaleEnergy();
-
+
emitterMomentum(em);
emissionMomentum(emm);
spectatorMomentum(spe);
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void FIMassiveKinematics::persistentOutput(PersistentOStream & ) const {
}
void FIMassiveKinematics::persistentInput(PersistentIStream & , int) {
}
ClassDescription<FIMassiveKinematics> FIMassiveKinematics::initFIMassiveKinematics;
// Definition of the static class description member.
void FIMassiveKinematics::Init() {
static ClassDocumentation<FIMassiveKinematics> documentation
("FIMassiveKinematics implements massless splittings "
"off a final-initial dipole.");
}
diff --git a/Shower/Dipole/Kinematics/FIMassiveKinematics.h b/Shower/Dipole/Kinematics/FIMassiveKinematics.h
--- a/Shower/Dipole/Kinematics/FIMassiveKinematics.h
+++ b/Shower/Dipole/Kinematics/FIMassiveKinematics.h
@@ -1,246 +1,281 @@
// -*- C++ -*-
//
// FILightKinematics.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_FILightKinematics_H
#define HERWIG_FILightKinematics_H
//
// This is the declaration of the FILightKinematics class.
//
#include "DipoleSplittingKinematics.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer, Martin Stoll
*
* \brief FIMassiveKinematics implements massless splittings
* off a final-initial dipole.
*
*/
class FIMassiveKinematics: public DipoleSplittingKinematics {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
FIMassiveKinematics();
/**
* The destructor.
*/
virtual ~FIMassiveKinematics();
//@}
public:
/**
* Return the boundaries in between the evolution
* variable random number is to be sampled; the lower
* cuoff is assumed to correspond to the infrared cutoff.
*/
virtual pair<double,double> kappaSupport(const DipoleSplittingInfo& dIndex) const;
/**
* Return the boundaries in between the momentum
* fraction random number is to be sampled.
*/
virtual pair<double,double> xiSupport(const DipoleSplittingInfo& dIndex) const;
/**
* Return the boundaries on the momentum fraction
*/
virtual pair<double,double> zBoundaries(Energy,
const DipoleSplittingInfo&,
const DipoleSplittingKernel&) const {
return {0.0,1.0};
}
/**
* Return the dipole scale associated to the
* given pair of emitter and spectator. This
* should be the invariant mass or absolute value
* final/final or initial/initial and the absolute
* value of the momentum transfer for intial/final or
* final/initial dipoles.
*/
virtual Energy dipoleScale(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const;
/**
* Return the maximum pt for the given dipole scale.
*/
virtual Energy ptMax(Energy dScale,
double emX, double specX,
+ const DipoleSplittingInfo& dInfo,
+ const DipoleSplittingKernel& split) const;
+
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy dScale,
+ double, double,
const DipoleIndex& dIndex,
- const DipoleSplittingKernel&) const;
-
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr) const;
+
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy,
+ double, double,
+ const DipoleIndex&,
+ const DipoleSplittingKernel&) const {
+ // Only the DipoleSplittingInfo version should be used for massive
+ // dipoles, for now anyway.
+ assert(false);
+ return ZERO;
+ }
+
/**
* Return the maximum virtuality for the given dipole scale.
*/
virtual Energy QMax(Energy dScale,
double emX, double specX,
- const DipoleIndex& dIndex,
- const DipoleSplittingKernel&) const;
-
+ const DipoleSplittingInfo& dInfo,
+ const DipoleSplittingKernel& split) const;
+
+ /**
+ * Return the maximum virtuality for the given dipole scale.
+ */
+ virtual Energy QMax(Energy,
+ double, double,
+ const DipoleIndex&,
+ const DipoleSplittingKernel&) const {
+ // Only the DipoleSplittingInfo version should be used for massive
+ // dipoles, for now anyway.
+ assert(false);
+ return ZERO;
+ }
+
/**
* Return the pt given a virtuality.
*/
virtual Energy PtFromQ(Energy scale, const DipoleSplittingInfo&) const;
/**
* Return the virtuality given a pt.
*/
virtual Energy QFromPt(Energy scale, const DipoleSplittingInfo&) const;
/**
* Return the random number associated to
* the given pt.
*/
virtual double ptToRandom(Energy pt, Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel&) const;
/**
* Generate splitting variables given three random numbers
* and the momentum fractions of the emitter and spectator.
* Return true on success.
*/
virtual bool generateSplitting(double kappa, double xi, double phi,
DipoleSplittingInfo& dIndex,
const DipoleSplittingKernel&);
/**
* Generate the full kinematics given emitter and
* spectator momentum and a previously completeted
* DipoleSplittingInfo object.
*/
virtual void generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo);
public:
/**
* Triangular / Kallen function
*/
template <class T>
inline double rootOfKallen (T a, T b, T c) const {
double sres=a*a + b*b + c*c - 2.*( a*b+a*c+b*c );
return sres>0.?sqrt( sres ):0.; }
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<FIMassiveKinematics> initFIMassiveKinematics;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FIMassiveKinematics & operator=(const FIMassiveKinematics &);
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of FIMassiveKinematics. */
template <>
struct BaseClassTrait<Herwig::FIMassiveKinematics,1> {
/** Typedef of the first base class of FIMassiveKinematics. */
typedef Herwig::DipoleSplittingKinematics NthBase;
};
/** This template specialization informs ThePEG about the name of
* the FIMassiveKinematics class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::FIMassiveKinematics>
: public ClassTraitsBase<Herwig::FIMassiveKinematics> {
/** Return a platform-independent class name */
static string className() { return "Herwig::FIMassiveKinematics"; }
/**
* The name of a file containing the dynamic library where the class
* FIMassiveKinematics is implemented. It may also include several, space-separated,
* libraries if the class FIMassiveKinematics depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_FIMassiveKinematics_H */
diff --git a/Shower/Dipole/Kinematics/IFLightKinematics.cc b/Shower/Dipole/Kinematics/IFLightKinematics.cc
--- a/Shower/Dipole/Kinematics/IFLightKinematics.cc
+++ b/Shower/Dipole/Kinematics/IFLightKinematics.cc
@@ -1,263 +1,255 @@
// -*- C++ -*-
//
// IFLightKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the IFLightKinematics class.
//
#include "IFLightKinematics.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
using namespace Herwig;
IFLightKinematics::IFLightKinematics()
: DipoleSplittingKinematics(), theCollinearScheme(true) {}
IFLightKinematics::~IFLightKinematics() {}
IBPtr IFLightKinematics::clone() const {
return new_ptr(*this);
}
IBPtr IFLightKinematics::fullclone() const {
return new_ptr(*this);
}
Energy IFLightKinematics::ptMax(Energy dScale,
double emX, double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return dScale * sqrt((1.-emX)/emX) /2.;
}
Energy IFLightKinematics::QMax(Energy,
double, double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
assert(false && "add this");
return 0.0*GeV;
}
Energy IFLightKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale*sqrt(1.-z);
}
Energy IFLightKinematics::QFromPt(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale/sqrt(1.-z);
}
pair<double,double> IFLightKinematics::zBoundaries(Energy pt,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel&) const {
double x = dInfo.emitterX();
Energy hard=dInfo.hardPt();
if(openZBoundaries()==1)hard=dInfo.scale() * sqrt((1.-x)/x) /2.;
if(openZBoundaries()==2)hard=dInfo.scale() * min(1.,sqrt((1.-x)/x) /2.);
if(hard<pt)return {0.5*(1.+x),0.5*(1.+x)};
double s = sqrt(1.-sqr(pt/hard));
return {0.5*(1.+x-(1.-x)*s),0.5*(1.+x+(1.-x)*s)};
}
bool IFLightKinematics::generateSplitting(double kappa, double xi, double rphi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel& split) {
if ( info.emitterX() < xMin() ) {
jacobian(0.0);
return false;
}
double weight = 1.0;
Energy pt = generatePt(kappa,info.scale(),
info.emitterX(),info.spectatorX(),
info.index(),split,
weight);
if ( pt < IRCutoff() || pt > info.hardPt() ) {
jacobian(0.0);
return false;
}
double z = 0.0;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emitterData()->id() == ParticleID::g ) {
z = generateZ(xi,pt,OneOverZOneMinusZ,
info,split,weight);
} else {
z = generateZ(xi,pt,OneOverZ,
info,split,weight);
}
}
if ( info.index().emitterData()->id() != ParticleID::g ) {
if ( info.emitterData()->id() != ParticleID::g ) {
z = generateZ(xi,pt,OneOverOneMinusZ,
info,split,weight);
} else {
z = generateZ(xi,pt,FlatZ,
info,split,weight);
}
}
if ( weight == 0. && z == -1. ) {
jacobian(0.0);
return false;
}
double ratio = sqr(pt/info.scale());
double rho = 1. - 4.*ratio*z*(1.-z)/sqr(1.-z+ratio);
if ( rho < 0.0 ) {
jacobian(0.0);
return false;
}
double x = 0.5*((1.-z+ratio)/ratio)*(1.-sqrt(rho));
double u = 0.5*((1.-z+ratio)/(1.-z))*(1.-sqrt(rho));
if ( x < info.emitterX() || x > 1. ||
u < 0. || u > 1. ) {
jacobian(0.0);
return false;
}
double phi = 2.*Constants::pi*rphi;
jacobian(weight*(1./(u+x-2.*u*x)));
lastPt(pt);
lastZ(z);
lastPhi(phi);
lastEmitterZ(x);
if ( theMCCheck )
theMCCheck->book(info.emitterX(),1.,info.scale(),info.hardPt(),pt,z,jacobian());
return true;
}
void IFLightKinematics::generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) {
Energy pt = dInfo.lastPt();
double z = dInfo.lastZ();
double ratio = sqr(pt)/(2.*pEmitter*pSpectator);
double rho = 1. - 4.*ratio*z*(1.-z)/sqr(1.-z+ratio);
double x = 0.5*((1.-z+ratio)/ratio)*(1.-sqrt(rho));
double u = 0.5*((1.-z+ratio)/(1.-z))*(1.-sqrt(rho));
Lorentz5Momentum kt =
getKt (pEmitter, pSpectator, pt, dInfo.lastPhi(),true);
+ // Initialise the momenta
Lorentz5Momentum em;
Lorentz5Momentum emm;
Lorentz5Momentum spe;
if ( !theCollinearScheme &&
x > u && (1.-x)/(x-u) < 1. ) {
assert(false);
- em =
- ((1.-u)/(x-u))*pEmitter + ((u/x)*(1.-x)/(x-u))*pSpectator - kt/(x-u);
- em.setMass(0.*GeV);
- em.rescaleEnergy();
-
- emm =
- ((1.-x)/(x-u))*pEmitter + ((u/x)*(1.-u)/(x-u))*pSpectator - kt/(x-u);
- emm.setMass(0.*GeV);
- emm.rescaleEnergy();
-
- spe =
- (1.-u/x)*pSpectator;
- spe.setMass(0.*GeV);
- spe.rescaleEnergy();
+ em = ((1.-u)/(x-u))*pEmitter + ((u/x)*(1.-x)/(x-u))*pSpectator - kt/(x-u);
+ emm = ((1.-x)/(x-u))*pEmitter + ((u/x)*(1.-u)/(x-u))*pSpectator - kt/(x-u);
+ spe = (1.-u/x)*pSpectator;
} else {
em = (1./x)*pEmitter;
+ emm = ((1.-x)*(1.-u)/x)*pEmitter + u*pSpectator + kt;
+ spe = ((1.-x)*u/x)*pEmitter + (1.-u)*pSpectator - kt;
+ }
- emm = ((1.-x)*(1.-u)/x)*pEmitter + u*pSpectator + kt;
- emm.setMass(0.*GeV);
- emm.rescaleEnergy();
+ em.setMass(ZERO);
+ em.rescaleEnergy();
- spe = ((1.-x)*u/x)*pEmitter + (1.-u)*pSpectator - kt;
- spe.setMass(0.*GeV);
- spe.rescaleEnergy();
+ emm.setMass(ZERO);
+ emm.rescaleEnergy();
- }
-
+ spe.setMass(ZERO);
+ spe.rescaleEnergy();
+
emitterMomentum(em);
emissionMomentum(emm);
spectatorMomentum(spe);
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void IFLightKinematics::persistentOutput(PersistentOStream &) const {
//os << theCollinearScheme;
}
void IFLightKinematics::persistentInput(PersistentIStream &, int) {
//is >> theCollinearScheme;
}
ClassDescription<IFLightKinematics> IFLightKinematics::initIFLightKinematics;
// Definition of the static class description member.
void IFLightKinematics::Init() {
static ClassDocumentation<IFLightKinematics> documentation
("IFLightKinematics implements massless splittings "
"off a initial-final dipole.");
/*
static Switch<IFLightKinematics,bool> interfaceCollinearScheme
("CollinearScheme",
"[experimental] Switch on or off the collinear scheme",
&IFLightKinematics::theCollinearScheme, false, false, false);
static SwitchOption interfaceCollinearSchemeYes
(interfaceCollinearScheme,
"Yes",
"Switch on the collinear scheme.",
true);
static SwitchOption interfaceCollinearSchemeNo
(interfaceCollinearScheme,
"No",
"Switch off the collinear scheme",
false);
interfaceCollinearScheme.rank(-1);
*/
}
diff --git a/Shower/Dipole/Kinematics/IFMassiveKinematics.cc b/Shower/Dipole/Kinematics/IFMassiveKinematics.cc
--- a/Shower/Dipole/Kinematics/IFMassiveKinematics.cc
+++ b/Shower/Dipole/Kinematics/IFMassiveKinematics.cc
@@ -1,362 +1,373 @@
// -*- C++ -*-
//
// IFMassiveKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the IFMassiveKinematics class.
//
#include "IFMassiveKinematics.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
#include "Herwig/Shower/Dipole/Kernels/DipoleSplittingKernel.h"
using namespace Herwig;
IFMassiveKinematics::IFMassiveKinematics()
: DipoleSplittingKinematics(), theCollinearScheme(true) {}
IFMassiveKinematics::~IFMassiveKinematics() {}
IBPtr IFMassiveKinematics::clone() const {
return new_ptr(*this);
}
IBPtr IFMassiveKinematics::fullclone() const {
return new_ptr(*this);
}
pair<double,double> IFMassiveKinematics::kappaSupport(const DipoleSplittingInfo&) const {
return {0.0,1.0};
}
pair<double,double> IFMassiveKinematics::xiSupport(const DipoleSplittingInfo& split) const {
double c = sqrt(1.-4.*sqr(IRCutoff()/generator()->maximumCMEnergy()));
if ( split.index().emitterData()->id() == ParticleID::g ) {
if ( split.emitterData()->id() == ParticleID::g ) {
double b = log((1.+c)/(1.-c));
return {-b,b};
} else {
return {log(0.5*(1.-c)),log(0.5*(1.+c))};
}
}
if ( split.index().emitterData()->id() != ParticleID::g &&
split.emitterData()->id() != ParticleID::g ) {
return {-log(0.5*(1.+c)),-log(0.5*(1.-c))};
}
return {0.5*(1.-c),0.5*(1.+c)};
}
// sbar
Energy IFMassiveKinematics::dipoleScale(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const {
return sqrt(2.*(pEmitter*pSpectator));
}
Energy IFMassiveKinematics::ptMax(Energy dScale,
double emX, double,
- const DipoleIndex& ind,
- const DipoleSplittingKernel& split) const {
+ const DipoleSplittingInfo& dInfo,
+ const DipoleSplittingKernel&) const {
Energy2 A = sqr(dScale) * (1.-emX)/emX;
- Energy2 mk2 = sqr(split.spectator(ind)->mass());
+ Energy2 mk2 = sqr(dInfo.spectatorMass());
+ Energy ptMax = 0.5*A/sqrt(mk2+A);
+ return ptMax;
+}
+
+Energy IFMassiveKinematics::ptMax(Energy dScale,
+ double emX, double,
+ const DipoleIndex&,
+ const DipoleSplittingKernel&,
+ tPPtr, tPPtr spectator) const {
+
+ Energy2 A = sqr(dScale) * (1.-emX)/emX;
+ Energy2 mk2 = sqr(spectator->mass());
Energy ptMax = 0.5*A/sqrt(mk2+A);
return ptMax;
}
Energy IFMassiveKinematics::QMax(Energy,
double, double,
- const DipoleIndex&,
+ const DipoleSplittingInfo&,
const DipoleSplittingKernel&) const {
assert(false && "add this");
return 0.0*GeV;
}
Energy IFMassiveKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale*sqrt(1.-z);
}
Energy IFMassiveKinematics::QFromPt(Energy pt, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return pt/sqrt(1.-z);
}
double IFMassiveKinematics::ptToRandom(Energy pt, Energy,
double,double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
return log(pt/IRCutoff()) / log(0.5 * generator()->maximumCMEnergy()/IRCutoff());
}
bool IFMassiveKinematics::generateSplitting(double kappa, double xi, double rphi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel&) {
// Check emitter x against xmin
if ( info.emitterX() < xMin() ) {
jacobian(0.0);
return false;
}
// Generate pt and check it against max allowed
Energy pt = IRCutoff() * pow(0.5 * generator()->maximumCMEnergy()/IRCutoff(),kappa);
if ( pt < IRCutoff() || pt > info.hardPt() ) {
jacobian(0.0);
return false;
}
// Compute scales required
Energy2 pt2 = sqr(pt);
Energy2 saj = sqr(info.scale());
- Energy2 mk2 = sqr(info.spectatorData()->mass());
+ Energy2 mk2 = sqr(info.spectatorMass());
// Generate z
double z = 0.;
double mapZJacobian = 0.;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emitterData()->id() == ParticleID::g ) {
z = exp(xi)/(1.+exp(xi));
mapZJacobian = z*(1.-z);
} else {
z = exp(xi);
mapZJacobian = z;
}
}
if ( info.index().emitterData()->id() != ParticleID::g ) {
if ( info.emitterData()->id() != ParticleID::g ) {
z = 1.-exp(-xi);
mapZJacobian = 1.-z;
} else {
z = xi;
mapZJacobian = 1.;
}
}
// Check limits on z
double xe = info.emitterX();
Energy hard = info.hardPt();
if(openZBoundaries()==1){
Energy2 A = saj*(1.-xe)/xe;
hard = 0.5*A/sqrt(mk2+A);
}
if(openZBoundaries()==2){
Energy2 A = saj*min(1.,(1.-xe)/xe);
hard= 0.5*A/sqrt(mk2+A);
assert(pt2<=sqr(hard));
}
double ptRatio = sqrt(1. - pt2/sqr(hard) );
double zp = 0.5*(1.+xe + (1.-xe)*ptRatio);
double zm = 0.5*(1.+xe - (1.-xe)*ptRatio);
if ( z < zm || z > zp ) {
jacobian(0.0);
return false;
}
// Calculate x and u in terms of z and pt
double r = pt2/saj;
double muk2 = mk2/saj;
double rho = 1. - 4.*r*(1.-muk2)*z*(1.-z)/sqr(1.-z+r);
if ( rho < 0.0 ) {
// This has never happened
jacobian(0.0);
return false;
}
double x = 0.5*((1.-z+r)/(r*(1.-muk2))) * (1. - sqrt(rho));
double u = x*r / (1.-z);
// Check limits on x and u
// Following Catani-Seymour paper
double muk2CS = x*muk2;
double up = (1.-x) / ( 1.-x + muk2CS );
if ( x < xe || x > 1. ||
u < 0. || u > up ) {
jacobian(0.0);
return false;
}
// Jacobian
// Jacobian for dpt2 dz -> dx du
Energy2 jac = saj*abs( (1.+x*(muk2-1.))*(-u*(1.-u)/sqr(x)) - (1.+u*(muk2-1.))*((1.-2.*u)*(1.-x)/x - 2.*u*muk2) );
jacobian( (pt2/(x*u*jac)) * mapZJacobian * 2. * log(0.5 * generator()->maximumCMEnergy()/IRCutoff()));
// Log results
double phi = 2.*Constants::pi*rphi;
lastPt(pt);
lastZ(z);
lastPhi(phi);
lastEmitterZ(x);
if ( theMCCheck )
theMCCheck->book(info.emitterX(),1.,info.scale(),info.hardPt(),pt,z,jacobian());
return true;
}
void IFMassiveKinematics::generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) {
// Initialise the momenta
Lorentz5Momentum em;
Lorentz5Momentum emm;
Lorentz5Momentum spe;
-
// TODO: adjust phasespace boundary condition
if (!theCollinearScheme) {
assert(false);
Energy2 sbar = 2.*pEmitter*pSpectator;
Energy pt = dInfo.lastPt();
double ratio = pt*pt/sbar;
double z = dInfo.lastZ();
double x = (z*(1.-z)-ratio)/(1.-z-ratio);
double u = ratio / (1.-z);
pt = sqrt(sbar*u*(1.-u)*(1.-x));
Energy magKt =
sqrt(sbar*u*(1.-u)*(1.-x)/x - sqr(u*dInfo.spectatorData()->mass()));
Lorentz5Momentum kt =
getKt (pEmitter, pSpectator, magKt, dInfo.lastPhi(),true);
- Energy2 mj2 = dInfo.spectatorData()->mass()*dInfo.spectatorData()->mass();
+ Energy2 mj2 = sqr(dInfo.spectatorMass());
double alpha = 1. - 2.*mj2/sbar;
if ( x > u && (1.-x)/(x-u) < 1. ) {
double fkt = sqrt(sqr(x-u)+4.*x*u*mj2/sbar);
// em =
// ((1.-u)/(x-u))*pEmitter + ((u/x)*(1.-x)/(x-u))*pSpectator - kt/(x-u);
Energy2 fa = (sbar*(x+u-2.*x*z)+2.*mj2*x*u) / sqrt(sqr(x-u)+4.*x*u*mj2/sbar);
double a = (-sbar+fa) / (2.*x*(sbar-mj2));
double ap = (sbar+alpha*fa) / (2.*x*(sbar-mj2));
em = ap*pEmitter + a*pSpectator - fkt*kt;
// emm =
// ((1.-x)/(x-u))*pEmitter + ((u/x)*(1.-u)/(x-u))*pSpectator - kt/(x-u);
Energy2 fb = abs(sbar*(u*(1.-u)-x*(1.-x))+2.*mj2*x*u) / sqrt(sqr(x-u)+4.*x*u*mj2/sbar);
double b = (-sbar*(1.-x-u)+fb) / (2.*x*(sbar-mj2));
double bp = (sbar*(1.-x-u)+alpha*fb) / (2.*x*(sbar-mj2));
emm = bp*pEmitter + b*pSpectator + fkt*kt;
// spe =
// (1.-u/x)*pSpectator;
Energy2 fc = sqrt(sqr(sbar*(x-u))+4.*sbar*mj2*x*u);
double c = (sbar*(x-u)-2.*x*mj2+fc) / (2.*x*(sbar-mj2));
double cp = (-sbar*(x-u)+2.*x*mj2+alpha*fc) / (2.*x*(sbar-mj2));
spe = cp*pEmitter + c*pSpectator;
}
}
else {
// Get z, pt and the relevant scales
double z = dInfo.lastZ();
Energy pt = dInfo.lastPt();
Energy2 pt2 = sqr(pt);
Energy2 saj = 2.*pEmitter*pSpectator;
- double muk2 = sqr(dInfo.spectatorData()->mass())/saj;
+ double muk2 = sqr(dInfo.spectatorMass())/saj;
double r = pt2/saj;
-
+
// Calculate x and u
double rho = 1. - 4.*r*(1.-muk2)*z*(1.-z)/sqr(1.-z+r);
double x = 0.5*((1.-z+r)/(r*(1.-muk2))) * (1. - sqrt(rho));
double u = x*r / (1.-z);
// Generate kt
Lorentz5Momentum kt = getKt (pEmitter, pSpectator, pt, dInfo.lastPhi(), true);
// Set the momenta
em = (1./x)*pEmitter;
emm = ((1.-x)*(1.-u)/x - 2.*u*muk2)*pEmitter + u*pSpectator + kt;
spe = ((1.-x)*u/x + 2.*u*muk2)*pEmitter + (1.-u)*pSpectator - kt;
}
-
+
em.setMass(ZERO);
em.rescaleEnergy();
emm.setMass(ZERO);
emm.rescaleEnergy();
- spe.setMass(dInfo.spectatorData()->mass());
+ spe.setMass(dInfo.spectatorMass());
spe.rescaleEnergy();
emitterMomentum(em);
emissionMomentum(emm);
spectatorMomentum(spe);
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void IFMassiveKinematics::persistentOutput(PersistentOStream &) const {
//os << theCollinearScheme;
}
void IFMassiveKinematics::persistentInput(PersistentIStream &, int) {
//is >> theCollinearScheme;
}
ClassDescription<IFMassiveKinematics> IFMassiveKinematics::initIFMassiveKinematics;
// Definition of the static class description member.
void IFMassiveKinematics::Init() {
static ClassDocumentation<IFMassiveKinematics> documentation
("IFMassiveKinematics implements massless splittings "
"off a initial-final dipole.");
/*
static Switch<IFMassiveKinematics,bool> interfaceCollinearScheme
("CollinearScheme",
"[experimental] Switch on or off the collinear scheme",
&IFMassiveKinematics::theCollinearScheme, false, false, false);
static SwitchOption interfaceCollinearSchemeYes
(interfaceCollinearScheme,
"Yes",
"Switch on the collinear scheme.",
true);
static SwitchOption interfaceCollinearSchemeNo
(interfaceCollinearScheme,
"No",
"Switch off the collinear scheme",
false);
interfaceCollinearScheme.rank(-1);
*/
}
diff --git a/Shower/Dipole/Kinematics/IFMassiveKinematics.h b/Shower/Dipole/Kinematics/IFMassiveKinematics.h
--- a/Shower/Dipole/Kinematics/IFMassiveKinematics.h
+++ b/Shower/Dipole/Kinematics/IFMassiveKinematics.h
@@ -1,244 +1,279 @@
// -*- C++ -*-
//
// IFLightKinematics.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_IFLightKinematics_H
#define HERWIG_IFLightKinematics_H
//
// This is the declaration of the IFLightKinematics class.
//
#include "DipoleSplittingKinematics.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup DipoleShower
* \author Simon Platzer, Martin Stoll
*
* \brief IFMassiveKinematics implements massless splittings
* off an initial-final dipole.
*
* @see \ref IFMassiveKinematicsInterfaces "The interfaces"
* defined for IFMassiveKinematics.
*/
class IFMassiveKinematics: public DipoleSplittingKinematics {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
IFMassiveKinematics();
/**
* The destructor.
*/
virtual ~IFMassiveKinematics();
//@}
public:
/**
* Return the boundaries in between the evolution
* variable random number is to be sampled; the lower
* cuoff is assumed to correspond to the infrared cutoff.
*/
virtual pair<double,double> kappaSupport(const DipoleSplittingInfo& dIndex) const;
/**
* Return the boundaries in between the momentum
* fraction random number is to be sampled.
*/
virtual pair<double,double> xiSupport(const DipoleSplittingInfo& dIndex) const;
/**
* Return the boundaries on the momentum fraction
*/
virtual pair<double,double> zBoundaries(Energy,
const DipoleSplittingInfo&,
const DipoleSplittingKernel&) const {
return {0.0,1.0};
}
/**
* Return the dipole scale associated to the
* given pair of emitter and spectator. This
* should be the invariant mass or absolute value
* final/final or initial/initial and the absolute
* value of the momentum transfer for intial/final or
* final/initial dipoles.
*/
virtual Energy dipoleScale(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator) const;
/**
* Return the maximum pt for the given dipole scale.
*/
virtual Energy ptMax(Energy dScale,
double emX, double specX,
- const DipoleIndex& ind,
+ const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel& split) const;
-
+
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy dScale,
+ double, double,
+ const DipoleIndex& dIndex,
+ const DipoleSplittingKernel& split,
+ tPPtr emitter, tPPtr) const;
+
+ /**
+ * Return the maximum pt for the given dipole scale.
+ */
+ virtual Energy ptMax(Energy,
+ double, double,
+ const DipoleIndex&,
+ const DipoleSplittingKernel&) const {
+ // Only the DipoleSplittingInfo version should be used for massive
+ // dipoles, for now anyway.
+ assert(false);
+ return ZERO;
+ }
+
/**
* Return the maximum virtuality for the given dipole scale.
*/
virtual Energy QMax(Energy dScale,
double emX, double specX,
- const DipoleIndex& dIndex,
- const DipoleSplittingKernel&) const;
-
+ const DipoleSplittingInfo& dInfo,
+ const DipoleSplittingKernel& split) const;
+
+ /**
+ * Return the maximum virtuality for the given dipole scale.
+ */
+ virtual Energy QMax(Energy,
+ double, double,
+ const DipoleIndex&,
+ const DipoleSplittingKernel&) const {
+ // Only the DipoleSplittingInfo version should be used for massive
+ // dipoles, for now anyway.
+ assert(false);
+ return ZERO;
+ }
+
/**
* Return the pt given a virtuality.
*/
virtual Energy PtFromQ(Energy scale, const DipoleSplittingInfo&) const;
/**
* Return the virtuality given a pt.
*/
virtual Energy QFromPt(Energy scale, const DipoleSplittingInfo&) const;
/**
* Return the random number associated to
* the given pt.
*/
virtual double ptToRandom(Energy pt, Energy dScale,
double emX, double specX,
const DipoleIndex& dIndex,
const DipoleSplittingKernel&) const;
/**
* Generate splitting variables given three random numbers
* and the momentum fractions of the emitter and spectator.
* Return true on success.
*/
virtual bool generateSplitting(double kappa, double xi, double phi,
DipoleSplittingInfo& dIndex,
const DipoleSplittingKernel&);
/**
* Generate the full kinematics given emitter and
* spectator momentum and a previously completeted
* DipoleSplittingInfo object.
*/
virtual void generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo);
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;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<IFMassiveKinematics> initIFMassiveKinematics;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
IFMassiveKinematics & operator=(const IFMassiveKinematics &);
private:
/**
* Wether or not to choose the `collinear' scheme
*/
bool theCollinearScheme;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of IFMassiveKinematics. */
template <>
struct BaseClassTrait<Herwig::IFMassiveKinematics,1> {
/** Typedef of the first base class of IFMassiveKinematics. */
typedef Herwig::DipoleSplittingKinematics NthBase;
};
/** This template specialization informs ThePEG about the name of
* the IFMassiveKinematics class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::IFMassiveKinematics>
: public ClassTraitsBase<Herwig::IFMassiveKinematics> {
/** Return a platform-independent class name */
static string className() { return "Herwig::IFMassiveKinematics"; }
/**
* The name of a file containing the dynamic library where the class
* IFMassiveKinematics is implemented. It may also include several, space-separated,
* libraries if the class IFMassiveKinematics depends on other classes (base classes
* excepted). In this case the listed libraries will be dynamically
* linked in the order they are specified.
*/
static string library() { return "HwDipoleShower.so"; }
};
/** @endcond */
}
#endif /* HERWIG_IFMassiveKinematics_H */
diff --git a/Shower/Dipole/Kinematics/IILightKinematics.cc b/Shower/Dipole/Kinematics/IILightKinematics.cc
--- a/Shower/Dipole/Kinematics/IILightKinematics.cc
+++ b/Shower/Dipole/Kinematics/IILightKinematics.cc
@@ -1,299 +1,290 @@
// -*- C++ -*-
//
// IILightKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the IILightKinematics class.
//
#include "IILightKinematics.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h"
using namespace Herwig;
IILightKinematics::IILightKinematics()
: DipoleSplittingKinematics(), theCollinearScheme(true), didCollinear(false) {}
IILightKinematics::~IILightKinematics() {}
IBPtr IILightKinematics::clone() const {
return new_ptr(*this);
}
IBPtr IILightKinematics::fullclone() const {
return new_ptr(*this);
}
Energy IILightKinematics::ptMax(Energy dScale,
double emX, double specX,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
double tau =
!theCollinearScheme ? emX*specX : emX;
return (1.-tau) * dScale / (2.*sqrt(tau));
}
Energy IILightKinematics::QMax(Energy,
double, double,
const DipoleIndex&,
const DipoleSplittingKernel&) const {
assert(false && "add this");
return 0.0*GeV;
}
Energy IILightKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale*sqrt(1.-z);
}
Energy IILightKinematics::QFromPt(Energy scale, const DipoleSplittingInfo& split) const {
double z = split.lastZ();
return scale/sqrt(1.-z);
}
pair<double,double> IILightKinematics::zBoundaries(Energy pt,
const DipoleSplittingInfo& dInfo,
const DipoleSplittingKernel&) const {
double x =
!theCollinearScheme ?
dInfo.emitterX()*dInfo.spectatorX() :
dInfo.emitterX();
Energy hard=dInfo.hardPt();
if(openZBoundaries()==1)hard=(1.-x) *dInfo.scale()/(2.*sqrt(x));
if(openZBoundaries()==2)hard=min(dInfo.scale(),(1.-x) *dInfo.scale()/(2.*sqrt(x)));
if(hard<pt)return {0.5*(1.+x),0.5*(1.+x)};
double s = sqrt(1.-sqr(pt/hard));
return {0.5*(1.+x-(1.-x)*s),0.5*(1.+x+(1.-x)*s)};
}
bool IILightKinematics::generateSplitting(double kappa, double xi, double rphi,
DipoleSplittingInfo& info,
const DipoleSplittingKernel& split) {
if ( info.emitterX() < xMin() ||
info.spectatorX() < xMin() ) {
jacobian(0.0);
return false;
}
double weight = 1.0;
Energy pt = generatePt(kappa,info.scale(),
info.emitterX(),info.spectatorX(),
info.index(),split,
weight);
if ( pt < IRCutoff() || pt > info.hardPt() ) {
jacobian(0.0);
return false;
}
double z = 0.0;
if ( info.index().emitterData()->id() == ParticleID::g ) {
if ( info.emitterData()->id() == ParticleID::g ) {
z = generateZ(xi,pt,OneOverZOneMinusZ,
info,split,weight);
} else {
z = generateZ(xi,pt,OneOverZ,
info,split,weight);
}
}
if ( info.index().emitterData()->id() != ParticleID::g ) {
if ( info.emitterData()->id() != ParticleID::g ) {
z = generateZ(xi,pt,OneOverOneMinusZ,
info,split,weight);
} else {
z = generateZ(xi,pt,FlatZ,
info,split,weight);
}
}
if ( weight == 0. && z == -1. ) {
jacobian(0.0);
return false;
}
double ratio = sqr(pt/info.scale());
double x = z*(1.-z)/(1.-z+ratio);
double v = ratio*z /(1.-z+ratio);
if ( x < 0. || x > 1. || v < 0. || v > 1.-x ) {
jacobian(0.0);
return false;
}
if ( !theCollinearScheme &&
(1.-v-x)/(v+x) < 1. ) {
if ( (x+v) < info.emitterX() ||
x/(x+v) < info.spectatorX() ) {
jacobian(0.0);
return false;
}
} else {
if ( x < info.emitterX() ) {
jacobian(0.0);
return false;
}
}
double phi = 2.*Constants::pi*rphi;
jacobian(weight*(1./z));
lastPt(pt);
lastZ(z);
lastPhi(phi);
if ( !theCollinearScheme &&
(1.-v-x)/(v+x) < 1. ) {
lastEmitterZ(x+v);
lastSpectatorZ(x/(x+v));
} else {
lastEmitterZ(x);
lastSpectatorZ(1.);
}
if ( theMCCheck )
theMCCheck->book(info.emitterX(),info.spectatorX(),info.scale(),info.hardPt(),pt,z,jacobian());
return true;
}
void IILightKinematics::generateKinematics(const Lorentz5Momentum& pEmitter,
const Lorentz5Momentum& pSpectator,
const DipoleSplittingInfo& dInfo) {
Energy pt = dInfo.lastPt();
double z = dInfo.lastZ();
double ratio = sqr(pt)/(2.*pEmitter*pSpectator);
double x = z*(1.-z)/(1.-z+ratio);
double v = ratio*z /(1.-z+ratio);
Lorentz5Momentum kt =
getKt (pEmitter, pSpectator, pt, dInfo.lastPhi());
+ // Initialise the momenta
+ Lorentz5Momentum em;
+ Lorentz5Momentum emm;
+ Lorentz5Momentum spe;
+
if ( !theCollinearScheme &&
(1.-v-x)/(v+x) < 1. ) {
assert(false);
- Lorentz5Momentum em =
- (1./(v+x))*pEmitter+(v*(1.-v-x)/(x*(x+v)))*pSpectator+kt/(x+v);
- em.setMass(0.*GeV);
- em.rescaleEnergy();
-
- Lorentz5Momentum emm =
- ((1.-v-x)/(v+x))*pEmitter+(v/(x*(x+v)))*pSpectator+kt/(x+v);
- emm.setMass(0.*GeV);
- emm.rescaleEnergy();
-
- Lorentz5Momentum spe =
- (1.+v/x)*pSpectator;
- spe.setMass(0.*GeV);
- spe.rescaleEnergy();
-
- emitterMomentum(em);
- emissionMomentum(emm);
- spectatorMomentum(spe);
-
+ em = (1./(v+x))*pEmitter+(v*(1.-v-x)/(x*(x+v)))*pSpectator+kt/(x+v);
+ emm = ((1.-v-x)/(v+x))*pEmitter+(v/(x*(x+v)))*pSpectator+kt/(x+v);
+ spe = (1.+v/x)*pSpectator;
+
didCollinear = false;
} else {
- Lorentz5Momentum em =
- (1./x)*pEmitter;
- em.setMass(0.*GeV);
- em.rescaleEnergy();
-
- Lorentz5Momentum emm =
- ((1.-x-v)/x)*pEmitter+v*pSpectator+kt;
- emm.setMass(0.*GeV);
- emm.rescaleEnergy();
-
- Lorentz5Momentum spe =
- pSpectator;
-
- emitterMomentum(em);
- emissionMomentum(emm);
- spectatorMomentum(spe);
+ em = (1./x)*pEmitter;
+ emm = ((1.-x-v)/x)*pEmitter+v*pSpectator+kt;
+ spe = pSpectator;
K = em + spe - emm;
K2 = K.m2();
Ktilde = pEmitter + pSpectator;
KplusKtilde = K + Ktilde;
KplusKtilde2 = KplusKtilde.m2();
didCollinear = true;
}
+
+ em.setMass(ZERO);
+ em.rescaleEnergy();
+
+ emm.setMass(ZERO);
+ emm.rescaleEnergy();
+
+ spe.setMass(ZERO);
+ spe.rescaleEnergy();
+
+ emitterMomentum(em);
+ emissionMomentum(emm);
+ spectatorMomentum(spe);
+
}
// If needed, insert default implementations of function defined
// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
void IILightKinematics::persistentOutput(PersistentOStream &) const {
//os << theCollinearScheme;
}
void IILightKinematics::persistentInput(PersistentIStream &, int) {
//is >> theCollinearScheme;
}
ClassDescription<IILightKinematics> IILightKinematics::initIILightKinematics;
// Definition of the static class description member.
void IILightKinematics::Init() {
static ClassDocumentation<IILightKinematics> documentation
("IILightKinematics implements massless splittings "
"off an initial-initial dipole.");
/*
static Switch<IILightKinematics,bool> interfaceCollinearScheme
("CollinearScheme",
"[experimental] Switch on or off the collinear scheme",
&IILightKinematics::theCollinearScheme, false, false, false);
static SwitchOption interfaceCollinearSchemeYes
(interfaceCollinearScheme,
"Yes",
"Switch on the collinear scheme.",
true);
static SwitchOption interfaceCollinearSchemeNo
(interfaceCollinearScheme,
"No",
"Switch off the collinear scheme",
false);
interfaceCollinearScheme.rank(-1);
*/
}
diff --git a/Shower/Dipole/Makefile.am b/Shower/Dipole/Makefile.am
--- a/Shower/Dipole/Makefile.am
+++ b/Shower/Dipole/Makefile.am
@@ -1,22 +1,23 @@
-SUBDIRS = Base Kernels Kinematics Utility AlphaS Merging
+SUBDIRS = Base Kernels Kinematics Utility AlphaS Merging Colorea
pkglib_LTLIBRARIES = HwDipoleShower.la
-HwDipoleShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 8:2:0
+HwDipoleShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 9:0:0
HwDipoleShower_la_LIBADD = \
Base/libHwDipoleShowerBase.la \
Kernels/libHwDipoleShowerKernels.la \
Kinematics/libHwDipoleShowerKinematics.la \
Utility/libHwDipoleShowerUtility.la \
- Merging/libHwDipoleShowerMerging.la
+ Merging/libHwDipoleShowerMerging.la \
+ Colorea/libHwDipoleShowerColorea.la
HwDipoleShower_la_SOURCES = \
DipoleShowerHandler.h DipoleShowerHandler.fh DipoleShowerHandler.cc
pkglib_LTLIBRARIES += HwKrknloEventReweight.la
HwKrknloEventReweight_la_SOURCES = \
KrkNLO/KrknloEventReweight.h KrkNLO/KrknloEventReweight.cc
HwKrknloEventReweight_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 1:0:0
diff --git a/Shower/Dipole/Merging/Merger.cc b/Shower/Dipole/Merging/Merger.cc
--- a/Shower/Dipole/Merging/Merger.cc
+++ b/Shower/Dipole/Merging/Merger.cc
@@ -1,1621 +1,1614 @@
// -*- C++ -*-
//
// Merger.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL , see COPYING for details.
// Please respect the MCnet academic guidelines , see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined , non-templated member
// functions of the Merger class.
//
#include "Merger.h"
#include "Node.h"
#include "MergingFactory.h"
// other includes when needed below.
using namespace Herwig;
IBPtr Merger::clone() const {
return new_ptr( *this );
}
IBPtr Merger::fullclone() const {
return new_ptr( *this );
}
namespace {
double decideClustering(const NodePtr sub,const NodePtr head,bool& pro){
if( sub != head ){// at least one history step -> unitarisation
if ( UseRandom::rndbool() ){ pro = true; return -2.; }
else{ pro = false; return 2.; }
} // no ordered history -> no projection
else{ pro = false; return 1.; }
}
}
CrossSection Merger::MergingDSigDRBornStandard( ){
// get the history for the process
const NodePtr productionNode =
currentNode()-> getHistory( true, DSH()->hardScaleFactor() );
// decide if to cluster
weight = decideClustering(productionNode, currentNode(), projected);
// check if we only want to calculate the current multiplicity.
if(notOnlyMulti()) return ZERO;
// Check for cuts on the production proces.
if ( !productionNode->xcomb()->willPassCuts() ) return ZERO;
// calculate the staring scale for the production node
Energy startscale = CKKW_StartScale( productionNode );
// fill history with caluclation of sudakov supression
fillHistory( startscale , productionNode , currentNode() );
// fill the projector -> return the scale of the last splitting
currentNode()->runningPt( fillProjector( projected ? 1 : 0 ) );
// the weight has three components to get shower history weight
weight *= history.back().weight* // Sudakov suppression
alphaReweight()* // alpha_s reweight
pdfReweight(); // pdf reweight
// If weight is zero return.
if( weight == ZERO ) return ZERO;
//calculate the cross section
return weight*TreedSigDR( startscale , 1. );
}
CrossSection Merger::MergingDSigDRVirtualStandard( ){
// get the history for the process
const NodePtr productionNode = currentNode()-> getHistory( true , DSH()->hardScaleFactor() );
// decide if to cluster
weight = decideClustering(productionNode,currentNode(),projected);
// Check for cuts on the production proces.
if ( !productionNode->xcomb()->willPassCuts() )return ZERO;
// calculate the staring scale
Energy startscale = CKKW_StartScale( productionNode );
// fill history with caluclation of sudakov supression
fillHistory( startscale , productionNode , currentNode() );
// fill the projector -> return the scale of the last splitting
currentNode()->runningPt( fillProjector( projected ? 1 : 0 ) );
// the weight has three components to get shower history weight
double ww1 = history.back().weight;
double ww2 = alphaReweight(true);
double ww3 = pdfReweight();
weight *= ww1*ww2*ww3;
// If weight is zero return.
if( weight == 0. )return ZERO;
// calculate the cross section for virtual contribution
// and various insertion operators.
CrossSection matrixElement = LoopdSigDR( startscale );
// Now calculate the expansion of the shower history.
// first: the born contibution:
CrossSection bornWeight = currentME()->dSigHatDRB();
// second: expansion of pdf ,alpha_s-ratio and sudakov suppression.
double w1 = -sumPdfReweightExpansion();
double w2 = -sumAlphaSReweightExpansion();
double w3 = -sumFillHistoryExpansion();
// put together the expansion weights.
CrossSection expansionweight =
bornWeight*SM().alphaS()/( 2.*ThePEG::Constants::pi );
if (theShowerExpansionWeights == 0){
expansionweight *=0.;
}else if ( theShowerExpansionWeights == 1 ){
expansionweight *=w1+w2+w3;
}else if ( theShowerExpansionWeights == 2 ){
expansionweight *=w1+w2+w3*pow(as( startscale*DSH()->renFac() )/SM().alphaS(),currentME()->orderInAlphaS())/ww2;
}else if ( theShowerExpansionWeights == 3 ){
expansionweight *=(w1+w2+w3)*pow(as( startscale*DSH()->renFac() )/SM().alphaS(),currentME()->orderInAlphaS())/ww2;
}else if ( theShowerExpansionWeights == 4 ){
expansionweight *= w1+w3+w2*pow(as( startscale*DSH()->renFac() )/SM().alphaS(),currentME()->orderInAlphaS())/ww2;
}else assert(false && theShowerExpansionWeights);
// [ DEBUG ]
if ( currentNode()->legsize() == 5 && Debug::level > 2 )
debugVirt(weight,w1,w2,w3,matrixElement,ww1,ww2,ww3,productionNode,bornWeight);
// return with correction that ME was calculated with fixed alpha_s
return weight* as( startscale*DSH()->renFac() )/
SM().alphaS()* ( matrixElement+expansionweight );
}
CrossSection Merger::MergingDSigDRRealStandard(){
if ( currentNode()->children().empty() ) {
throw Exception()
<< "Real emission contribution without underlying born."
<< "These are finite contibutions already handled in LO merging."
<< Exception::abortnow;
}
// check for IR Safe Cutoff
if( !currentNode()->allAbove( theIRSafePT ) )return ZERO;
auto inOutPair = currentNode()->getInOut();
NodePtr randomChild = currentNode()->randomChild();
bool meRegion =matrixElementRegion(
inOutPair.first ,
inOutPair.second ,
randomChild->pT() ,
theMergePt );
if ( meRegion )return MergingDSigDRRealAllAbove( );
if ( UseRandom::rndbool() )
return 2.*MergingDSigDRRealBelowSubReal( );
return 2.*MergingDSigDRRealBelowSubInt( );
}
CrossSection Merger::MergingDSigDRRealAllAbove( ){
//If all dipoles pts are above , we cluster to this dipole.
NodePtr CLNode = currentNode()->randomChild();
// Check if phase space poing is in ME region--> else rm PSP
if ( !CLNode->children().empty() ) {
auto inOutPair = CLNode->getInOut();
NodePtr randomChild = CLNode->randomChild();
if( !matrixElementRegion( inOutPair.first ,
inOutPair.second ,
randomChild->pT() ,
theMergePt ) )return ZERO;
}
// first find the history for the acctual Node
NodePtr productionNode = currentNode()-> getHistory( true , DSH()->hardScaleFactor() );
// If CLNode is not part of the history , dont calculate the Real contribution
// else multiply the real contribution with N ( number of children ).
// this returns the sudakov suppression according to
// the clustering of the born parts.
bool inhist = CLNode->isInHistoryOf( productionNode );
if(productionNode== currentNode())assert(!inhist);
// get the history for the clustered Node.
productionNode = CLNode-> getHistory( false , DSH()->hardScaleFactor() );
// decide if to cluster
weight = decideClustering(productionNode,CLNode,projected);
// Check for cuts on the production process.
if ( !productionNode->xcomb()->willPassCuts() )return ZERO;
// calculate the staring scale
Energy startscale = CKKW_StartScale( productionNode );
// fill history with caluclation of sudakov supression
fillHistory( startscale , productionNode , CLNode );
// fill the projector -> return the scale of the last splitting
currentNode()->runningPt( fillProjector( projected ? 2 : 1 ) );
// the weight has three components to get shower history weight
weight *= history.back().weight*alphaReweight(true)*pdfReweight();
if( weight == 0. )return ZERO;
// The inhist flag produces the correct cluster density.
CrossSection me = ( inhist?TreedSigDR( startscale ):ZERO );
// calculate the dipole
CrossSection dip = CLNode->calcDip( startscale* currentME()->renFac() );
CrossSection res = weight*as( startscale*DSH()->renFac() )/SM().alphaS()*
currentNode()->children().size()*
( me - dip );
// [ DEBUG ]
if ( currentNode()->legsize() == 6&&Debug::level > 2 )
debugReal("RAA",weight,me,dip);
return res;
}
CrossSection Merger::MergingDSigDRRealBelowSubReal( ){
// Choose a random child to produce history from.
NodePtr HistNode = currentNode()->randomChild();
// Check that this subleading point is in ME region.
if ( !HistNode->children().empty() ) {
auto inOutPair = HistNode->getInOut();
NodePtr randomChild = HistNode->randomChild(); // Here we make sure that clustering and splitting are invertible
if( !matrixElementRegion( inOutPair.first , inOutPair.second , randomChild->pT() , theMergePt ) )return ZERO;
}
// As the HistNode is now in ME region, we can cluster according to LO merging.
// In this clustering we do not require a orering for the last step to the currentNode.
const NodePtr productionNode = HistNode-> getHistory( false , DSH()->hardScaleFactor() );
// If the real emission contribution should be unitarised, we decide here if we cluster.
// This applies to NLO corrections for the first emission w.r.t. the production process the first time.
weight = decideClustering(productionNode,HistNode,projected);
// The production node needs to fulfill the cut criterion of the production process.
if ( !productionNode->xcomb()->willPassCuts() && !currentNode()->xcomb()->willPassCuts() )return ZERO;
// Calculate the starting scale w.r.t. the production process.
Energy startscale = CKKW_StartScale( productionNode );
// If the production process does not fullfill the cut criterion use the real emission point (DEBUG)
if (!productionNode->xcomb()->willPassCuts()) startscale = CKKW_StartScale( currentNode() );
// DEBUG trial
//currentNode()->xcomb()->lastProjector( productionNode->xcomb());
// Calculate the sudakov weights starting from the production node to the histNode
fillHistory( startscale , productionNode , HistNode );
// Set the running Pt of the process as it is used in the vetoed parton shower.
currentNode()->runningPt( fillProjector( projected ? 1 : 0 ) );
currentNode()->runningPt(max(HistNode->pT(),theMergePt));
// Calculate the alpha_S ratios and pdf ratios.
weight *= history.back().weight*alphaReweight(true)*pdfReweight();
if( weight == 0. )return ZERO;
// Start calculation of subtraction contribution.
CrossSection sumPS = ZERO;
// Iterate over all subtraction contributions.
for( auto const & child : currentNode()->children() ){
if ( child->allAbove( mergePt() ) && child->xcomb()->willPassCuts() ){
Energy relevantScale=child->children().empty()?CKKW_StartScale( child ):child->maxChildPt();
if( ( child )->pT()>mergePt()/theRealSubtractionRatio ){
if( child ->pT()<relevantScale&&(child->inShowerPS(relevantScale))){ //DEBUG: CKKW_StartScale( child);????
sumPS += child->calcPs( startscale* currentME()->renFac() );
}
}else{
if( child ->pT()<relevantScale){
sumPS += child->calcDip( startscale* currentME()->renFac() );
}
}
}
}
CrossSection me = ZERO;
if(currentNode()->xcomb()->willPassCuts()){
me = TreedSigDR( startscale );
}
// [ DEBUG ]
if ( currentNode()->legsize() == 6&&Debug::level > 2 )
debugReal("RBSR",weight,me,sumPS);
//Here we subtract the PS ( and below the dynamical cutoff the Dip )
return weight*as( startscale*DSH()->renFac() )/SM().alphaS()*
( me-sumPS );
}
CrossSection Merger::MergingDSigDRRealBelowSubInt( ){
if( currentNode()->children().empty() )return ZERO;
NodePtr CLNode = currentNode()->randomChild();
if( CLNode->pT()<mergePt()/theRealSubtractionRatio )return ZERO;
if ( !CLNode->children().empty() ) {
auto inOutPair = CLNode->getInOut( );
NodePtr randomChild = CLNode->randomChild(); // Here we make sure that clustering and splitting are invertible
if( !matrixElementRegion( inOutPair.first , inOutPair.second , randomChild->pT() , theMergePt ) )return ZERO;
}
const NodePtr productionNode = CLNode-> getHistory( false , DSH()->hardScaleFactor() );
weight = decideClustering(productionNode,CLNode,projected);
if ( !CLNode->allAbove( mergePt() ) )return ZERO;
if ( !productionNode->xcomb()->willPassCuts() )return ZERO;
Energy startscale = CKKW_StartScale( productionNode );
fillHistory( startscale , productionNode , CLNode );
currentNode()->runningPt( fillProjector( projected ? 2 : 1 ) );
weight *= history.back().weight*alphaReweight(true)*pdfReweight();
if( weight == 0. )return ZERO;
pair<CrossSection , CrossSection> DipAndPs =
CLNode->calcDipandPS( startscale* currentME()->renFac() );
// [ DEBUG ]
if ( currentNode()->legsize() == 6&&Debug::level > 2 )
debugReal("RBSI",weight,DipAndPs.second,DipAndPs.first);
Energy relevantScale=CLNode->children().empty()?CKKW_StartScale( CLNode ):CLNode->maxChildPt();
bool calcPScontribution=CLNode->pT()<relevantScale&&(CLNode->inShowerPS(relevantScale));
//Here we add the PS and subtrac the Dip ( only above the dynamical cutoff )
return weight*as( startscale*DSH()->renFac() )/SM().alphaS()*
currentNode()->children().size()*( (calcPScontribution?DipAndPs.second:ZERO)-DipAndPs.first );
}
CrossSection Merger::MergingDSigDRBornGamma( ){
double weightCL = 0.;
weight = 1.;
if ( !currentNode()->children().empty() ) {
auto const inOutPair = currentNode()->getInOut();
// Here we make sure that clustering and splitting are invertible.
NodePtr randomChild = currentNode()->randomChild();
// Check if point is part of the ME region.
if( !matrixElementRegion( inOutPair.first ,
inOutPair.second ,
randomChild->pT() ,
theMergePt ) )weight *= 0.;
}
const NodePtr productionNode = currentNode()->getHistory( true , DSH()->hardScaleFactor() );
NodePtr CLNode;
NodePtr BornCL;
if( !currentNode()->children().empty() ){
if ( UseRandom::rndbool() ){
CLNode = currentNode()->randomChild();
bool inhist = CLNode->isInHistoryOf( productionNode );
weight *= inhist?( -2.*int( currentNode()->children().size() ) ):0.;
projected = true;
weightCL = 2.*int( currentNode()->children().size() );
BornCL = CLNode-> getHistory( false , DSH()->hardScaleFactor() );
}else{
weight = 2.;
projected = false;
}
}else{
weight = 1.;
projected = false;
}
if ( treefactory()->onlymulti() != -1&&
treefactory()->onlymulti() !=
int( currentNode()->legsize()-(projected ? 1 : 0) ) )
return ZERO;
if( !currentNode()->allAbove( mergePt()*(1.-1e-6) ) )weight = 0.;
if( CLNode&&!CLNode->allAbove( mergePt()*(1.-1e-6) ) )weightCL = 0.;
if ( !productionNode->xcomb()->willPassCuts() ){
return ZERO;
}
CrossSection res = ZERO;
bool maxMulti = currentNode()->legsize() == int( maxLegsLO() );
if( weight != 0. ){
Energy startscale = CKKW_StartScale( productionNode );
fillHistory( startscale , productionNode , currentNode() );
currentNode()->runningPt( fillProjector( (projected ? 1 : 0) ) );
weight *= history.back().weight*alphaReweight()*pdfReweight();
if( weight == 0.&&weightCL == 0. )return ZERO;
res += weight*TreedSigDR( startscale , ( !maxMulti&&!projected )?theGamma:1. );
}
if( CLNode&&theGamma != 1. ){
Energy startscale = CKKW_StartScale( BornCL );
fillHistory( startscale , BornCL , CLNode );
currentNode()->runningPt( fillProjector( projected ? 1 : 0 ) );
weightCL *= history.back().weight*alphaReweight()*pdfReweight();
CrossSection diff = ZERO;
currentME()->factory()->setAlphaParameter( 1. );
diff -= weightCL*CLNode->dipole()->dSigHatDR( sqr( startscale* currentME()->renFac() ) );
currentME()->factory()->setAlphaParameter( theGamma );
string alp = ( CLNode->dipole()->aboveAlpha()?"Above":"Below" );
diff += weightCL*CLNode->dipole()->dSigHatDR( sqr( startscale* currentME()->renFac() ) );
currentME()->factory()->setAlphaParameter( 1. );
res += diff;
}
return res;
}
CrossSection Merger::TreedSigDR( Energy startscale , double diffAlpha ){
currentME()->setScale( sqr( startscale ) , sqr( startscale ) );
CrossSection res = currentME()->dSigHatDRB();
/*bool useDipolesForME=false;
if (useDipolesForME && !currentNode()->children().empty()){
res=ZERO;
for (auto const & child : currentNode()->children() )
res-=child->dipole()->dSigHatDR(sqr( startscale ));
}
*/
if ( projected && emitDipoleMEDiff ) {
CrossSection resDip=ZERO;
for (auto const & child : currentNode()->children() )
resDip-=child->dipole()->dSigHatDR(sqr( startscale ));
setEmissionProbability(1.-min(resDip/res,res/resDip));
}else{
setEmissionProbability(0.);
}
if ( diffAlpha != 1. ) {
res += currentME()->dSigHatDRAlphaDiff( diffAlpha );
}
if( std::isnan( double( res/nanobarn ) ) ){
generator()->logWarning(Exception()
<< "Merger: TreedSigDR is nan"
<< Exception::warning);
res = ZERO;};
return res;
}
CrossSection Merger::LoopdSigDR( Energy startscale ){
currentME()->setScale( sqr( startscale ) , sqr( startscale ) );
currentME()->doOneLoopNoBorn();
CrossSection res = currentME()->dSigHatDRV()+
currentME()->dSigHatDRI();
currentME()->noOneLoopNoBorn();
return res;
}
Energy Merger::fillProjector( int pjs ){
// in the shower handler the scale is multiplied
// by DSH()->hardScaleFactor() so here we need
// to devide by the factor.
double xiQSh = history.begin()->node->legsize() == N0()?DSH()->hardScaleFactor():1.;
if( pjs == 0 ){
return ( history.size() == 1?1.:( 1./xiQSh ) )*history.back().scale;
}
for( auto const & hs : history )
if ( isProjectorStage( hs.node , pjs )&&pjs != 0 ){
currentNode()->xcomb()->lastProjector( hs.node->xcomb() );
return ( hs.node == history[0].node?1.:( 1./xiQSh ) )*hs.scale;
}
throw Exception() << "Could not fill projector." << Exception::abortnow;
return ZERO;
}
double Merger::pdfReweight(){ // TODO factorization scale inside
double res = 1.;
// consider both sides.
for( int side : {0 , 1} ){
// The side scale defines the scale that the leg is changig thou the history.
// We start reweighting at the seed process.
// We only need to calculate the pdf if the emission whould change the leg,
// otherwise the leg remains the same.
// If no emission is prduced from this leg the pdf ratios from this leg are always 1.
Energy sidescale=history[0].scale*(
history[0].node->legsize() == N0() ?
currentME()->facFac():
DSH()->facFac());
bool sidechanged=false;
// only if the incoming parton is coloured.
if( history[0].node->xcomb()->mePartonData()[side]->coloured() ){
// go though the history.
for ( auto const & hs : history ){
//pdf-ratio only to the last step
if ( !hs.node->parent() ) continue;
if ( hs.node == history.back().node ) continue;
if ( !hs.node->dipole() ){
throw Exception()
<< "\nMerger: pdfReweight: history step has no dipol. "
<< Exception::abortnow;
return 0.;
}
// if the emitter is the side the emission changes the momentum fraction.
if(!(hs.node->dipole()->bornEmitter()==side||
// II dipoles dont change the momentum fraction of the spectator only FI
( hs.node->dipole()->bornSpectator()==side && hs.node->dipole()->bornEmitter()>1)))
continue;
const bool fromIsME = false;
const bool toIsME = history[0].node == hs.node;
res *= pdfratio( hs.node,
//numerator
sidescale,
// denominator
DSH()->facFac()*hs.node->pT(),
side,
fromIsME,
toIsME);
sidescale= DSH()->facFac()*hs.node->pT();
sidechanged=true;
}
const bool fromIsME = true;
const bool toIsME = !sidechanged && history[0].node->legsize() == N0();
res *= pdfratio( history.back().node,
sidescale,
history[0].scale * currentME()->facFac(),
side,
fromIsME,
toIsME );
}
}
if ( std::isnan( res ) )
generator()->logWarning(Exception()
<< "Merger: pdfReweight is nan."
<< Exception::warning);
return res;
}
double Merger::cmwAlphaS(Energy q)const{
using Constants::pi;
// No cmw-scheme
if (theCMWScheme==0)
return as( q );
// Linear cmw-scheme
else if(theCMWScheme==1){
double als=as( q );
return als *
(1.+(3.*(67./18.-1./6.*sqr(pi))
-5./9.*Nf(q))* als/2./pi);
}
// cmw-scheme as factor in argument.
else if(theCMWScheme==2){
double kg=exp(-(67.-3.*sqr(pi)-10/3*Nf(q))
/( 2. *(33.-2.*Nf(q))));
//Note factor 2 since we here dealing with Energy
return as(max(kg*q,1_GeV));
}else{
throw Exception()
<< "This CMW-Scheme is not implemented."
<< Exception::abortnow;
}
return -1;
}
double Merger::alphaReweight(bool nocmw){
double res = 1.;
Energy Q_R = ( history[0].node->legsize() == N0()?
currentME()->renFac():
DSH()->renFac() )*
history[0].scale;
using Constants::pi;
const auto Q_qed=history[0].node->nodeME()->factory()->scaleChoice()->renormalizationScaleQED();
const auto Oew=history[0].node->nodeME()->orderInAlphaEW();
const auto Oqcd=history[0].node->nodeME()->orderInAlphaS();
if (!history[0].node->children().empty()) {
assert(Oqcd!=0);
}
res *= pow( SM().alphaEMME( Q_qed )/ SM().alphaEMMZ() , Oew );
res *= pow( (nocmw?as(Q_R):cmwAlphaS(Q_R)) / SM().alphaS() , Oqcd );
for ( auto const & hs : history )
if ( hs.node!= history.back().node ){
Energy q_i = DSH()->renFac()* hs.node->pT();
res *= cmwAlphaS(q_i) / SM().alphaS();
}
if ( std::isnan( res ) )
generator()->logWarning(Exception()
<< "Merger: alphaReweight is nan. "<< Exception::warning);
return res;
}
void Merger::fillHistory( Energy scale , NodePtr begin , NodePtr endNode ){
history.clear();
double sudakov0_n = 1.;
history.push_back( {begin , sudakov0_n , scale} );
double xiQSh = history.begin()->node->legsize() == N0()?
DSH()->hardScaleFactor():1.;
scale *= xiQSh;
if ( begin->parent()||!isUnitarized ) {
while ( begin->parent() && ( begin != endNode ) ) {
if ( !dosudakov( begin , scale , begin->pT() , sudakov0_n ) ){
history.push_back( { begin->parent() , 0. , scale } );
}
if ( std::isnan( sudakov0_n ) )
generator()->logWarning(Exception()
<< "Merger: sudakov"<<scale/GeV<<" "
<<begin->pT()/GeV<<"0_n is nan. "
<< Exception::warning);
scale = begin->pT();
history.push_back( { begin->parent() , sudakov0_n , begin->pT() } );
begin = begin->parent();
}
Energy notunirunning = scale;
if ( !isUnitarized&&N()+N0() > int( currentNode()->legsize() ) ) {
if ( !dosudakov( begin , notunirunning , mergePt() , sudakov0_n ) ){
history.back().weight = 0.;
}else{
history.back().weight = sudakov0_n;
}
}
}
if( history.size() == 1 )scale /= DSH()->hardScaleFactor();
}
double Merger::sumPdfReweightExpansion()const{
double res = 0.;
Energy beam1Scale = history[0].scale*
( history[0].node->legsize() == N0()?
currentME()->facFac():
DSH()->facFac() );
Energy beam2Scale = history[0].scale*
( history[0].node->legsize() == N0()?
currentME()->facFac():
DSH()->facFac() );
for ( auto const & hs : history ){
//pdf expansion only to the last step
if( !hs.node->parent() )continue;
if( hs.node->xcomb()->mePartonData()[0]->coloured()&&
hs.node->nodeME()->lastX1()>0.99 )return 0.;
if( hs.node->xcomb()->mePartonData()[1]->coloured()&&
hs.node->nodeME()->lastX2()>0.99 )return 0.;
if( hs.node->nodeME()->lastX1()<0.00001 )return 0.;
if( hs.node->nodeME()->lastX2()<0.00001 )return 0.;
if ( hs.node->dipole()->bornEmitter() == 0 ){
res += pdfExpansion( hs.node , 0 ,
beam1Scale ,
( hs.node->pT() ) ,
hs.node->nodeME()->lastX1() ,
Nf( history[0].scale ) ,
history[0].scale );
beam1Scale = ( hs.node->pT() )*DSH()->facFac();
}
else if ( hs.node->dipole()->bornEmitter() == 1 ){
res += pdfExpansion( hs.node , 1 ,
beam2Scale ,
( hs.node->pT() ) ,
hs.node->nodeME()->lastX2() ,
Nf( history[0].scale ) ,
history[0].scale );
beam2Scale = ( hs.node->pT() )*DSH()->facFac();
}
// if we're here we know hs.node->dipole()->bornEmitter() > 1
// works only in collinear scheme
else if ( hs.node->dipole()->bornSpectator() == 0 ){
res += pdfExpansion( hs.node , 0 ,
beam1Scale ,
( hs.node->pT() ) ,
hs.node->nodeME()->lastX1() ,
Nf( history[0].scale ) ,
history[0].scale );
beam1Scale = ( hs.node->pT() )*DSH()->facFac();
}
else if ( hs.node->dipole()->bornSpectator() == 1 ){
res += pdfExpansion( hs.node , 1 ,
beam2Scale ,
( hs.node->pT() ) ,
hs.node->nodeME()->lastX2() ,
Nf( history[0].scale ) ,
history[0].scale );
beam2Scale = ( hs.node->pT() )*DSH()->facFac();
}
}
if ( currentNode()->xcomb()->mePartonData()[0]->coloured() ){
res += pdfExpansion( history.back().node , 0 ,
beam1Scale ,
history[0].scale* currentME()->facFac() ,
( history.back() ).node->nodeME()->lastX1() ,
Nf( history[0].scale ) ,
history[0].scale );
}
if ( currentNode()->xcomb()->mePartonData()[1]->coloured() ) {
res += pdfExpansion( history.back().node , 1 ,
beam2Scale ,
history[0].scale* currentME()->facFac() ,
( history.back() ).node->nodeME()->lastX2() ,
Nf( history[0].scale ) ,
history[0].scale );
}
return res;
}
#include "Herwig/MatrixElement/Matchbox/Phasespace/RandomHelpers.h"
double Merger::pdfExpansion( NodePtr node ,
int side , Energy running ,
Energy next , double x ,
int nlp , Energy fixedScale ) const {
tcPDPtr particle , parton;
tcPDFPtr pdf;
if ( side == 0 ) {
particle = node->nodeME()->lastParticles().first->dataPtr();
parton = node->nodeME()->lastPartons().first->dataPtr();
pdf = node->xcomb()->partonBins().first->pdf();
}else{
assert( side == 1 );
particle = node->nodeME()->lastParticles().second->dataPtr();
parton = node->nodeME()->lastPartons().second->dataPtr();
pdf = node->xcomb()->partonBins().second->pdf();
}
//copied from PKOperator
double res = 0.;
int number = 10;
for ( int nr = 0;nr<number;nr++ ){
double restmp = 0;
using namespace RandomHelpers;
double r = UseRandom::rnd();
double eps = 1e-3;
pair<double , double> zw =
generate( ( piecewise() ,
flat( 0.0 , x ) ,
match( inverse( 0.0 , x , 1.0 ) +
inverse( 1.0+eps , x , 1.0 ) ) ) , r );
double z = zw.first;
double mapz = zw.second;
double PDFxparton = pdf->xfx( particle , parton , sqr( fixedScale ) , x )/x;
- double CA = SM().Nc();
- double CF = ( SM().Nc()*SM().Nc()-1.0 )/( 2.*SM().Nc() );
+ static double CA = SM().Nc();
+ static double CF = ( SM().Nc()*SM().Nc()-1.0 )/( 2.*SM().Nc() );
if ( abs( parton->id() ) < 7 ) {
double PDFxByzgluon = pdf->xfx( particle ,
getParticleData( ParticleID::g ) ,
sqr( fixedScale ) , x/z )*z/x;
double PDFxByzparton = pdf->xfx( particle , parton ,
sqr( fixedScale ) , x/z )*z/x;
assert( abs( parton->id() ) < 7 );
restmp += CF*( 3./2.+2.*log( 1.-x ) ) * PDFxparton;
if ( z > x ) {
restmp += 0.5 * ( sqr( z ) + sqr( 1.-z ) ) * PDFxByzgluon / z;
restmp += CF*2.*( PDFxByzparton - z*PDFxparton )/( z*( 1.-z ) );
restmp -= CF*PDFxByzparton * ( 1.+z )/z;
}
}else{
assert( parton->id() == ParticleID::g );
double PDFxByzgluon = pdf->xfx( particle ,
getParticleData( ParticleID::g ) ,
sqr( fixedScale ) , x/z )*z/x;
// Pqg
if ( z > x ){
double factor = CF * ( 1. + sqr( 1.-z ) ) / sqr( z );
for ( int f = -nlp; f <= nlp; ++f ) {
if ( f == 0 )
continue;
restmp += pdf->xfx( particle , getParticleData( f ) ,
sqr( fixedScale ) , x/z )*z/x*factor;
}
}
// Pgg
restmp += ( ( 11./6. ) * CA
- ( 1./3. )*Nf( history[0].scale )
+ 2.*CA*log( 1.-x ) ) *PDFxparton;
if ( z > x ) {
restmp += 2. * CA * ( PDFxByzgluon - z*PDFxparton ) / ( z*( 1.-z ) );
restmp += 2.* CA *( ( 1.-z )/z - 1. + z*( 1.-z ) ) * PDFxByzgluon / z;
}
}
if ( PDFxparton<1e-8 )
restmp = 0.;
else
res += 1*restmp*log( sqr( running/next ) )/PDFxparton*mapz;
}
return res/number;
}
double Merger::sumAlphaSReweightExpansion()const{
double res = 0.;
const auto Oqcd=history[0].node->nodeME()->orderInAlphaS();
res += alphasExpansion( history[0].scale* DSH()->renFac() ,
history[0].scale* currentME()->renFac() )*
Oqcd;
// dsig is calculated with fixed alpha_s
for ( auto const & hs : history ){
//expansion only to the last step
if( !hs.node->parent() )continue;
res += alphasExpansion( hs.node->pT()*DSH()->renFac() ,currentME()->renFac()*history[0].scale );
}
return res;
}
double Merger::sumFillHistoryExpansion(){
double res = 0.;
double xiQSh = history[0].node->legsize() == N0()?DSH()->hardScaleFactor():1.;
for ( auto const & hs : history ){
if( !hs.node->parent() )continue;
doHistExpansion( hs.node , ( hs.node == history[0].node?xiQSh:1. )*hs.scale ,
hs.node->pT() , history[0].scale , res );
}
return res;
}
MergingFactoryPtr Merger::treefactory()const{return theTreeFactory;}
void Merger::doinit(){
if ( !DSH()->hardScaleIsMuF() ) {
throw Exception()
<< "Merger: Merging is currently only sensible "
<< "if we are using the hardScale as MuF."
<< Exception::abortnow;
}
+ DSH()->init();
+
+ if ( !( DSH()->showerPhaseSpaceOption() == 0 ||
+ DSH()->showerPhaseSpaceOption() == 1) ){
+ throw InitException() << "Merger::doinit(): Choice of shower phase space cannot be handled by the merging";
+ }
}
namespace{
void setXCombScales(StdXCombPtr xc,Energy2 scale){
xc->lastShowerScale ( scale );
xc->partonBinInstances().first->scale ( scale );
xc->partonBinInstances().second->scale ( scale );
}
}
CrossSection Merger::MergingDSigDR() {
history.clear();
assert(currentNode()==theFirstNodeMap[ currentME()]);
if(DSH()->doesSplitHardProcess()){
throw Exception()
<< "Merger: The splithardprocess option is currently not supported."
<< Exception::abortnow;
}
//get the PDF's (from ShowerHandler.cc)
if (!DSH()->getPDFA()||!DSH()->firstPDF().particle()){
tSubProPtr sub = currentNode()->xcomb()->construct();
const auto pb=currentNode()->xcomb()->partonBins();
tcPDFPtr first = DSH()->getPDFA() ?
tcPDFPtr(DSH()->getPDFA()) : DSH()->firstPDF().pdf();
tcPDFPtr second = DSH()->getPDFB() ?
tcPDFPtr(DSH()->getPDFB()) : DSH()->secondPDF().pdf();
DSH()->resetPDFs( {first,second },pb );
}
DSH()->eventHandler( generator()->eventHandler() );
CrossSection res = ZERO;
if( currentNode()->subtractedReal() ){
res = MergingDSigDRRealStandard();
theCurrentMaxLegs = maxLegsNLO();
}else if( currentNode()->virtualContribution() ){
res = MergingDSigDRVirtualStandard();
theCurrentMaxLegs = maxLegsNLO();
}else if( theGamma!= 1. ){
res = MergingDSigDRBornGamma();
theCurrentMaxLegs = maxLegsLO();
}else{
res = MergingDSigDRBornStandard();
theCurrentMaxLegs = maxLegsLO();
}
auto lxc= currentME()->lastXCombPtr();
setXCombScales(lxc,sqr( currentNode()->runningPt()));
auto lp= currentME()->lastXCombPtr()->lastProjector();
if( lp )
setXCombScales( lp, sqr( currentNode()->runningPt()));
if ( res == ZERO ){
history.clear();
return ZERO;
}
cleanup( currentNode() );
lxc->subProcess( SubProPtr() );
history.clear();
if( !std::isfinite( double( res/nanobarn ) ) ){
generator()->logWarning(Exception()
<< "Merger weight is " << res/nanobarn<< " -> setting to 0"
<< Exception::warning);
return ZERO;
}
return res;
}
#include "Herwig/PDF/HwRemDecayer.h"
void Merger::CKKW_PrepareSudakov( NodePtr node , Energy running ){
tSubProPtr sub = node->xcomb()->construct();
const auto pb=node->xcomb()->partonBins();
DSH()->setCurrentHandler();
DSH()->currentHandler()->generator()->currentEventHandler(currentNode()->xcomb()->eventHandlerPtr() );
DSH()->currentHandler()->remnantDecayer()->setHadronContent( currentNode()->xcomb()->lastParticles() );
DSH()->eventRecord().clear();
- DSH()->eventRecord().slimprepare( sub , dynamic_ptr_cast<tStdXCombPtr>( node->xcomb() ) , DSH()->pdfs() , currentNode()->xcomb()->lastParticles() );
+ DSH()->eventRecord().slimprepare( sub , dynamic_ptr_cast<tStdXCombPtr>( node->xcomb() ) , DSH()->pdfs() ,
+ currentNode()->xcomb()->lastParticles(), DSH()->offShellPartons() );
DSH()->hardScales( sqr( running ) );
}
Energy Merger::CKKW_StartScale( NodePtr node ) const {
Energy res = generator()->maximumCMEnergy();
const int N=node->legsize();
const auto & data=node->nodeME()->mePartonData();
const auto & momenta=node->nodeME()->lastMEMomenta();
if( !node->children().empty() ){
for ( int i = 0; i<N ; i++ ){ if ( !data[i]->coloured() )continue;
for ( int j = 2; j<N ; j++ ){ if ( i == j||!data[j]->coloured() )continue;
for ( int k = 0; k<N ; k++ ){ if ( !data[k]->coloured() || i == k || j == k )continue;
if(i<2){
if(k<2) {
res = min( res , IILTK->lastPt( momenta[i] , momenta[j] , momenta[k] ));
}
else {
res = min( res ,
(data[k]->mass()+data[j]->mass()+data[i]->mass()>ZERO)?
IFMTK->lastPt( momenta[i] , momenta[j] , momenta[k] ):
IFLTK->lastPt( momenta[i] , momenta[j] , momenta[k] ));
}
}else{
if(k<2) {
res = min( res ,
(data[k]->mass()+data[j]->mass()+data[i]->mass()>ZERO)?
FIMTK->lastPt( momenta[i] , momenta[j] , momenta[k] ):
FILTK->lastPt( momenta[i] , momenta[j] , momenta[k] ));
}
else {
res = min( res ,
(data[k]->mass()+data[j]->mass()+data[i]->mass()>ZERO)?
FFMTK->lastPt( momenta[i] , momenta[j] , momenta[k] ):
FFLTK->lastPt( momenta[i] , momenta[j] , momenta[k] ));
}
}
}
}
}
}else{
node->nodeME()->factory()->scaleChoice()->setXComb( node->xcomb() );
res = sqrt( node->nodeME()->factory()->scaleChoice()->renormalizationScale() );
}
node->nodeME()->factory()->scaleChoice()->setXComb( node->xcomb() );
res = max( res , sqrt( node->nodeME()->factory()->scaleChoice()->renormalizationScale() ) );
return res;
}
double Merger::alphasExpansion( Energy next , Energy fixedScale ) const {
double betaZero = ( 11./6. )*SM().Nc() - ( 1./3. )*Nf( history[0].scale );
double K=3.*( 67./18.-1./6.*sqr(Constants::pi) ) -5./9.*Nf( history[0].scale);
return ( betaZero*log( sqr( fixedScale/next ) ) )+( theCMWScheme>0?K:0. );
}
double Merger::pdfratio( NodePtr node ,
Energy numerator_scale ,
Energy denominator_scale ,
int side ,
bool fromIsME,
bool toIsME ){
StdXCombPtr bXc = node->xcomb();
if( !bXc->mePartonData()[side]->coloured() )
throw Exception()
<< "Merger: pdf-ratio required for non-coloured particle."
<< Exception::abortnow;
double from = 1.;
double to = 1.;
if ( side == 0 ){
if ( denominator_scale == numerator_scale && fromIsME==toIsME ) {
return 1.;
}
if (fromIsME) {
from = node->nodeME()->pdf1( sqr( denominator_scale ) );
}else{
from = DSH()->firstPDF().xfx(node->xcomb()->lastPartons().first->dataPtr(),
sqr( denominator_scale ),
node->xcomb()->lastX1())/node->xcomb()->lastX1();
}
if (toIsME) {
to = node->nodeME()->pdf1( sqr( numerator_scale ) );
}else{
to = DSH()->firstPDF().xfx(node->xcomb()->lastPartons().first->dataPtr(),
sqr( numerator_scale ),
node->xcomb()->lastX1())/node->xcomb()->lastX1();
}
if ( ( to < 1e-8||from < 1e-8 )&&( to/from>10000000. ) ){
generator()->logWarning(Exception()
<< "Merger: pdfratio to = " << to << " from = " << from
<< Exception::warning);
return 0.;
}
}
else{
if ( denominator_scale == numerator_scale && fromIsME==toIsME ) {
return 1.;
}
if (fromIsME) {
from = node->nodeME()->pdf2( sqr( denominator_scale ) );
}else{
from =DSH()->secondPDF().xfx(node->xcomb()->lastPartons().second->dataPtr(),
sqr( denominator_scale ),
node->xcomb()->lastX2())/node->xcomb()->lastX2();
}
if (toIsME) {
to = node->nodeME()->pdf2( sqr( numerator_scale ) );
}else{
to = DSH()->secondPDF().xfx(node->xcomb()->lastPartons().second->dataPtr(),
sqr( numerator_scale ),
node->xcomb()->lastX2())/node->xcomb()->lastX2();
}
if ( ( to < 1e-8||from < 1e-8 )&&( to/from>10000000. ) ){
generator()->logWarning(Exception()
<< "Merger: pdfratio to = "
<< to << " from = " << from
<< Exception::warning);
return 0.;}
}
return to/from;
}
bool Merger::dosudakov( NodePtr node , Energy running , Energy next , double& sudakov0_n ) {
CKKW_PrepareSudakov( node , running );
for( DipoleChain const & chain : DSH()->eventRecord().chains() ){
for( Dipole const & dip : chain.dipoles() ){
sudakov0_n *= singlesudakov( dip , next , running , { true , false } );
sudakov0_n *= singlesudakov( dip , next , running , { false , true } );
if ( sudakov0_n == 0.0 ){
cleanup( node );
return false;
}
}
}
cleanup( node );
return true;
}
bool Merger::doHistExpansion( NodePtr node , Energy running , Energy next , Energy fixedScale , double& histExpansion ) {
CKKW_PrepareSudakov( node , running );
for( DipoleChain const & chain : DSH()->eventRecord().chains() ){
for( Dipole const & dip : chain.dipoles() ){
histExpansion += singleHistExpansion( dip , next , running , fixedScale , { true , false } );;
histExpansion += singleHistExpansion( dip , next , running , fixedScale , { false , true } );
}
}
cleanup( node );
return true;
}
bool Merger::isProjectorStage( NodePtr node , int pjs )const{
return ( pjs == int( ( currentNode()->legsize() - node->legsize() ) ) );
}
void Merger::cleanup( NodePtr node ) {
DSH()->eventRecord().clear();
if( !node->xcomb()->subProcess() )return;
ParticleVector vecfirst = node->xcomb()->subProcess()->incoming().first->children();
for( auto const & particle : vecfirst )
node->xcomb()->subProcess()->incoming().first->abandonChild( particle );
ParticleVector vecsecond = node->xcomb()->subProcess()->incoming().second->children();
for( auto const & particle : vecsecond )
node->xcomb()->subProcess()->incoming().second->abandonChild( particle );
node->xcomb()->subProcess( SubProPtr() );
}
double Merger::singlesudakov( Dipole dip , Energy next , Energy running , pair<bool , bool> conf ){
double res = 1.;
tPPtr emitter = dip.emitter( conf );
tPPtr spectator = dip.spectator( conf );
DipoleSplittingInfo candidate( dip.index( conf ) , conf ,
dip.emitterX( conf ) ,
dip.spectatorX( conf ) ,
emitter , spectator );
if ( DSH()->generators().find( candidate.index() ) == DSH()->generators().end() ) DSH()->getGenerators( candidate.index() );
auto const & gens = DSH()->generators().equal_range( candidate.index() );
for ( auto gen = gens.first; gen != gens.second; ++gen ) {
if ( !( gen->first == candidate.index() ) )
continue;
Energy dScale = gen->second->splittingKinematics()->dipoleScale( emitter->momentum() , spectator->momentum() );
candidate.scale( dScale );
candidate.continuesEvolving();
- Energy ptMax = gen->second->splittingKinematics()->ptMax( candidate.scale() , candidate.emitterX() , candidate.spectatorX() ,
- candidate.index() , *gen->second->splittingKernel() );
+
+ Energy ptMax = gen->second->splittingKinematics()->ptMax(
+ candidate.scale() ,
+ candidate.emitterX() ,
+ candidate.spectatorX() ,
+ candidate ,
+ *gen->second->splittingKernel() );
candidate.hardPt( min( running , ptMax ) );
if ( candidate.hardPt()>next ){
res *= gen->second->sudakov( candidate , next );
}
}
return res;
}
double Merger::singleHistExpansion( Dipole dip , Energy next , Energy running , Energy fixedScale , pair<bool , bool> conf ){
double res = 0.;
tPPtr emitter = dip.emitter( conf );
tPPtr spectator = dip.spectator( conf );
DipoleSplittingInfo candidate( dip.index( conf ) ,
conf , dip.emitterX( conf ) ,
dip.spectatorX( conf ) ,
emitter , spectator );
if ( DSH()->generators().find( candidate.index() ) ==
DSH()->generators().end() )
DSH()->getGenerators( candidate.index() );
auto const & gens = DSH()->generators().equal_range( candidate.index() );
for ( auto gen = gens.first; gen != gens.second; ++gen ) {
if ( !( gen->first == candidate.index() ) )
continue;
Energy dScale = gen->second->splittingKinematics()->dipoleScale(
emitter->momentum() , spectator->momentum() );
candidate.scale( dScale );
candidate.continuesEvolving();
Energy ptMax = gen->second->
splittingKinematics()->ptMax(
- candidate.scale() , candidate.emitterX() ,
- candidate.spectatorX() , candidate.index() ,
+ candidate.scale() ,
+ candidate.emitterX() ,
+ candidate.spectatorX() ,
+ candidate ,
*gen->second->splittingKernel() );
candidate.hardPt( min( running , ptMax ) );
if ( candidate.hardPt()>next ){
res += gen->second->sudakovExpansion( candidate , next , fixedScale );
}
}
return res;
}
void Merger::firstNodeMap( MatchboxMEBasePtr a , NodePtr b ){
theFirstNodeMap.insert( { a , b } );
}
map<MatchboxMEBasePtr , NodePtr> Merger::firstNodeMap()const{return theFirstNodeMap;}
void Merger::setXComb( tStdXCombPtr xc ){
currentNode()->setXComb( xc );
}
void Merger::setKinematics( ){
currentNode()->setKinematics();
}
void Merger::clearKinematics( ){
currentNode()->clearKinematics();
}
void Merger::flushCaches(){
if (currentNode()&&currentNode()->xcomb()->lastParticles().first) {
currentNode()->flushCaches();
}
}
bool Merger::generateKinematics( const double * r ){
return currentNode()->firstgenerateKinematics( r , ! currentNode()->subtractedReal() );
}
bool Merger::matrixElementRegion( PVector incoming , PVector outgoing , Energy winnerScale , Energy cutscale )const{
Energy ptx = Constants::MaxEnergy;
bool foundwinnerpt = false;
using namespace boost;
//FF
for( auto const & em : outgoing ){ if ( ! em->coloured() ) continue;
for( auto const & emm : outgoing ){ if ( !emm->coloured() ) continue; if ( em == emm ) continue;
for( auto const & spe : outgoing ){ if ( !spe->coloured() ) continue; if ( em == spe||emm == spe ) continue;
if ( !( em->id() == -emm->id()||emm->id()>6 ) )continue;
Energy pt = ZERO;
if ( em->momentum().m()<= 10_MeV &&
emm->momentum().m()<= 10_MeV &&
spe->momentum().m()<= 10_MeV ) {
pt = FFLTK->lastPt( em->momentum() , emm->momentum() , spe->momentum() );
}else{
pt = FFMTK->lastPt( em->momentum() , emm->momentum() , spe->momentum() );
}
if ( abs( pt-winnerScale ) < 10_MeV ) {
foundwinnerpt = true;
}
ptx = min( ptx , pt );
}
}
}
//FI
for( auto const & spe : incoming ){ if ( ! spe->coloured() ) continue;
for( auto const & emm : outgoing ){ if ( ! emm->coloured() ) continue;
for( auto const & em : outgoing ){ if ( ! em->coloured() ) continue; if ( em == emm ) continue;
if ( !( em->id() == -emm->id() || emm->id()>6 ) )continue;
Energy pt = ZERO;
if ( em->momentum().m()<= 10_MeV &&
emm->momentum().m()<= 10_MeV &&
spe->momentum().m()<= 10_MeV ) {
pt = FILTK->lastPt( em->momentum() , emm->momentum() , spe->momentum() );
}else{
pt = FIMTK->lastPt( em->momentum() , emm->momentum() , spe->momentum() );
}
if ( abs( pt-winnerScale )<10_MeV ) {
foundwinnerpt = true;
}
if( pt > ZERO )
ptx = min( ptx , pt );
}
}
}
//IF
for( auto const & em : incoming ){ if ( ! em->coloured() ) continue;
for( auto const & emm : outgoing ){ if ( ! emm->coloured() ) continue;
for( auto const & spe : outgoing ){ if ( ! spe->coloured() ) continue; if ( emm == spe ) continue;
if ( !( em->id()>6|| em->id() == emm->id() ||emm->id()>6 ) )continue;
Energy pt = ZERO;
if ( em->momentum().m()<= 10_MeV &&
emm->momentum().m()<= 10_MeV &&
spe->momentum().m()<= 10_MeV ) {
//massless
pt = IFLTK->lastPt( em->momentum() , emm->momentum() , spe->momentum() );
}else{
//massiv
pt = IFMTK->lastPt( em->momentum() , emm->momentum() , spe->momentum() );
}
if ( abs( pt-winnerScale )< 10_MeV ) {
foundwinnerpt = true;
}
ptx = min( ptx , pt );
}
}
}
//II
for( auto const & em : incoming ){ if ( ! em->coloured() ) continue;
for( auto const & spe : incoming ){ if ( ! spe->coloured() ) continue; if ( em == spe ) continue;
for( auto const & emm : outgoing ){ if ( ! emm->coloured() ) continue;
if ( !( em->id()>6||em->id() == emm->id() ||emm->id()>6 ) )continue;
Energy pt = IILTK->lastPt( em->momentum() , emm->momentum() , spe->momentum() );
if ( abs( pt-winnerScale )< 10_MeV ) {
foundwinnerpt = true;
}
ptx = min( ptx , pt );
}
}
}
if( !foundwinnerpt ){
generator()->logWarning( Exception()
<< "Merger: Could not find winner with pt."
<< "Run with -d3 to get phase space points. "
<< Exception::warning );
if( Debug::level > 2 ) {
generator()->log() << "\nWarning: could not find winner with pt: " << winnerScale/GeV;
for( auto const & emm : incoming ){
generator()->log() << "\n" << emm->id() << " " << emm->momentum()/GeV << " " << emm->momentum().m()/GeV << flush;
}
for( auto const & emm : outgoing ){
generator()->log() <<"\n" << emm->id() << " " << emm->momentum()/GeV << " " << emm->momentum().m()/GeV << flush;
}
}
}
return ( ptx>cutscale ) ;
}
bool Merger::notOnlyMulti() const {
return ( treefactory()->onlymulti() != -1&&
treefactory()->onlymulti() !=
int( currentNode()->legsize()-( projected ? 1 : 0 ) ) );
}
int Merger::M()const{return theTreeFactory->M();}
int Merger::N()const{return theTreeFactory->N();}
void Merger::debugVirt(double weight,double w1,double w2,double w3,
CrossSection matrixElement,double ww1,double ww2,
double ww3, NodePtr node,CrossSection bornWeight)const{
Energy minPT = Constants::MaxEnergy;
for( auto const & no :currentNode()->children() )minPT = min( no->pT() , minPT );
generator()->log() << "\nVIRT " << minPT/GeV << " " << weight << " " << w1;
generator()->log() << " " << w2;
generator()->log() << " " << w3;
generator()->log() << " " << ( matrixElement/nanobarn ) << " " << ww1 << " " << ww2 << " " << ww3 << " " << node->pT()/GeV << " " << node->nodeME()->mePartonData()[3]->mass()/GeV << " " << ( bornWeight*SM().alphaS()/( 2.*ThePEG::Constants::pi )/nanobarn );
}
void Merger::debugReal(string realstr, double weight,
CrossSection me, CrossSection dip)const {
Energy minPT = Constants::MaxEnergy;
for( auto const & no :currentNode()->children() )minPT = min( no->pT() , minPT );
generator()->log() << "\n"<<realstr <<" "<< minPT/GeV << " " << weight << " " << ( me-dip )/nanobarn << " " << me/nanobarn << " " << dip/nanobarn;
}
// If needed , insert default implementations of virtual function defined
// in the InterfacedBase class here ( using ThePEG-interfaced-impl in Emacs ).
#include "ThePEG/Persistency/PersistentOStream.h"
void Merger::persistentOutput( PersistentOStream & os ) const {
os << theShowerExpansionWeights << theCMWScheme << projected <<
isUnitarized << isNLOUnitarized <<
- theOpenZBoundaries << theChooseHistory <<
+ theChooseHistory <<
theN0 << theOnlyN << weight <<
theGamma << theSmearing << ounit( theIRSafePT , GeV ) <<
ounit( theMergePt , GeV ) << ounit( theCentralMergePt , GeV )
<< theLargeNBasis << FFLTK << FILTK <<
IFLTK << IILTK << FFMTK << FIMTK << IFMTK <<
theDipoleShowerHandler << theTreeFactory <<
theFirstNodeMap<<theRealSubtractionRatio << emitDipoleMEDiff;
}
#include "ThePEG/Persistency/PersistentIStream.h"
void Merger::persistentInput( PersistentIStream & is , int ) {
is >> theShowerExpansionWeights >> theCMWScheme >> projected >>
isUnitarized >> isNLOUnitarized >>
- theOpenZBoundaries >>
theChooseHistory >> theN0 >> theOnlyN >>
weight >>
theGamma >> theSmearing >> iunit( theIRSafePT , GeV ) >>
iunit( theMergePt , GeV ) >>
iunit( theCentralMergePt , GeV ) >> theLargeNBasis >>
FFLTK >> FILTK >> IFLTK >>
IILTK >> FFMTK >> FIMTK >>
IFMTK >> theDipoleShowerHandler >> theTreeFactory >>
theFirstNodeMap >> theRealSubtractionRatio >> emitDipoleMEDiff;
}
// *** Attention *** The following static variable is needed for the type
// description system in ThePEG. Please check that the template arguments
// are correct ( the class and its base class ) , and that the constructor
// arguments are correct ( the class name and the name of the dynamically
// loadable library where the class implementation can be found ).
#include "ThePEG/Utilities/DescribeClass.h"
DescribeClass<Merger , Herwig::MergerBase>
describeHerwigMerger( "Herwig::Merger" , "HwDipoleShower.so" );
//ClassDescription<Merger> Merger::initMerger;
// Definition of the static class description member.
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/Switch.h"
void Merger::Init() {
static ClassDocumentation<Merger> documentation
( "The Merger class takes care of merging multiple LO & NLO cross sections." );
//////////////////////////////////////////////////
static Switch<Merger , unsigned int>
interfaceShowerExpansionWeights
( "ShowerExpansionWeights" ,
"Calculate the expansions of the shower history to be NLO accurate, in different schemes." ,
&Merger::theShowerExpansionWeights ,
3 , false , false );
static SwitchOption
interfaceShowerExpansionWeightsScheme0
( interfaceShowerExpansionWeights ,
"NoWeights" ,
"Switch off the expansion." ,
0 );
static SwitchOption
interfaceShowerExpansionWeightsScheme1
( interfaceShowerExpansionWeights ,
"FlatAndHistoryReweighted" ,
"Sum alphaS expansion and weight with same Historyweight as LO." ,
1 );
static SwitchOption
interfaceShowerExpansionWeightsScheme2
( interfaceShowerExpansionWeights ,
"NoAlphaSReweightForSudakovExpansion" ,
"Switch off the expansion." ,
2 );
static SwitchOption
interfaceShowerExpansionWeightsScheme3
( interfaceShowerExpansionWeights ,
"NoAlphaSReweightForAllExpansions" ,
"Switch off the expansion." ,
3 );
static SwitchOption
interfaceShowerExpansionWeightsScheme4
( interfaceShowerExpansionWeights ,
"NoAlphaSReweightForAlphaSExpansion" ,
"Switch off the expansion." ,
4 );
- /////////////////////////////////////////////////////////////////////7
-
+ /////////////////////////////////////////////////////////////////////
static Switch<Merger , unsigned int>
interfacetheCMWScheme
( "CMWScheme" ,
"Use CMW-Scheme to calculate the alpha_s for the shower expressions." ,
&Merger::theCMWScheme ,
0 ,
false , false );
static SwitchOption interfacetheCMWSchemeNo
(interfacetheCMWScheme,
"No",
"No CMW-Scheme",
0);
static SwitchOption interfacetheCMWSchemeLinear
(interfacetheCMWScheme,
"Linear",
"Linear CMW multiplication: alpha_s(q) -> alpha_s(q)(1+K_g*alpha_s(q)/2pi )",
1);
static SwitchOption interfacetheCMWSchemeFactor
(interfacetheCMWScheme,
"Factor",
"Use factor in alpha_s argument: alpha_s(q) -> alpha_s(fac*q) with fac=exp(-(67-3pi^2-10/3*Nf)/(33-2Nf)) ",
2);
-
static Parameter<Merger , Energy> interfaceMergerScale
( "MergingScale" , "The MergingScale." ,
&Merger::theCentralMergePt ,
GeV , 20.0*GeV , 0.0*GeV , 0*GeV ,
false , false , Interface::lowerlim );
-
-
static Parameter<Merger , double> interfacegamma
( "gamma" ,
"gamma parameter." ,
&Merger::theGamma , 1.0 , 0.0 , 0 ,
false , false , Interface::lowerlim );
interfacegamma.rank(-1);
-
- static Switch<Merger,int> interfaceOpenZBoundariesM
- ("OpenZBoundaries", "",
- &Merger::theOpenZBoundaries, 0, false, false);
- static SwitchOption interfaceOpenZBoundariesMhardScale
- (interfaceOpenZBoundariesM, "Hard", "", 0);
- static SwitchOption interfaceOpenZBoundariesMfull
- (interfaceOpenZBoundariesM, "Full", "", 1);
- static SwitchOption interfaceOpenZBoundariesMDipoleScale
- (interfaceOpenZBoundariesM, "DipoleScale", "", 2);
-
-
-
static Switch<Merger , bool>
interfaceemitDipoleMEDiff
( "emitDipoleMEDiff" ,
"Allow emissions of the unitarisation contribution with prob. 1-min(B_n/sum Dip_n,sum Dip_n/B_n)" ,
&Merger::emitDipoleMEDiff , false , false , false );
static SwitchOption interfaceemitDipoleMEDiffYes
( interfaceemitDipoleMEDiff , "Yes" , "" , true );
static SwitchOption interfaceemitDipoleMEDiffNo
( interfaceemitDipoleMEDiff , "No" , "" , false );
interfaceemitDipoleMEDiff.rank(-1);
-
-
-
static Parameter<Merger , Energy> interfaceIRSafePT
( "IRSafePT" ,
"Set the pt for which a matrixelement should be treated as IR-safe." ,
&Merger::theIRSafePT ,
GeV , 0.0 * GeV , ZERO , Constants::MaxEnergy ,
true , false , Interface::limited );
interfaceIRSafePT.setHasDefault( false );
static Parameter<Merger , double> interfacemergePtsmearing(
"MergingScaleSmearing" ,
"Set the percentage the merging pt should be smeared." ,
&Merger::theSmearing ,
0. , 0. , 0.0 , 0.5 ,
true , false , Interface::limited );
static Parameter<Merger , int> interfacechooseHistory(
"chooseHistory" ,
"Various ways of choosing the history weights: 0(default):dipole xs, 1:dipole/born, 2:flat, 3: 1/pt_dip" ,
&Merger::theChooseHistory ,
3 , -1 , 0 ,
false , false , Interface::lowerlim );
static Parameter<Merger , double> interfacetheRealSubtractionRatio(
"RealSubtractionRatio" ,
"If the pt of the Dipole divided by the merging scale is lower than the ratio, the dipole is used to subtract the real emission. Otherwise the shower approximation is used, " ,
&Merger::theRealSubtractionRatio , 0. , 0. ,
1. , 10.0 ,
true , false , Interface::limited );
}
diff --git a/Shower/Dipole/Merging/Merger.h b/Shower/Dipole/Merging/Merger.h
--- a/Shower/Dipole/Merging/Merger.h
+++ b/Shower/Dipole/Merging/Merger.h
@@ -1,410 +1,408 @@
/// -*- C++ -*-
//
/// Merger.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_Merger_H
#define HERWIG_Merger_H
//
/// This is the declaration of the Merger class.
//
#include "MergingFactory.fh"
#include "Node.fh"
#include "ThePEG/Handlers/HandlerBase.h"
#include "Herwig/Shower/Dipole/DipoleShowerHandler.h"
//#include "Herwig/Shower/Dipole/Base/DipoleSplittingGenerator.h"
#include "Herwig/MatrixElement/Matchbox/Base/MergerBase.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/FFLightTildeKinematics.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/IFLightTildeKinematics.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/FFMassiveTildeKinematics.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/IFMassiveTildeKinematics.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/FILightTildeKinematics.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/IILightTildeKinematics.h"
#include "Herwig/MatrixElement/Matchbox/Phasespace/FIMassiveTildeKinematics.h"
#include "ThePEG/Cuts/JetFinder.h"
#include "ThePEG/Cuts/Cuts.h"
namespace Herwig {
using namespace ThePEG;
class Merger;
ThePEG_DECLARE_POINTERS(Merger , MergerPtr );
typedef vector<NodePtr> NodePtrVec;
//definition of a history step
struct HistoryStep {
/// containing the full information
NodePtr node;
/// current sudakov weight of the history
double weight;
/// current scale of the history
Energy scale;
};
typedef vector< HistoryStep > History;
typedef multimap<DipoleIndex, Ptr<DipoleSplittingGenerator>::ptr> GeneratorMap2;
/**
* \ingroup DipoleShower
* \author Johannes Bellm
*
* \brief Merger handles the Merger ....... //TODO .
*
* @see \ref MergerInterfaces "The interfaces"
* defined for Merger.
*/
class Merger: public MergerBase {
friend class MergingFactory;
friend class Node;
public:
// define the ME region for a particle vector.
bool matrixElementRegion(PVector incoming,
PVector outgoing,
Energy winnerScale = ZERO,
Energy cutscale = ZERO)const;
/// return the current merging scale,
/// gets smeared around the central merging scale in generate kinematics.
Energy mergingScale()const{return theMergePt;}
/// return the current merging pt (should be unified with mergingScale)
Energy mergePt()const {return theMergePt;}
/// legsize of highest process with NLO corrections
int M()const;
/// legsize of the highest LO merged process
int N()const;
/// legsize of the production process
int N0()const{return theN0;}
/// cross section of as given by the merging
CrossSection MergingDSigDR();
/// ***** virtual functions of the base class ****///
/// set the current xcomb, called from ME
void setXComb( tStdXCombPtr );
/// set kinematics, called from ME
void setKinematics();
/// clear kinematics, called from ME
void clearKinematics();
/// generate kinematics, called from ME
bool generateKinematics( const double * );
/// generate kinematics, called from ME
void flushCaches();
/// return the current maximum legs, the shower should veto
size_t maxLegs() const {return theCurrentMaxLegs;}
/// set the current ME
void setME(MatchboxMEBasePtr me){
theCurrentME=me;
assert(theFirstNodeMap.count(theCurrentME));
theCurrentNode=theFirstNodeMap[theCurrentME];
}
/// allow emissions with a given probability.in the ME region
double emissionProbability() const{ return theEmissionProbability; }
/// set a probability of allowed emission into ME region.
void setEmissionProbability(double x){theEmissionProbability=x;}
protected:
/// the merging factory needs to set the legsize of the production process
void N0(int n){ theN0=n;}
/// return the large-N basis (TODO: implement check if born ME works with the choice)
Ptr<ColourBasis>::ptr largeNBasis()const{return theLargeNBasis;}
/// smear the merging pt
void smearMergePt(){
const double factor = 1. + (-1. + 2.*UseRandom::rnd() ) * smear();
theMergePt = factor * centralMergePt();
}
/// true if the phase space for initial emissions should not be restricted in z.
- int openZBoundaries()const{return theOpenZBoundaries;}
+ int openZBoundaries()const{return DSH()->showerPhaseSpaceOption();}
/// return the current ME
MatchboxMEBasePtr currentME() const { return theCurrentME; }
/// return the current Node
NodePtr currentNode() const { return theCurrentNode; }
/// the gamma parameter to subtract dipoles above a alpha parameter
/// and subtract the corresponding IPK operator
double gamma()const{return theGamma;}
private:
/// calculate a single sudakov step for a given dipole
double singlesudakov(Dipole, Energy, Energy, pair<bool, bool>);
/// calculate the sudakov supression for a clusternode between
/// the current running scale and next scale
bool dosudakov(NodePtr Born, Energy running, Energy next, double& sudakov0_n);
/// cleanup
void cleanup(NodePtr);
/// return true if the cluster node has the matching number of
/// legs to the current projector stage
bool isProjectorStage( NodePtr , int )const;
/**
* Calculate the staring scale:
* if Node is part of the production process, calculate according to the
* scale choice object in the merging scale objekt, else
* return max(scale as scalechoice , min(Mass(i, j)))
*/
Energy CKKW_StartScale(NodePtr) const;
/// prepare the sudakov calculation
void CKKW_PrepareSudakov(NodePtr, Energy);
/// number of active flavours as given by the shower
double Nf(Energy scale)const{return DSH()->Nf(scale);}
/// pointer to the factory
MergingFactoryPtr treefactory() const;
/// map from ME to first clusternode
map<MatchboxMEBasePtr, NodePtr> firstNodeMap() const ;
/// set the current merging pt, smeared in generate kinematics
void mergePt(Energy x) {theMergePt = x;}
/// return the central merging pt
Energy centralMergePt() const {return theCentralMergePt;}
private:
/// calculate the history weighted born cross section
CrossSection MergingDSigDRBornStandard();
/**
* calculate the history weighted born cross section
* add the difference of IPK with and without alpha parameter
* subtract the dipoles above the alpha parameter
*/
CrossSection MergingDSigDRBornGamma();
/// calculate the history weighted virtual contribution
CrossSection MergingDSigDRVirtualStandard();
/**
* calculate the history weighted real contribution
* splitted into 3 differnt contibutions
*/
CrossSection MergingDSigDRRealStandard();
/// calculate the history weighted real contribution
/// all dipoles above:
/// N*(R rnd(i)-Dip_i) history_i U(\phi^n_i)
CrossSection MergingDSigDRRealAllAbove();
/// calculate the history weighted real contribution
/// not all dipoles above:
/// (R - sum PS_i) history_rnd U(\phi^n+1)
CrossSection MergingDSigDRRealBelowSubReal();
/// calculate the history weighted real contribution
/// not all dipoles above:
/// rnd(i)-> N*(PS_i - Dip_i) history_i U(\phi^n_i)
CrossSection MergingDSigDRRealBelowSubInt();
/// max legssize the shower should veto for LO
size_t maxLegsLO() const {return N0()+N();}
/// Calculate the LO partonic cross section.
/// if diffalpha != 1, add the difference of IPK(1)-IPK(diffalpha)
CrossSection TreedSigDR(Energy startscale, double diffalpha=1.);
/// fill the projecting xcomb
Energy fillProjector(int);
/// fill the history, including calculation of sudakov supression
void fillHistory(Energy, NodePtr, NodePtr );
/// calculate the pdf ratio for the given clusternode
double pdfratio(NodePtr, Energy, Energy, int, bool fromIsME, bool toIsME);
/// return the pdf-ratio reweight for the history
double pdfReweight();
/// return the alpha_s reweight for the history
double alphaReweight(bool nocmw=false);
/// max legssize the shower should veto for NLO
size_t maxLegsNLO()const {return N0()+M();}
/// calculate the virtual contribution.
CrossSection LoopdSigDR(Energy startscale );
/// calculate alpha_s expansion of the pdf-ratios
double sumPdfReweightExpansion()const;
/// calculate alpha_s expansion of the alpha_s-ratios, including K_g
double sumAlphaSReweightExpansion()const;
/// calculate alpha_s expansion of the sudakov exponents
double sumFillHistoryExpansion();
/// calculate alpha_s expansion of the single step alpha_s-ratio, including K_g
double alphasExpansion( Energy next, Energy fixedScale)const;
/// calculate alpha_s expansion of the single step pdf-ratio
double pdfExpansion(NodePtr, int, Energy, Energy, double, int, Energy)const;
/// calculate alpha_s expansion of the single step sudakov exponent
bool doHistExpansion(NodePtr Born, Energy running, Energy next, Energy fixedScale, double& HistExpansion);
/// calculate alpha_s expansion of the single dipole sudakov exponent
double singleHistExpansion(Dipole, Energy, Energy, Energy, pair<bool, bool>);
//alpha_s as given in the shower
double as(Energy q)const{return DSH()->as(q);}
// set the pointer to the Mergingfactory.
void setFactory(MergingFactoryPtr f){theTreeFactory=f;}
// set the pointer to the DipoleShower.
void setDipoleShower(DipoleShowerHandlerPtr dsh){theDipoleShowerHandler=dsh;}
//return the dipole shower handler
DipoleShowerHandlerPtr DSH(){return theDipoleShowerHandler;}
//return the const dipole shower handler
cDipoleShowerHandlerPtr DSH()const{return theDipoleShowerHandler;}
/// insert map from ME to first clusternode
void firstNodeMap(MatchboxMEBasePtr, NodePtr);
/// history choice: weighted history choice
int chooseHistory()const {return theChooseHistory;}
/// the smearing factor for the merging scale
double smear()const{return theSmearing;}
/// return the large-N colour basis
void largeNBasis(Ptr<ColourBasis>::ptr x){theLargeNBasis=x;}
/// helper function to check the only multi condition.
bool notOnlyMulti()const;
/// Calculate the CMW AlphaS
double cmwAlphaS(Energy q)const;
/// debug output for virtual
void debugVirt(double, double, double, double, CrossSection,
double, double, double, NodePtr,CrossSection) const;
/// debug output for reals
void debugReal( string, double, CrossSection, CrossSection) const;
private:
/// calculate the history expansion
unsigned int theShowerExpansionWeights = 2;
/// use CMW scheme
unsigned int theCMWScheme = 0;
/// true if current point should be projected
bool projected = true;
/// true if LO cross sections should be unitarised
bool isUnitarized = true;
/// true if NLO contributions should be unitarised
bool isNLOUnitarized = true;
- /// no z-restricions on initial state emissions in clustering
- int theOpenZBoundaries = 0;
/// history weight choice
int theChooseHistory = 0;
/// legsize of production process
int theN0 = 0;
/// calculate only the N particle contribution
int theOnlyN = -1;
/// the current maxlegs (either LO or NLO maxlegs)
size_t theCurrentMaxLegs = -1;
/// current weight and weight of clustered born
double weight = 1.0;
double weightCB = 1.0;
/// subtract the dipole contribution above a given gamma
double theGamma = 1.0;
/// smearing factor for merging scale
double theSmearing = 0.;
/**
* Allow emissions for the unitarising LO contributions
* according to the prob 1-min(B_n/sum Dip_n,Dip_n/B_n)
*/
bool emitDipoleMEDiff = false;
/// The conditional emission probability if emitDipoleMEDiff is true.
double theEmissionProbability = 0.;
/// cutoff for real emission contribution
Energy theIRSafePT = 1_GeV;
/// current merging scale
Energy theMergePt = 4_GeV;
/// central merging scale
Energy theCentralMergePt = 4_GeV;
/// below mergingscale/theRealSubtractionRatio the dipoles are used to subtract.
/// above the shower approximation is in use.
double theRealSubtractionRatio=3.;
/// current cluster histoy including sudakov weights
History history;
/// pointer to the large-N basis
Ptr<ColourBasis>::ptr theLargeNBasis;
/// current Node
NodePtr theCurrentNode;
/// current ME
MatchboxMEBasePtr theCurrentME;
/// Tilde kinematics pointers, only to use lastPt(emitter, emission, spectator)
Ptr<FFLightTildeKinematics>::ptr FFLTK = new_ptr( FFLightTildeKinematics() );
Ptr<FILightTildeKinematics>::ptr FILTK = new_ptr( FILightTildeKinematics() );
Ptr<IFLightTildeKinematics>::ptr IFLTK = new_ptr( IFLightTildeKinematics() );
Ptr<IILightTildeKinematics>::ptr IILTK = new_ptr( IILightTildeKinematics() );
Ptr<FFMassiveTildeKinematics>::ptr FFMTK = new_ptr( FFMassiveTildeKinematics() );
Ptr<FIMassiveTildeKinematics>::ptr FIMTK = new_ptr( FIMassiveTildeKinematics() );
Ptr<IFMassiveTildeKinematics>::ptr IFMTK = new_ptr( IFMassiveTildeKinematics() );
//pointer to the shower handler
DipoleShowerHandlerPtr theDipoleShowerHandler;
/// pointer to the MergingFactory
MergingFactoryPtr theTreeFactory;
/// map from ME to first Node
map<MatchboxMEBasePtr, NodePtr> theFirstNodeMap;
/// map from ME to highest ME weight so far
map<NodePtr, CrossSection> theHighMeWeightMap;
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();
//@}
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;
//@}
// If needed, insert declarations of virtual function defined in the
// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
Merger & operator=(const Merger &) = delete;
};
}
#endif /* HERWIG_Merger_H */
diff --git a/Shower/Dipole/Merging/MergingFactory.cc b/Shower/Dipole/Merging/MergingFactory.cc
--- a/Shower/Dipole/Merging/MergingFactory.cc
+++ b/Shower/Dipole/Merging/MergingFactory.cc
@@ -1,646 +1,683 @@
// -*- C++ -*-
//
// MergeboxFactory.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the MergeboxFactory class.
//
#include "MergingFactory.h"
#include "Node.h"
#include "ThePEG/Repository/Repository.h"
#include "ThePEG/Utilities/ColourOutput.h"
using namespace Herwig;
using std::ostream_iterator;
IBPtr MergingFactory::clone() const {
return new_ptr(*this);
}
IBPtr MergingFactory::fullclone() const {
return new_ptr(*this);
}
void MergingFactory::doinit(){
MatchboxFactory::doinit();
if (subProcessGroups()) {
throw InitException() << "There are no subprocess groups in merging!";
}
}
void MergingFactory::productionMode() {
if(M()<0)
for ( vector<Ptr<MatchboxAmplitude>::ptr>::iterator amp
= amplitudes().begin(); amp != amplitudes().end(); ++amp ) {
Repository::clog() << "One-loop contributions from '"
<< (**amp).name()
<< "' are not required and will be disabled.\n"
<< flush;
(**amp).disableOneLoop();
}
MatchboxFactory::productionMode();
}
void MergingFactory::fillMEsMap() {
olpProcesses().clear();
assert( getProcesses().size() == 1 );
processMap[0] = getProcesses()[0];
if ( MH()->M() >= 0 )
setHighestVirt(processMap[0].size()+MH()->M());
MH()->N0(processMap[0].size());
for ( int i = 1 ; i <= MH()->N() ; ++i ) {
processMap[i] = processMap[i - 1];
processMap[i].push_back("j");
}
for ( int i = 0 ; i <= MH()->N() ; ++i ) {
const bool below_maxNLO = i < MH()->M() + 1;
vector<MatchboxMEBasePtr> ames
= makeMEs(processMap[i], orderInAlphaS() + i, below_maxNLO );
copy(ames.begin(), ames.end(), back_inserter(pureMEsMap()[i]));
}
}
#include "Herwig/MatrixElement/Matchbox/Base/DipoleRepository.h"
void MergingFactory::prepare_BV(int i) {
// check if we have virtual contributions
bool haveVirtuals = true;
for ( auto born : pureMEsMap()[i]) {
prepareME(born);
if ( born->isOLPTree() ) {
int id = orderOLPProcess(born->subProcess(),
born->matchboxAmplitude(),
ProcessType::treeME2);
born->olpProcess(ProcessType::treeME2,id);
id = orderOLPProcess(born->subProcess(),
born->matchboxAmplitude(),
ProcessType::colourCorrelatedME2);
born->olpProcess(ProcessType::colourCorrelatedME2,id);
bool haveGluon = false;
for ( const auto & p : born->subProcess().legs )
if ( p->id() == 21 ) {
haveGluon = true;
break;
}
if ( haveGluon ) {
id = orderOLPProcess(born->subProcess(),
born->matchboxAmplitude(),
ProcessType::spinColourCorrelatedME2);
born->olpProcess(ProcessType::spinColourCorrelatedME2,id);
}
}
if ( born->isOLPLoop() && i <= MH()->M() ) {
int id = orderOLPProcess(born->subProcess(),
born->matchboxAmplitude(),
ProcessType::oneLoopInterference);
born->olpProcess(ProcessType::oneLoopInterference,id);
if ( !born->onlyOneLoop() && born->needsOLPCorrelators() ) {
id = orderOLPProcess(born->subProcess(),
born->matchboxAmplitude(),
ProcessType::colourCorrelatedME2);
born->olpProcess(ProcessType::colourCorrelatedME2,id);
}
}
haveVirtuals &= born->haveOneLoop();
}
// check for consistent conventions on virtuals, if we are to include MH()->M()
if (!(i > MH()->M()||haveVirtuals))
throw InitException()
<< MH()->M()
<< " NLO corrections requested,\n"
<< "but no virtual contributions are found.";
}
void MergingFactory::prepare_R(int i) {
for ( auto real : pureMEsMap()[i])
prepareME(real);
}
#include "Herwig/MatrixElement/Matchbox/Base/DipoleRepository.h"
void MergingFactory::getVirtuals(MatchboxMEBasePtr nlo, bool clone){
const auto & partons = nlo->diagrams().front()->partons();
for ( auto I : DipoleRepository::insertionIOperators(dipoleSet()) )
if ( I->apply(partons) ){
auto myI = I;
if ( clone ) myI = I->cloneMe();
nlo->virtuals().push_back(myI);
}
for ( auto PK : DipoleRepository::insertionPKOperators(dipoleSet()) )
if ( PK->apply(partons) ){
auto myPK = PK;
if ( clone ) myPK = PK->cloneMe();
nlo->virtuals().push_back(myPK);
}
}
void MergingFactory::pushB(MatchboxMEBasePtr born, int i) {
MatchboxMEBasePtr bornme = born->cloneMe();
bornme->maxMultCKKW(1);
bornme->minMultCKKW(0);
string pname = fullName() + "/" + bornme->name() + ".Born";
if ( !(generator()->preinitRegister(bornme, pname)) )
throw InitException()
<< "Born ME "<< pname << " already existing.";
if (MH()->gamma()!=1.)
getVirtuals(bornme,false);
NodePtr clusternode = new_ptr(Node(bornme, 0, MH()));
clusternode->deepHead(clusternode);
MH()->firstNodeMap(bornme,clusternode);
bornme->merger(MH());
vector<NodePtr> current = {{clusternode}};
vector<NodePtr> children;
unsigned int k = 1;
while ( ! thePureMEsMap[i - k].empty() ) {
for ( auto tmp : current ){//j
tmp->birth(thePureMEsMap[i - k]);
for ( auto tmpchild : tmp->children() ) {//m
children.push_back(tmpchild);
}
}
current = children;
children.clear();
++k;
}
if ( MH()->N() > i )
bornme->needsCorrelations();
else
bornme->needsNoCorrelations();
bornme->cloneDependencies();
MEs().push_back(bornme);
}
void MergingFactory::pushV(MatchboxMEBasePtr born, int i) {
MatchboxMEBasePtr nlo = born->cloneMe();
string pname = fullName() + "/" + nlo->name() + ".Virtual";
if ( !(generator()->preinitRegister(nlo, pname)) )
throw InitException()
<< "Virtual ME "<< pname << " already existing.";
////////////////////////////////////NLO///////////////////////////
nlo->virtuals().clear();
getVirtuals(nlo , false);
if ( nlo->virtuals().empty() )
throw InitException()
<< "No insertion operators have been found for "
<< born->name() << ".\n";
nlo->doOneLoopNoBorn();
////////////////////////////////////NLO///////////////////////////
NodePtr clusternode = new_ptr(Node(nlo, 0,MH()));
clusternode->deepHead(clusternode);
clusternode->virtualContribution(true);
MH()->firstNodeMap(nlo,clusternode);
nlo->merger(MH());
vector<NodePtr> current = {{clusternode}};
vector<NodePtr> children;
unsigned int k = 1;
while ( ! thePureMEsMap[i - k].empty() ) {
for ( auto tmp : current ){
tmp->birth(thePureMEsMap[i - k]);
for ( auto tmpchild : tmp->children())
children.push_back(tmpchild);
}
current = children;
children.clear();
++k;
}
if ( nlo->isOLPLoop() ) {
int id = orderOLPProcess(nlo->subProcess(),
born->matchboxAmplitude(),
ProcessType::oneLoopInterference);
nlo->olpProcess(ProcessType::oneLoopInterference,id);
if ( !nlo->onlyOneLoop() && nlo->needsOLPCorrelators() ) {
id = orderOLPProcess(nlo->subProcess(),
born->matchboxAmplitude(),
ProcessType::colourCorrelatedME2);
nlo->olpProcess(ProcessType::colourCorrelatedME2,id);
}
}
nlo->needsCorrelations();
nlo->cloneDependencies();
MEs().push_back(nlo);
}
void MergingFactory::pushR(MatchboxMEBasePtr born, int i) {
MatchboxMEBasePtr bornme = born->cloneMe();
string pname = fullName() + "/" + bornme->name() + ".Real";
if ( !(generator()->preinitRegister(bornme, pname)) )
throw InitException()
<< "Subtracted ME " << pname << " already existing.";
NodePtr clusternode = new_ptr(Node(bornme, 1, MH()));
clusternode->deepHead(clusternode);
clusternode->subtractedReal(true);
MH()->firstNodeMap(bornme,clusternode);
bornme->merger(MH());
vector<NodePtr> current = {{clusternode}};
vector<NodePtr> children;
unsigned int k = 1;
while ( ! thePureMEsMap[i - k].empty() ) {
for ( auto tmp : current ){
tmp->birth(thePureMEsMap[i - k]);
for ( auto tmpchild : tmp->children())
children.push_back(tmpchild);
}
current = children;
children.clear();
++k;
}
if(clusternode->children().empty()){
// This is a finite real contribution.
// This process is included in the LO merging.
return;
}
if ( MH()->N() > i ) bornme->needsCorrelations();
else bornme->needsNoCorrelations();
bornme->cloneDependencies(pname);
MEs().push_back(bornme);
}
// MergingFactory should never order OLPs here,
// they're done elsewhere.
void MergingFactory::orderOLPs() {}
#include "ThePEG/Utilities/StringUtils.h"
vector<string> MergingFactory::parseProcess(string in) {
vector<string> process = StringUtils::split(in);
if ( process.size() < 3 )
throw Exception()
<< "MatchboxFactory: Invalid process."<< Exception::runerror;
for ( string & p : process) {
p = StringUtils::stripws(p);
}
theN = 0;
bool prodprocess = true;
vector<string> result;
for ( const string & p : process ) {
if ( p == "->" )
continue;
if (p=="[") {
prodprocess = false;
} else if (p=="]") {
prodprocess = false;
// TODO what if there's stuff after the bracket?
assert( p == process.back() );
break;
} else if (p=="[j") {
prodprocess = false;
++theN;
} else if (p=="j" && !prodprocess) {
++theN;
prodprocess = false;
} else if (p=="j]") {
++theN;
prodprocess = false;
// TODO what if there's stuff after the bracket?
assert( p == process.back() );
break;
} else if ( prodprocess ) {
result.push_back(p);
} else {
throw InitException()
<< "Unknown particle class \"" << p << '"'
<< " in the process definition merging bracket.\n"
<< "Only jets (\"j\") are supported at the moment.";
}
}
return result;
}
#include "Herwig/Utilities/Progress.h"
void MergingFactory::setup() {
useMe();
DipoleShowerHandlerPtr dsh=dynamic_ptr_cast<DipoleShowerHandlerPtr>(this->CKKWHandler());
- if(! dsh )throw InitException() << "The showerhandlerfor the MergingFactory must be the DipoleShower. ";
+ if(! dsh )throw InitException() << "The showerhandler for the MergingFactory must be the DipoleShower. ";
dsh->setMerger(MH());
MH()->setFactory(this);
MH()->setDipoleShower(dsh);
if(!ransetup){
generator()->log() <<"\nStarting merging setup.\n\n";
olpProcesses().clear();
externalAmplitudes().clear();
// We set the couplings in the ME to be fixed
// and reweight in the history weight for this.
setFixedCouplings(true);
setFixedQEDCouplings(true);
// rebind the particle data objects, can't use rebind() function
for ( auto & g : particleGroups()) {
for ( auto & p : g.second) {
p = getParticleData(p->id());
}
}
const PDVector& partons = particleGroups()["j"];
unsigned int nl = 0;
for ( const auto p : partons ) {
const Energy mass = p->hardProcessMass();
const long pid = p->id();
if ( abs(pid) < 7 && mass == ZERO )
++nl;
if ( pid > 0 && pid < 7 && mass == ZERO )
nLightJetVec( pid );
if ( pid > 0 && pid < 7 && mass != ZERO )
nHeavyJetVec( pid );
}
nLight(nl/2);
const PDVector& partonsInP = particleGroups()["p"];
for ( const auto pip : partonsInP )
if ( pip->id() > 0 && pip->id() < 7 && pip->hardProcessMass() == ZERO )
nLightProtonVec( pip->id() );
// fill the amplitudes
if ( !amplitudes().empty() ) fillMEsMap();
// Use the colour basis of the first element of amplitudes
// to set the large N colour basis for the MergingHelper
assert(!amplitudes().empty() );
if ( !amplitudes()[0]->colourBasis() )
throw Exception() << "MergingFactory::setup(): Expecting a colour basis object."
<< Exception::runerror;
auto largeNBasis =
amplitudes()[0]->colourBasis()->cloneMe();
largeNBasis->clear();
largeNBasis->doLargeN();
MH()->largeNBasis(largeNBasis);
// prepare the Born and virtual matrix elements
for ( int i = 0 ; i <= max(0, MH()->N()) ; ++i ) prepare_BV(i);
// prepare the real emission matrix elements
for ( int i = 0 ; i <= MH()->N() ; ++i ) prepare_R(i);
if (MH()->N()<=MH()->M()) {
throw InitException() << "Merging: The number of NLOs need to be"
<< "\nsmaller than the number of LO processes.\n";
}
// Order the external Amplitudes.
orderOLPs();
// start creating matrix elements
MEs().clear();
// count the subprocesses
size_t numb = 0;
size_t numv = 0;
size_t numr = 0;
for (int i = 0; i <= max(0, MH()->N()) ; ++i ) {
for ( auto born : thePureMEsMap[i] ) {
if (bornContributions()
) {
numb++;
}
}
}
for (int i = 0 ; i <=max(0, MH()->N()); ++i )
for ( auto virt : thePureMEsMap[i] )
if ( virtualContributions() && i <= MH()->M()) {
numv++;
}
for (int i = 1; i <= max(0, MH()->N()) ; ++i )
for ( auto real : thePureMEsMap[i] )
if (realContributions() && i <= MH()->M() + 1 ){
numr++;
}
+
+
+ if(int(numb+numv+numr) < theChunk){
+ throw InitException() << "You try to chunk (Chunk="<<theChunk<<") the number of "<<
+ "subprocesses ("<<int(numb+numv+numr)<<") into more parts than there are subprocesses.";
+ }
+ if(theChunk<theChunkPart)
+ throw InitException() <<" The ChunkPart is larger than the Chunk.";
+
+ if(theChunk > 0 && theChunkPart == 0 )
+ throw InitException() <<" Set the ChunkPart ( = "<<theChunkPart<<" ) to i in [1,..,N] with N=Chunk.";
+
+ if ( theChunkPart != 0 )
+ generator()->log() << ANSI::yellow
+ << "\n\nWarning: \nYou split up the runs into theChunks. This is no standard feature."
+ << "\nYou are now responsible to make sure to run all theChunk parts."
+ << "\nThis setup run is for: " << theChunkPart << "/" << theChunk<<"\n\n ";
+
+
+
generator()->log() << ANSI::red << "Preparing Merging: ";
generator()->log() << ANSI::green << numb << " x Born " << ANSI::red;
if (MH()->M()>-1) {
generator()->log() << ANSI::yellow << numv << " x Virtual ";
generator()->log() << ANSI::blue << numr << " x Real " << ANSI::red << flush;
}
+ int countchunk=0;
+
progress_display progressBar{ numb+numv+numr, generator()->log() };
- for (int i = 0; i <= max(0, MH()->N()) ; ++i ){
- for ( auto born : thePureMEsMap[i]){
- if (bornContributions() ){
- pushB(born, i);
- generator()->log() << ANSI::green;
- ++progressBar;
- generator()->log() << ANSI::reset;
- }
+
+ // insert the born contributions to ME vector
+ for (int i = 0; i <= max(0, MH()->N()) ; ++i )
+ for ( auto born : thePureMEsMap[i])
+ if (bornContributions() ){
+ countchunk++; // theChunkPart is in [1,...,theChunk]
+ if ( theChunk == 0 || theChunkPart == countchunk ) pushB( born , i );
+ if ( countchunk == theChunk ) countchunk=0;
+ generator()->log() << ANSI::green;
+ ++progressBar;
+ generator()->log() << ANSI::reset;
}
- }
+ // insert the virtual contributions to ME vector
+ for (int i = 0 ; i <=max(0, MH()->N()); ++i )
+ for ( auto virt : thePureMEsMap[i])
+ if ( virtualContributions() && i <= MH()->M()){
+ countchunk++;// theChunkPart is in [1,...,theChunk]
+ if ( theChunk == 0 || theChunkPart == countchunk ) pushV(virt, i);
+ if ( countchunk == theChunk ) countchunk=0;
+ generator()->log() << ANSI::yellow;
+ ++progressBar;
+ }
+ // insert the real contributions to ME vector
+ for (int i = 1; i <= max(0, MH()->N()) ; ++i )
+ for ( auto real : thePureMEsMap[i] )
+ if (realContributions()&& i <= MH()->M() + 1 ){
+ countchunk++;// theChunkPart is in [1,...,theChunk]
+ if ( theChunk == 0 || theChunkPart == countchunk ) pushR(real, i);
+ if ( countchunk == theChunk ) countchunk=0;
+ generator()->log() << ANSI::blue;
+ ++progressBar;
+ }
-
-
-
- for (int i = 0 ; i <=max(0, MH()->N()); ++i )
- for ( auto virt : thePureMEsMap[i])
- if ( virtualContributions() && i <= MH()->M()){
- pushV(virt, i);
- generator()->log() << ANSI::yellow;
- ++progressBar;
- }
-
- for (int i = 1; i <= max(0, MH()->N()) ; ++i )
- for ( auto real : thePureMEsMap[i] )
- if (realContributions()&& i <= MH()->M() + 1 ){
- pushR(real, i);
- generator()->log() << ANSI::blue;
- ++progressBar;
- }
generator()->log() << ANSI::reset;
if ( !externalAmplitudes().empty() ) {
generator()->log() << "Initializing external amplitudes." << endl;
progress_display progressBar{ externalAmplitudes().size(), generator()->log() };
for ( const auto ext : externalAmplitudes() ) {
if ( ! ext->initializeExternal() ) {
throw InitException()
<< "error: failed to initialize amplitude '" << ext->name() << "'\n";
}
++progressBar;
}
generator()->log()
<< "---------------------------------------------------" << endl;
}
if ( !olpProcesses().empty() ) {
generator()->log() << "Initializing one-loop provider(s)." << endl;
map<Ptr<MatchboxAmplitude>::tptr, map<pair<Process, int>, int> > olps;
for (const auto oit : olpProcesses()) {
olps[oit.first] = oit.second;
}
progress_display progressBar{ olps.size(), generator()->log() };
for ( const auto olpit : olps ) {
if ( !olpit.first->startOLP(olpit.second) ) {
throw InitException() << "error: failed to start OLP for amplitude '" << olpit.first->name() << "'\n";
}
++progressBar;
}
generator()->log()
<< "---------------------------------------------------\n" << flush;
}
generator()->log() <<"\nGenerated "<<MEs().size()<<" Subprocesses.\n"<<flush;
generator()->log()
<< "---------------------------------------------------\n" << flush;
generator()->log() <<"\n\n" << ANSI::red
<<"Note: Due to the unitarization of the higher "
<<"\nmultiplicities, the individual cross sections "
<<"\ngiven in the integration and run step are not"
<<"\nmeaningful without merging." << ANSI::reset << endl;
ransetup=true;
}
}
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
void MergingFactory::persistentOutput(PersistentOStream & os) const {
os
<< theonlymulti
<< ransetup
- << processMap << theMergingHelper <<theM<<theN<<theNonQCDCuts;
+ << processMap << theMergingHelper <<theM<<theN<<theNonQCDCuts<<theChunk<<theChunkPart;
}
void MergingFactory::persistentInput(PersistentIStream & is, int) {
is
>> theonlymulti
>> ransetup
- >> processMap >> theMergingHelper >>theM>>theN>>theNonQCDCuts;
+ >> processMap >> theMergingHelper >>theM>>theN>>theNonQCDCuts>>theChunk>>theChunkPart;
}
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Command.h"
void MergingFactory::Init() {
static Parameter<MergingFactory, int> interfaceonlymulti("onlymulti",
"Calculate only the ME with k additional partons.",
&MergingFactory::theonlymulti, -1, -1, 0,
false, false, Interface::lowerlim);
static Switch<MergingFactory, bool> interface_Unitarized("Unitarized",
"Unitarize the cross section (default is unitarised. NLO merging must be unitarised).",
&MergingFactory::unitarized, true, false, false);
static SwitchOption interface_UnitarizedYes(interface_Unitarized, "Yes",
"Switch on the unitarized cross section.", true);
static SwitchOption interface_UnitarizedNo(interface_Unitarized, "No",
"Switch off the unitarized cross section.", false);
static Reference<MergingFactory,Merger> interfaceMergingHelper("MergingHelper",
"Pointer to the Merging Helper.",
&MergingFactory::theMergingHelper, false, false, true, true, false);
static Parameter<MergingFactory, int> interfaceaddNLOLegs("NLOProcesses",
"Set the number of virtual corrections to consider. 0 is default for no virtual correction.",
&MergingFactory::theM, 0, 0, 0, false, false, Interface::lowerlim);
static Reference<MergingFactory, Cuts > interfaceNonQcdCuts("NonQCDCuts",
"Cut on non-QCD modified observables. Be carefull!",
&MergingFactory::theNonQCDCuts, false, false, true, true, false);
+
+
+ static Parameter<MergingFactory, int> interfacetheChunk("Chunk",
+ "Cut the number of subprocesses into n theChunks.",
+ &MergingFactory::theChunk, -1, -1, 0,
+ false, false, Interface::lowerlim);
+
+ static Parameter<MergingFactory, int> interfacetheChunkPart("ChunkPart",
+ "If theChunk is larger then 0, set this parameter to the n'th part. Make sure to add the ChunksParts afterwards.",
+ &MergingFactory::theChunkPart, -1, -1, 0,
+ false, false, Interface::lowerlim);
}
// *** Attention *** The following static variable is needed for the type
// description system in ThePEG. Please check that the template arguments
// are correct (the class and its base class), and that the constructor
// arguments are correct (the class name and the name of the dynamically
// loadable library where the class implementation can be found).
DescribeClass<MergingFactory, Herwig::MatchboxFactory>
describeHerwigMergingFactory("Herwig::MergingFactory", "HwDipoleShower.so");
diff --git a/Shower/Dipole/Merging/MergingFactory.h b/Shower/Dipole/Merging/MergingFactory.h
--- a/Shower/Dipole/Merging/MergingFactory.h
+++ b/Shower/Dipole/Merging/MergingFactory.h
@@ -1,168 +1,179 @@
/// -*- C++ -*-
//
/// MergingFactory.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_MergingFactory_H
#define HERWIG_MergingFactory_H
//
/// This is the declaration of the MergingFactory class.
//
#include "MergingFactory.fh"
#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h"
#include "Node.fh"
#include "Merger.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
namespace Herwig {
using namespace ThePEG;
/**
* \ingroup Matchbox
* \author Johannes Bellm
*
* \brief MergingFactory automatically sets up a NLO
* QCD merging.
*
* @see \ref MergingFactoryInterfaces "The interfaces"
* defined for MergeboxFactory.
*/
class MergingFactory : public MatchboxFactory {
public:
///Check consistency and switch to porduction mode.
void productionMode();
/// main method to setup the ME vector
virtual void setup();
/// fill all amplitudes, stored in pureMEsMap
void fillMEsMap();
/// prepare the Born and virtual matrix elements.
void prepare_BV(int i);
/// prepare the real emission matrix elements.
void prepare_R(int i);
/// push the born contributions to the ME vector.
void pushB(MatchboxMEBasePtr, int);
//push the virtual contributions to the ME vector.
void pushV(MatchboxMEBasePtr, int);
/// push the real contributions to the ME vector.
void pushR(MatchboxMEBasePtr, int);
/// order matrix elements from one loop provider.
void orderOLPs();
/// Debugging: push only multiplicities to the ME vector
/// in range of specified mulltiplicity.
int onlymulti()const {
return theonlymulti==-1?-1:(theonlymulti+processMap.find(0)->second.size());
}
/// pointer to the merging helper.
MergerPtr MH() {return theMergingHelper;}
/// maximal NLO mulitplicity: 0=NLO corrections to the productio process.
int M() const {return theM-1;}
/// leg size of highest multiplicity.
int N() const {return theN;}
/// Return the Map of matrix elements to be considered
/// (the Key is the number of additional jets)
const map<int, vector<MatchboxMEBasePtr> >& pureMEsMap() const {
return thePureMEsMap;
}
/// Access the Map of matrix elements to be considered
/// (the Key is the number of additional jets)
map<int, vector<MatchboxMEBasePtr> >& pureMEsMap() {
return thePureMEsMap;
}
//Parse a process description
virtual vector<string> parseProcess(string);
// fill the virtuals vector (these are IPK-operators)
void getVirtuals(MatchboxMEBasePtr nlo, bool clone );
// In the merged setup we only produce single phase space points.
bool subProcessGroups() const { return false;}
// Cut on non-QCD observables.
Ptr<Cuts>::ptr nonQCDCuts(){return theNonQCDCuts;}
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);
//@}
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:
/** @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:
/// unitarise the LO contributions.
bool unitarized = true;
/// did run setup.
bool ransetup = false;
/// Debugging: push only multiplicities to the ME vector
/// in range of specified mulltiplicity.
int theonlymulti = -1;
/// maximal legsize for NLO corrections.
int theM = -1;
/// maximal legsize for LO contributions.
int theN = -1;
/// map for processes.
map< int, vector<string> > processMap;
//The matrix elements: int = number of additional jets
map< int, vector<MatchboxMEBasePtr> > thePureMEsMap;
/// the merging helper
MergerPtr theMergingHelper;
/// Cut on non-QCD modified observables.
- Ptr<Cuts>::ptr theNonQCDCuts;
+ Ptr<Cuts>::ptr theNonQCDCuts;
+
+ /// For more complicated processes the number of subprocesses is large.
+ /// This parameter allows to chunk the suprocesses into same sized cunks.
+ /// It is in the responsibility of the user to add all chunk parts afterwards.
+ /// The user also needs to take care that, e.g. output can be compined.
+ int theChunk=0;
+ /// This parameter selects a part chunkpart of the chunked subprocesses.
+ /// The user needs to take care to sum all chunkparts afterwards.
+ int theChunkPart=0;
+
+
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
MergingFactory & operator=(const MergingFactory &) = delete;
};
}
#endif /* HERWIG_MergingFactory_H */
diff --git a/Shower/Dipole/Merging/Node.cc b/Shower/Dipole/Merging/Node.cc
--- a/Shower/Dipole/Merging/Node.cc
+++ b/Shower/Dipole/Merging/Node.cc
@@ -1,553 +1,489 @@
// -*- C++ -*-
//
// This is the implementation of the non-inlined, non-templated member
// functions of the Node class.
//
#include "Node.h"
#include "MergingFactory.h"
#include "Merger.h"
using namespace Herwig;
Node::Node(MatchboxMEBasePtr nodeME, int cutstage, MergerPtr mh)
:Interfaced(),
thenodeMEPtr(nodeME),
thedipol(),
theparent(),
theCutStage(cutstage),
isOrdered(true),
theSubtractedReal(false),
theVirtualContribution(false),
theMergingHelper(mh)
{
nodeME->maxMultCKKW(1);
nodeME->minMultCKKW(0);
}
Node::Node(NodePtr deephead,
NodePtr head,
SubtractionDipolePtr dipol,
MatchboxMEBasePtr nodeME,
int cutstage)
:Interfaced(), thenodeMEPtr(nodeME),
thedipol(dipol),
theparent(head),
theDeepHead(deephead),
theCutStage(cutstage),
isOrdered(true),
theSubtractedReal(false),
theVirtualContribution(false),
theMergingHelper() //The subnodes have no merging helper
{
}
Node::~Node() { }
SubtractionDipolePtr Node::dipole() const {
return thedipol;
}
/** returns the matrix element pointer */
const MatchboxMEBasePtr Node::nodeME() const {
return thenodeMEPtr;
}
/** access the matrix element pointer */
MatchboxMEBasePtr Node::nodeME() {
return thenodeMEPtr;
}
pair<PVector , PVector> Node::getInOut( ){
PVector in;
const auto me= nodeME();
const auto pd=me->mePartonData();
for( auto i : {0 , 1} )
in.push_back(pd[i]->produceParticle( me->lastMEMomenta()[i] ) );
PVector out;
for ( size_t i = 2;i< pd.size();i++ ){
PPtr p = pd[i]->produceParticle( me->lastMEMomenta()[i] );
out.push_back( p );
}
return { in , out };
}
int Node::legsize() const {return nodeME()->legsize();}
NodePtr Node::randomChild() {
return thechildren[UseRandom::irnd(thechildren.size())];
}
bool Node::allAbove(Energy pt) {
for (NodePtr child : thechildren)
if ( child->pT() < pt )
return false;
return true;
}
Energy Node::maxChildPt(){
Energy maxi=-1*GeV;
for (NodePtr child : thechildren)maxi=max(child->pT(),maxi);
return maxi;
}
bool Node::isInHistoryOf(NodePtr other) {
while (other->parent()) {
if (other == this)
return true;
other = other->parent();
}
return false;
}
void Node::flushCaches() {
if (didflush) return;
didflush=true;
for ( auto const & ch: thechildren) {
ch->xcomb()->clean();
ch->nodeME()->flushCaches();
ch->flushCaches();
}
}
void Node::setKinematics() {
for (auto const & ch: thechildren) {
ch->dipole()->setXComb(ch->xcomb());
ch->dipole()->setKinematics();
ch->nodeME()->setKinematics();
ch->setKinematics();
}
}
void Node::clearKinematics() {
for (auto const & ch: thechildren) {
ch->dipole()->setXComb(ch->xcomb());
ch->nodeME()->clearKinematics();
ch->dipole()->clearKinematics();
ch->clearKinematics();
}
}
bool Node::generateKinematics(const double *r, bool directCut) {
didflush=false;
// If there are no children to the child process we are done.
if(children().empty()) return true;
assert(parent());
if ( ! directCut && pT() < deepHead()->MH()->mergePt()) {
// Real emission:
// If there are children to the child process,
// we now require that all subsequent children
// with pt < merging scale are in their ME region.
// Since the possible children of the real emission
// contribution are now in their ME region,
// it is clear that a second clustering is possible
// -- modulo phase space restrictions.
// Therefore the real emission contribution
// are unitarised and the cross section is
// hardly modified.
auto inOutPair = getInOut();
NodePtr rc = randomChild();
rc->dipole()->setXComb(rc->xcomb());
if(!rc->dipole()->generateKinematics(r))assert(false);
// If not in ME -> return false
if(!deepHead()->MH()->matrixElementRegion( inOutPair.first ,
inOutPair.second ,
rc->pT() ,
deepHead()->MH()->mergePt() ) )return false;
}
for (auto & ch : children() ) {
ch->dipole()->setXComb(ch->xcomb());
if ( !ch->dipole()->generateKinematics(r) ) { assert(false); }
ch->generateKinematics( r, true);
}
return true;
}
bool Node::firstgenerateKinematics(const double *r, bool directCut) {
didflush=false;
// This is called form the merging helper for the first node. So:
assert(!parent());
assert(xcomb());
if(MH()->treefactory()->nonQCDCuts()){
tcPDVector outdata(xcomb()->mePartonData().begin()+2,
xcomb()->mePartonData().end());
vector<LorentzMomentum> outmomenta(xcomb()->meMomenta().begin()+2,
xcomb()->meMomenta().end());
if ( !MH()->treefactory()->nonQCDCuts()->passCuts(outdata,outmomenta,
xcomb()->mePartonData()[0],
xcomb()->mePartonData()[1]) )
return false;
}
///// This should not be needed!!!
///// ( Warning inMerger::matrixElementRegion gets triggered.)
flushCaches();
//Set here the new merge Pt for the next phase space point.( Smearing!!!)
MH()->smearMergePt();
// If there are no children to this node, we are done here:
if (children().empty())
return true;
// directCut is for born and for virtual contributions.
// if directCut is true, then cut on the first ME region.
// call recursiv generate kinematics for subsequent nodes.
if ( directCut ){
auto inOutPair = getInOut();
NodePtr rc = randomChild();
rc->dipole()->setXComb(rc->xcomb());
if ( !rc->dipole()->generateKinematics(r) ) { return false; }
rc->nodeME()->setXComb(rc->xcomb());
if(MH()->gamma() == 1.){
if(!MH()->matrixElementRegion( inOutPair.first ,
inOutPair.second ,
rc->pT() ,
MH()->mergePt() ) ){
return false;
}
}else{
// Different treatment if gamma is not 1.
// Since the dipoles need to be calculated always
// their alpha region is touched.
// AlphaRegion != MERegion !!!
bool inAlphaPS = false;
for (auto const & ch: thechildren) {
ch->dipole()->setXComb(ch->xcomb());
if ( !ch->dipole()->generateKinematics(r) )
return false;
MH()->treefactory()->setAlphaParameter( MH()->gamma() );
inAlphaPS |= ch->dipole()->aboveAlpha();
MH()->treefactory()->setAlphaParameter( 1. );
}
NodePtr rc = randomChild();
if(!inAlphaPS&&
!MH()->matrixElementRegion( inOutPair.first ,
inOutPair.second ,
rc->pT() ,
MH()->mergePt() ) )
return false;
}
}
for (auto const & ch: thechildren) {
ch->dipole()->setXComb(ch->xcomb());
if ( !ch->dipole()->generateKinematics(r) ) { cout<<"\nCould not generate dipole kinematics";;return false; }
if( ! ch->generateKinematics(r,directCut) )return false;
}
return true;
}
StdXCombPtr Node::xcomb() const {
assert(thexcomb);
return thexcomb;
}
StdXCombPtr Node::xcomb(){
if(thexcomb)return thexcomb;
assert(parent());
thexcomb=dipole()->makeBornXComb(parent()->xcomb());
xcomb()->head(parent()->xcomb());
dipole()->setXComb(thexcomb);
return thexcomb;
}
void Node::setXComb(tStdXCombPtr xc) {
assert ( !parent() );
thexcomb=xc;
assert(thexcomb->lastParticles().first);
}
#include "Herwig/MatrixElement/Matchbox/Base/DipoleRepository.h"
void Node::birth(const vector<MatchboxMEBasePtr> & vec) {
// produce the children
vector<SubtractionDipolePtr> dipoles =
nodeME()->getDipoles(DipoleRepository::dipoles(
nodeME()->factory()->dipoleSet()), vec, true);
for ( auto const & dip : dipoles ) {
dip->doSubtraction();
NodePtr node = new_ptr(Node(theDeepHead,
this,
dip,
dip->underlyingBornME(),
theDeepHead->cutStage()));
thechildren.push_back(node);
}
}
-namespace{
-
- /**
- * Triangular / Kallen function
- */
- double rootOfKallen (double a, double b, double c) {
- return sqrt( a*a + b*b + c*c - 2.*( a*b+a*c+b*c ) ); }
-
-}
-
vector<NodePtr> Node::getNextOrderedNodes(bool normal, double hardScaleFactor) const {
vector<NodePtr> temp = children();
vector<NodePtr> res;
for (NodePtr const & child : children()) {
if(deepHead()->MH()->mergePt()>child->pT()) {
res.clear();
return res;
}
}
for (NodePtr const & child: children()) {
if (parent()&& normal) {
if ( child->pT() < pT() ) {
continue;
}
}
if ( child->children().size() != 0 ) {
for (NodePtr itChild: child->children()) {
if( itChild->pT() > child->pT()&&child->inShowerPS(itChild->pT()) ) {
res.push_back(child);
break;
}
}
}
else {
const auto sc=child->nodeME()->factory()->scaleChoice();
sc->setXComb(child->xcomb());
if ( sqr(hardScaleFactor)*
sc->renormalizationScale() >= sqr(child->pT()) &&
child->inShowerPS(hardScaleFactor*sqrt(sc->renormalizationScale()))) {
res.push_back(child);
}
}
}
return res;
}
bool Node::inShowerPS(Energy hardpT)const {
// Here we decide if the current phase space
// point can be reached from the underlying Node.
// Full phase space available -> Tilde Kinematic is always fine.
if(deepHead()->MH()->openZBoundaries()==1)
return true;
+
double z_ = dipole()->lastZ();
// restrict according to hard scale
if(deepHead()->MH()->openZBoundaries()==0){
pair<double, double> zbounds =
dipole()->tildeKinematics()->zBounds(pT(), hardpT);
return (zbounds.first<z_&&z_<zbounds.second);
}
- // restrict according to min ( dipole scale , kinematic limit )
- // where here due to the tilde kinematics always the kinematic
- // limit is produced. So
- assert(deepHead()->MH()->openZBoundaries()==2);
-
- if( dipole()->bornEmitter()>1&& dipole()->bornSpectator()>1 ) return true;
-
-
- bool isMassiv = (dipole()->tildeKinematics()->realEmitterData()->hardProcessMass()
- +dipole()->tildeKinematics()->realEmissionData()->hardProcessMass()
- +dipole()->tildeKinematics()->realSpectatorData()->hardProcessMass())!=ZERO;
-
- Energy scale=sqrt(2.*dipole()->tildeKinematics()->bornEmitterMomentum()*
- dipole()->tildeKinematics()->bornSpectatorMomentum());
-
- Energy hard=ZERO;
-
- assert(scale>=ZERO);
- // II
- if( dipole()->bornEmitter()<2&& dipole()->bornSpectator()<2 ) {
- hard = min(scale,(1.-dipole()->tildeKinematics()->emitterX())
- *scale/(2.*sqrt(dipole()->tildeKinematics()->emitterX())));
- }else
- // IF
- if( dipole()->bornEmitter()<2&& dipole()->bornSpectator() >= 2){
- if(isMassiv){
- hard = scale * min(1.,sqrt(1.-dipole()->tildeKinematics()->emitterX()) /2.);
- }
- else{
- hard = scale * min(1.,sqrt((1.-dipole()->tildeKinematics()->emitterX())/
- dipole()->tildeKinematics()->emitterX()) /2.);
- }
- }
- // FI
- else{
- if(isMassiv){
- Energy2 mi2 = sqr(dipole()->tildeKinematics()->realEmitterData()->hardProcessMass());
- Energy2 m2 = sqr(dipole()->tildeKinematics()->realEmissionData()->hardProcessMass());
- Energy2 Mi2 = sqr(dipole()->tildeKinematics()->bornEmitterData()->hardProcessMass());
- Energy2 scale=2.*dipole()->tildeKinematics()->bornEmitterMomentum()*
- dipole()->tildeKinematics()->bornSpectatorMomentum();
- Energy2 s = scale * (1.-dipole()->tildeKinematics()->spectatorX())/
- dipole()->tildeKinematics()->spectatorX() + Mi2;
- Energy2 sdip = scale + Mi2;
- hard = .5 * sqrt(s) * rootOfKallen( s/s, mi2/s, m2/s );
- hard = min( .5 * sqrt(sdip) * rootOfKallen( sdip/sdip, mi2/sdip, m2/sdip ),hard);
- }
- else{
- hard = scale*min(1.,sqrt((1.-dipole()->tildeKinematics()->spectatorX())/
- dipole()->tildeKinematics()->spectatorX())/2.);
- }
- }
-
- pair<double, double> zbounds =
- dipole()->tildeKinematics()->zBounds(pT(), hard);
+ assert(false);
- return (zbounds.first<z_&&z_<zbounds.second);
}
NodePtr Node::getHistory(bool normal, double hardScaleFactor) {
NodePtr res = this;
vector<NodePtr> temp = getNextOrderedNodes(normal, hardScaleFactor);
Energy minpt = Constants::MaxEnergy;
Selector<NodePtr> subprosel;
while (temp.size() != 0) {
minpt = Constants::MaxEnergy;
subprosel.clear();
for (NodePtr const & child : temp) {
assert(deepHead()->MH()->largeNBasis());
if( child->dipole()->underlyingBornME()->largeNColourCorrelatedME2(
{child->dipole()->bornEmitter(),
child->dipole()->bornSpectator()},
deepHead()->MH()->largeNBasis()) != 0.
) {
double weight = 1.;
if ( deepHead()->MH()->chooseHistory() == 0 )
weight = abs(child->dipole()->dSigHatDR()/nanobarn);
else if ( deepHead()->MH()->chooseHistory() == 1 )
weight = abs(child->dipole()->dSigHatDR()/child->nodeME()->dSigHatDRB());
else if ( deepHead()->MH()->chooseHistory() == 2 )
weight = 1.;
else if ( deepHead()->MH()->chooseHistory() == 3 )
weight = 1_GeV/child->pT();
else
assert(false);
if(weight != 0.) {
subprosel.insert(weight , child);
minpt = min(minpt, child->pT());
}
}
}
if (subprosel.empty())
return res;
res = subprosel.select(UseRandom::rnd());
temp = res->getNextOrderedNodes(true, hardScaleFactor);
}
return res;
}
pair<CrossSection, CrossSection> Node::calcDipandPS(Energy scale)const {
return dipole()->dipandPs(sqr(scale), deepHead()->MH()->largeNBasis());
}
CrossSection Node::calcPs(Energy scale)const {
return dipole()->ps(sqr(scale), deepHead()->MH()->largeNBasis());
}
CrossSection Node::calcDip(Energy scale)const {
return dipole()->dip(sqr(scale));
}
IBPtr Node::clone() const {
return new_ptr(*this);
}
IBPtr Node::fullclone() const {
return new_ptr(*this);
}
#include "ThePEG/Persistency/PersistentOStream.h"
void Node::persistentOutput(PersistentOStream & os) const {
os <<
thexcomb<<
thenodeMEPtr<<
thedipol<<
thechildren<<
theparent<<
theProjector<<
theDeepHead<<
theCutStage<<
ounit(theRunningPt, GeV)<<
theSubtractedReal<<
theVirtualContribution<<
theMergingHelper;
}
#include "ThePEG/Persistency/PersistentIStream.h"
void Node::persistentInput(PersistentIStream & is, int) {
is >>
thexcomb>>
thenodeMEPtr>>
thedipol>>
thechildren>>
theparent>>
theProjector>>
theDeepHead>>
theCutStage>>
iunit(theRunningPt, GeV)>>
theSubtractedReal>>
theVirtualContribution>>
theMergingHelper;
}
// *** Attention *** The following static variable is needed for the type
// description system in ThePEG. Please check that the template arguments
// are correct (the class and its base class), and that the constructor
// arguments are correct (the class name and the name of the dynamically
// loadable library where the class implementation can be found).
#include "ThePEG/Utilities/DescribeClass.h"
DescribeClass<Node, Interfaced>
describeHerwigNode("Herwig::Node", "HwDipoleShower.so");
void Node::Init() {
static ClassDocumentation<Node>
documentation("There is no documentation for the Node class");
}
diff --git a/Shower/QTilde/Base/ShowerParticle.cc b/Shower/QTilde/Base/ShowerParticle.cc
--- a/Shower/QTilde/Base/ShowerParticle.cc
+++ b/Shower/QTilde/Base/ShowerParticle.cc
@@ -1,585 +1,586 @@
// -*- C++ -*-
//
// ShowerParticle.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ShowerParticle class.
//
#include "ShowerParticle.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h"
#include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h"
#include <ostream>
using namespace Herwig;
PPtr ShowerParticle::clone() const {
return new_ptr(*this);
}
PPtr ShowerParticle::fullclone() const {
return new_ptr(*this);
}
ClassDescription<ShowerParticle> ShowerParticle::initShowerParticle;
// Definition of the static class description member.
void ShowerParticle::vetoEmission(ShowerPartnerType, Energy scale) {
scales_.QED = min(scale,scales_.QED );
scales_.QED_noAO = min(scale,scales_.QED_noAO );
scales_.QCD_c = min(scale,scales_.QCD_c );
scales_.QCD_c_noAO = min(scale,scales_.QCD_c_noAO );
scales_.QCD_ac = min(scale,scales_.QCD_ac );
scales_.QCD_ac_noAO = min(scale,scales_.QCD_ac_noAO);
scales_.EW = min(scale,scales_.EW );
+ if(spinInfo()) spinInfo()->undecay();
}
void ShowerParticle::addPartner(EvolutionPartner in ) {
partners_.push_back(in);
}
namespace {
LorentzRotation boostToShower(Lorentz5Momentum & porig, tShowerBasisPtr basis) {
LorentzRotation output;
assert(basis);
if(basis->frame()==ShowerBasis::BackToBack) {
// we are doing the evolution in the back-to-back frame
// work out the boostvector
Boost boostv(-(basis->pVector()+basis->nVector()).boostVector());
// momentum of the parton
Lorentz5Momentum ptest(basis->pVector());
// construct the Lorentz boost
output = LorentzRotation(boostv);
ptest *= output;
Axis axis(ptest.vect().unit());
// now rotate so along the z axis as needed for the splitting functions
if(axis.perp2()>1e-10) {
double sinth(sqrt(1.-sqr(axis.z())));
output.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
}
else if(axis.z()<0.) {
output.rotate(Constants::pi,Axis(1.,0.,0.));
}
porig = output*basis->pVector();
porig.setX(ZERO);
porig.setY(ZERO);
}
else {
output = LorentzRotation(-basis->pVector().boostVector());
porig = output*basis->pVector();
porig.setX(ZERO);
porig.setY(ZERO);
porig.setZ(ZERO);
}
return output;
}
RhoDMatrix bosonMapping(ShowerParticle & particle,
const Lorentz5Momentum & porig,
VectorSpinPtr vspin,
const LorentzRotation & rot,
Helicity::Direction dir) {
// rotate the original basis
vector<LorentzPolarizationVector> sbasis;
for(unsigned int ix=0;ix<3;++ix) {
sbasis.push_back(vspin->getProductionBasisState(ix));
sbasis.back().transform(rot);
}
// splitting basis
vector<LorentzPolarizationVector> fbasis;
bool massless(particle.id()==ParticleID::g||particle.id()==ParticleID::gamma);
VectorWaveFunction wave(porig,particle.dataPtr(),dir==outgoing ? incoming : outgoing);
for(unsigned int ix=0;ix<3;++ix) {
if(massless&&ix==1) {
fbasis.push_back(LorentzPolarizationVector());
}
else {
wave.reset(ix,vector_phase);
fbasis.push_back(wave.wave());
}
}
// work out the mapping
RhoDMatrix mapping=RhoDMatrix(PDT::Spin1,false);
for(unsigned int ix=0;ix<3;++ix) {
for(unsigned int iy=0;iy<3;++iy) {
mapping(ix,iy)= -conj(sbasis[ix].dot(fbasis[iy]));
if(particle.id()<0) mapping(ix,iy)=conj(mapping(ix,iy));
}
}
return mapping;
}
RhoDMatrix fermionMapping(ShowerParticle & particle,
const Lorentz5Momentum & porig,
FermionSpinPtr fspin,
const LorentzRotation & rot) {
// extract the original basis states
vector<LorentzSpinor<SqrtEnergy> > sbasis;
for(unsigned int ix=0;ix<2;++ix) {
sbasis.push_back(fspin->getProductionBasisState(ix));
sbasis.back().transform(rot);
}
// calculate the states in the splitting basis
vector<LorentzSpinor<SqrtEnergy> > fbasis;
SpinorWaveFunction wave(porig,particle.dataPtr(),
particle.id()>0 ? incoming : outgoing);
for(unsigned int ix=0;ix<2;++ix) {
wave.reset(ix);
fbasis.push_back(wave.dimensionedWave());
}
RhoDMatrix mapping=RhoDMatrix(PDT::Spin1Half,false);
for(unsigned int ix=0;ix<2;++ix) {
if(fbasis[0].s2()==complex<SqrtEnergy>()) {
mapping(ix,0) = sbasis[ix].s3()/fbasis[0].s3();
mapping(ix,1) = sbasis[ix].s2()/fbasis[1].s2();
}
else {
mapping(ix,0) = sbasis[ix].s2()/fbasis[0].s2();
mapping(ix,1) = sbasis[ix].s3()/fbasis[1].s3();
}
}
return mapping;
}
FermionSpinPtr createFermionSpinInfo(ShowerParticle & particle,
const Lorentz5Momentum & porig,
const LorentzRotation & rot,
Helicity::Direction dir) {
// calculate the splitting basis for the branching
// and rotate back to construct the basis states
LorentzRotation rinv = rot.inverse();
SpinorWaveFunction wave;
if(particle.id()>0)
wave=SpinorWaveFunction(porig,particle.dataPtr(),incoming);
else
wave=SpinorWaveFunction(porig,particle.dataPtr(),outgoing);
FermionSpinPtr fspin = new_ptr(FermionSpinInfo(particle.momentum(),dir==outgoing));
for(unsigned int ix=0;ix<2;++ix) {
wave.reset(ix);
LorentzSpinor<SqrtEnergy> basis = wave.dimensionedWave();
basis.transform(rinv);
fspin->setBasisState(ix,basis);
fspin->setDecayState(ix,basis);
}
particle.spinInfo(fspin);
return fspin;
}
VectorSpinPtr createVectorSpinInfo(ShowerParticle & particle,
const Lorentz5Momentum & porig,
const LorentzRotation & rot,
Helicity::Direction dir) {
// calculate the splitting basis for the branching
// and rotate back to construct the basis states
LorentzRotation rinv = rot.inverse();
bool massless(particle.id()==ParticleID::g||particle.id()==ParticleID::gamma);
VectorWaveFunction wave(porig,particle.dataPtr(),dir);
VectorSpinPtr vspin = new_ptr(VectorSpinInfo(particle.momentum(),dir==outgoing));
for(unsigned int ix=0;ix<3;++ix) {
LorentzPolarizationVector basis;
if(massless&&ix==1) {
basis = LorentzPolarizationVector();
}
else {
wave.reset(ix,vector_phase);
basis = wave.wave();
}
basis *= rinv;
vspin->setBasisState(ix,basis);
vspin->setDecayState(ix,basis);
}
particle.spinInfo(vspin);
vspin-> DMatrix() = RhoDMatrix(PDT::Spin1);
vspin->rhoMatrix() = RhoDMatrix(PDT::Spin1);
if(massless) {
vspin-> DMatrix()(0,0) = 0.5;
vspin->rhoMatrix()(0,0) = 0.5;
vspin-> DMatrix()(2,2) = 0.5;
vspin->rhoMatrix()(2,2) = 0.5;
}
return vspin;
}
}
RhoDMatrix ShowerParticle::extractRhoMatrix(bool forward) {
// get the spin density matrix and the mapping
RhoDMatrix mapping;
SpinPtr inspin;
bool needMapping = getMapping(inspin,mapping);
// set the decayed flag
inspin->decay();
// get the spin density matrix
RhoDMatrix rho = forward ? inspin->rhoMatrix() : inspin->DMatrix();
// map to the shower basis if needed
if(needMapping) {
RhoDMatrix rhop(rho.iSpin(),false);
for(int ixb=0;ixb<rho.iSpin();++ixb) {
for(int iyb=0;iyb<rho.iSpin();++iyb) {
if(mapping(iyb,ixb)==0.)continue;
for(int iya=0;iya<rho.iSpin();++iya) {
if(rho(iya,iyb)==0.)continue;
for(int ixa=0;ixa<rho.iSpin();++ixa) {
rhop(ixa,ixb) += rho(iya,iyb)*mapping(iya,ixa)*conj(mapping(iyb,ixb));
}
}
}
}
rhop.normalize();
rho = rhop;
}
return rho;
}
bool ShowerParticle::getMapping(SpinPtr & output, RhoDMatrix & mapping) {
// if the particle is not from the hard process
if(!this->perturbative()) {
// mapping is the identity
output=this->spinInfo();
mapping=RhoDMatrix(this->dataPtr()->iSpin());
if(output) {
return false;
}
else {
Lorentz5Momentum porig;
LorentzRotation rot = boostToShower(porig,showerBasis());
Helicity::Direction dir = this->isFinalState() ? outgoing : incoming;
if(this->dataPtr()->iSpin()==PDT::Spin0) {
assert(false);
}
else if(this->dataPtr()->iSpin()==PDT::Spin1Half) {
output = createFermionSpinInfo(*this,porig,rot,dir);
}
else if(this->dataPtr()->iSpin()==PDT::Spin1) {
output = createVectorSpinInfo(*this,porig,rot,dir);
}
else {
assert(false);
}
return false;
}
}
// if particle is final-state and is from the hard process
else if(this->isFinalState()) {
assert(this->perturbative()==1 || this->perturbative()==2);
// get transform to shower frame
Lorentz5Momentum porig;
LorentzRotation rot = boostToShower(porig,showerBasis());
// the rest depends on the spin of the particle
PDT::Spin spin(this->dataPtr()->iSpin());
mapping=RhoDMatrix(spin,false);
// do the spin dependent bit
if(spin==PDT::Spin0) {
ScalarSpinPtr sspin=dynamic_ptr_cast<ScalarSpinPtr>(this->spinInfo());
if(!sspin) {
ScalarWaveFunction::constructSpinInfo(this,outgoing,true);
}
output=this->spinInfo();
return false;
}
else if(spin==PDT::Spin1Half) {
FermionSpinPtr fspin=dynamic_ptr_cast<FermionSpinPtr>(this->spinInfo());
// spin info exists get information from it
if(fspin) {
output=fspin;
mapping = fermionMapping(*this,porig,fspin,rot);
return true;
}
// spin info does not exist create it
else {
output = createFermionSpinInfo(*this,porig,rot,outgoing);
return false;
}
}
else if(spin==PDT::Spin1) {
VectorSpinPtr vspin=dynamic_ptr_cast<VectorSpinPtr>(this->spinInfo());
// spin info exists get information from it
if(vspin) {
output=vspin;
mapping = bosonMapping(*this,porig,vspin,rot,outgoing);
return true;
}
else {
output = createVectorSpinInfo(*this,porig,rot,outgoing);
return false;
}
}
// not scalar/fermion/vector
else
assert(false);
}
// incoming to hard process
else if(this->perturbative()==1 && !this->isFinalState()) {
// get the basis vectors
// get transform to shower frame
Lorentz5Momentum porig;
LorentzRotation rot = boostToShower(porig,showerBasis());
porig *= this->x();
// the rest depends on the spin of the particle
PDT::Spin spin(this->dataPtr()->iSpin());
mapping=RhoDMatrix(spin);
// do the spin dependent bit
if(spin==PDT::Spin0) {
cerr << "testing spin 0 not yet implemented " << endl;
assert(false);
}
// spin-1/2
else if(spin==PDT::Spin1Half) {
FermionSpinPtr fspin=dynamic_ptr_cast<FermionSpinPtr>(this->spinInfo());
// spin info exists get information from it
if(fspin) {
output=fspin;
mapping = fermionMapping(*this,porig,fspin,rot);
return true;
}
// spin info does not exist create it
else {
output = createFermionSpinInfo(*this,porig,rot,incoming);
return false;
}
}
// spin-1
else if(spin==PDT::Spin1) {
VectorSpinPtr vspin=dynamic_ptr_cast<VectorSpinPtr>(this->spinInfo());
// spinInfo exists map it
if(vspin) {
output=vspin;
mapping = bosonMapping(*this,porig,vspin,rot,incoming);
return true;
}
// create the spininfo
else {
output = createVectorSpinInfo(*this,porig,rot,incoming);
return false;
}
}
assert(false);
}
// incoming to decay
else if(this->perturbative() == 2 && !this->isFinalState()) {
// get the basis vectors
Lorentz5Momentum porig;
LorentzRotation rot=boostToShower(porig,showerBasis());
// the rest depends on the spin of the particle
PDT::Spin spin(this->dataPtr()->iSpin());
mapping=RhoDMatrix(spin);
// do the spin dependent bit
if(spin==PDT::Spin0) {
cerr << "testing spin 0 not yet implemented " << endl;
assert(false);
}
// spin-1/2
else if(spin==PDT::Spin1Half) {
// FermionSpinPtr fspin=dynamic_ptr_cast<FermionSpinPtr>(this->spinInfo());
// // spin info exists get information from it
// if(fspin) {
// output=fspin;
// mapping = fermionMapping(*this,porig,fspin,rot);
// return true;
// // spin info does not exist create it
// else {
// output = createFermionSpinInfo(*this,porig,rot,incoming);
// return false;
// }
// }
assert(false);
}
// // spin-1
// else if(spin==PDT::Spin1) {
// VectorSpinPtr vspin=dynamic_ptr_cast<VectorSpinPtr>(this->spinInfo());
// // spinInfo exists map it
// if(vspin) {
// output=vspin;
// mapping = bosonMapping(*this,porig,vspin,rot);
// return true;
// }
// // create the spininfo
// else {
// output = createVectorSpinInfo(*this,porig,rot,incoming);
// return false;
// }
// }
// assert(false);
assert(false);
}
else
assert(false);
return true;
}
void ShowerParticle::constructSpinInfo(bool timeLike) {
// now construct the required spininfo and calculate the basis states
PDT::Spin spin(dataPtr()->iSpin());
if(spin==PDT::Spin0) {
ScalarWaveFunction::constructSpinInfo(this,outgoing,timeLike);
}
// calculate the basis states and construct the SpinInfo for a spin-1/2 particle
else if(spin==PDT::Spin1Half) {
// outgoing particle
if(id()>0) {
vector<LorentzSpinorBar<SqrtEnergy> > stemp;
SpinorBarWaveFunction::calculateWaveFunctions(stemp,this,outgoing);
SpinorBarWaveFunction::constructSpinInfo(stemp,this,outgoing,timeLike);
}
// outgoing antiparticle
else {
vector<LorentzSpinor<SqrtEnergy> > stemp;
SpinorWaveFunction::calculateWaveFunctions(stemp,this,outgoing);
SpinorWaveFunction::constructSpinInfo(stemp,this,outgoing,timeLike);
}
}
// calculate the basis states and construct the SpinInfo for a spin-1 particle
else if(spin==PDT::Spin1) {
bool massless(id()==ParticleID::g||id()==ParticleID::gamma);
vector<Helicity::LorentzPolarizationVector> vtemp;
VectorWaveFunction::calculateWaveFunctions(vtemp,this,outgoing,massless,vector_phase);
VectorWaveFunction::constructSpinInfo(vtemp,this,outgoing,timeLike,massless);
}
else {
throw Exception() << "Spins higher than 1 are not yet implemented in "
<< "FS_QtildaShowerKinematics1to2::constructVertex() "
<< Exception::runerror;
}
}
void ShowerParticle::initializeDecay() {
Lorentz5Momentum p, n, ppartner, pcm;
assert(perturbative()!=1);
// this is for the initial decaying particle
if(perturbative()==2) {
ShowerBasisPtr newBasis;
p = momentum();
Lorentz5Momentum ppartner(partner()->momentum());
// removed to make inverse recon work properly
//if(partner->thePEGBase()) ppartner=partner->thePEGBase()->momentum();
pcm=ppartner;
Boost boost(p.findBoostToCM());
pcm.boost(boost);
n = Lorentz5Momentum( ZERO,0.5*p.mass()*pcm.vect().unit());
n.boost( -boost);
newBasis = new_ptr(ShowerBasis());
newBasis->setBasis(p,n,ShowerBasis::Rest);
showerBasis(newBasis,false);
}
else {
showerBasis(dynamic_ptr_cast<ShowerParticlePtr>(parents()[0])->showerBasis(),true);
}
}
void ShowerParticle::initializeInitialState(PPtr parent) {
// For the time being we are considering only 1->2 branching
Lorentz5Momentum p, n, pthis, pcm;
assert(perturbative()!=2);
if(perturbative()==1) {
ShowerBasisPtr newBasis;
// find the partner and its momentum
if(!partner()) return;
if(partner()->isFinalState()) {
Lorentz5Momentum pa = -momentum()+partner()->momentum();
Lorentz5Momentum pb = momentum();
Energy scale=parent->momentum().t();
Lorentz5Momentum pbasis(ZERO,parent->momentum().vect().unit()*scale);
Axis axis(pa.vect().unit());
LorentzRotation rot;
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
if(axis.perp2()>1e-20) {
rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot.rotateX(Constants::pi);
}
if(abs(1.-pa.e()/pa.vect().mag())>1e-6) rot.boostZ( pa.e()/pa.vect().mag());
pb *= rot;
if(pb.perp2()/GeV2>1e-20) {
Boost trans = -1./pb.e()*pb.vect();
trans.setZ(0.);
rot.boost(trans);
}
pbasis *=rot;
rot.invert();
n = rot*Lorentz5Momentum(ZERO,-pbasis.vect());
p = rot*Lorentz5Momentum(ZERO, pbasis.vect());
}
else {
pcm = parent->momentum();
p = Lorentz5Momentum(ZERO, pcm.vect());
n = Lorentz5Momentum(ZERO, -pcm.vect());
}
newBasis = new_ptr(ShowerBasis());
newBasis->setBasis(p,n,ShowerBasis::BackToBack);
showerBasis(newBasis,false);
}
else {
showerBasis(dynamic_ptr_cast<ShowerParticlePtr>(children()[0])->showerBasis(),true);
}
}
void ShowerParticle::initializeFinalState() {
// set the basis vectors
Lorentz5Momentum p,n;
if(perturbative()!=0) {
ShowerBasisPtr newBasis;
// find the partner() and its momentum
if(!partner()) return;
Lorentz5Momentum ppartner(partner()->momentum());
// momentum of the emitting particle
p = momentum();
Lorentz5Momentum pcm;
// if the partner is a final-state particle then the reference
// vector is along the partner in the rest frame of the pair
if(partner()->isFinalState()) {
Boost boost=(p + ppartner).findBoostToCM();
pcm = ppartner;
pcm.boost(boost);
n = Lorentz5Momentum(ZERO,pcm.vect());
n.boost( -boost);
}
else if(!partner()->isFinalState()) {
// if the partner is an initial-state particle then the reference
// vector is along the partner which should be massless
if(perturbative()==1) {
n = Lorentz5Momentum(ZERO,ppartner.vect());
}
// if the partner is an initial-state decaying particle then the reference
// vector is along the backwards direction in rest frame of decaying particle
else {
Boost boost=ppartner.findBoostToCM();
pcm = p;
pcm.boost(boost);
n = Lorentz5Momentum( ZERO, -pcm.vect());
n.boost( -boost);
}
}
newBasis = new_ptr(ShowerBasis());
newBasis->setBasis(p,n,ShowerBasis::BackToBack);
showerBasis(newBasis,false);
}
else if(initiatesTLS()) {
showerBasis(dynamic_ptr_cast<ShowerParticlePtr>(parents()[0]->children()[0])->showerBasis(),true);
}
else {
showerBasis(dynamic_ptr_cast<ShowerParticlePtr>(parents()[0])->showerBasis(),true);
}
}
void ShowerParticle::setShowerMomentum(bool timeLike) {
Energy m = this->mass() > ZERO ? this->mass() : this->data().mass();
// calculate the momentum of the assuming on-shell
Energy2 pt2 = sqr(this->showerParameters().pt);
double alpha = timeLike ? this->showerParameters().alpha : this->x();
double beta = 0.5*(sqr(m) + pt2 - sqr(alpha)*showerBasis()->pVector().m2())/(alpha*showerBasis()->p_dot_n());
Lorentz5Momentum porig=showerBasis()->sudakov2Momentum(alpha,beta,
this->showerParameters().ptx,
this->showerParameters().pty);
porig.setMass(m);
this->set5Momentum(porig);
}
diff --git a/Shower/QTilde/Base/ShowerTree.cc b/Shower/QTilde/Base/ShowerTree.cc
--- a/Shower/QTilde/Base/ShowerTree.cc
+++ b/Shower/QTilde/Base/ShowerTree.cc
@@ -1,922 +1,923 @@
// -*- C++ -*-
//
// ShowerTree.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#include "ThePEG/EventRecord/MultiColour.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ShowerTree.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/ShowerHandler.h"
#include "ThePEG/PDT/DecayMode.h"
#include "ThePEG/Handlers/EventHandler.h"
#include "ThePEG/Handlers/XComb.h"
#include <cassert>
#include "ThePEG/Repository/CurrentGenerator.h"
#include "ThePEG/PDT/StandardMatchers.h"
using namespace Herwig;
using namespace ThePEG;
bool ShowerTree::_spaceTime = false;
Energy2 ShowerTree::_vmin2 = 0.1*GeV2;
namespace {
void findBeam(tPPtr & beam, PPtr incoming) {
while(!beam->children().empty()) {
bool found=false;
for(unsigned int ix=0;ix<beam->children().size();++ix) {
if(beam->children()[ix]==incoming) {
found = true;
break;
}
}
if(found) break;
beam = beam->children()[0];
}
}
}
ShowerTree::ShowerTree(PerturbativeProcessPtr process)
: _hardMECorrection(false),
_parent(), _hasShowered(false) {
// get the incoming and outgoing particles and make copies
vector<PPtr> original,copy;
for(unsigned int ix=0;ix<process->incoming().size();++ix) {
original.push_back(process->incoming()[ix].first);
copy .push_back(new_ptr(Particle(*original.back())));
}
for(unsigned int ix=0;ix<process->outgoing().size();++ix) {
original.push_back(process->outgoing()[ix].first);
copy .push_back(new_ptr(Particle(*original.back())));
}
// isolate the colour
colourIsolate(original,copy);
// hard process
unsigned int itype(1);
if(process->incoming().size()==2) {
_wasHard = true;
// set the beams and incoming particles
tPPair beam = CurrentGenerator::current().currentEvent()->incoming();
findBeam(beam.first ,process->incoming()[0].first);
findBeam(beam.second,process->incoming()[1].first);
_incoming = make_pair(process->incoming()[0].first,
process->incoming()[1].first);
double x1(_incoming.first ->momentum().rho()/beam.first ->momentum().rho());
double x2(_incoming.second->momentum().rho()/beam.second->momentum().rho());
// must have two incoming particles
assert(_incoming.first && _incoming.second);
// set the parent tree
_parent=ShowerTreePtr();
for(unsigned int ix=0;ix<2;++ix) {
ShowerParticlePtr temp=new_ptr(ShowerParticle(*copy[ix],itype,false));
fixColour(temp);
temp->x(ix==0 ? x1 : x2);
_incomingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[ix],
copy[ix],temp)),temp));
_backward.insert(temp);
}
}
// decay process
else if(process->incoming().size()==1) {
_wasHard = false;
itype=2;
// create the parent shower particle
ShowerParticlePtr sparent(new_ptr(ShowerParticle(*copy[0],itype,false)));
fixColour(sparent);
_incomingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[0],copy[0],sparent))
,sparent));
// return if not decayed
if(original.size()==1) return;
}
else
assert(false);
// create the children
assert(copy.size() == original.size());
for (unsigned int ix=process->incoming().size();ix<original.size();++ix) {
ShowerParticlePtr stemp= new_ptr(ShowerParticle(*copy[ix],itype,true));
fixColour(stemp);
_outgoingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[ix],copy[ix],
stemp)),
stemp));
_forward.insert(stemp);
}
}
void ShowerTree::updateFinalStateShowerProduct(ShowerProgenitorPtr progenitor,
ShowerParticlePtr parent,
const ShowerParticleVector & children) {
assert(children.size()==2);
bool matches[2];
for(unsigned int ix=0;ix<2;++ix) {
matches[ix] = children[ix]->id()==progenitor->id();
}
ShowerParticlePtr newpart;
if(matches[0]&&matches[1]) {
if(parent->showerKinematics()->z()>0.5) newpart=children[0];
else newpart=children[1];
}
else if(matches[0]) newpart=children[0];
else if(matches[1]) newpart=children[1];
_outgoingLines[progenitor]=newpart;
}
void ShowerTree::updateInitialStateShowerProduct(ShowerProgenitorPtr progenitor,
ShowerParticlePtr newParent) {
_incomingLines[progenitor]=newParent;
}
void ShowerTree::insertHard(StepPtr pstep, bool ISR, bool) {
assert(_incomingLines.size()==2);
colourLines().clear();
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
// construct the map of colour lines for hard process
for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) {
if(!cit->first->perturbative()) continue;
mapColour(cit->first->original(),cit->first->copy());
}
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) {
if(!cjt->first->perturbative()) continue;
mapColour(cjt->first->original(),cjt->first->copy());
}
// initial-state radiation
if(ISR) {
for(cit=incomingLines().begin();cit!=incomingLines().end();++cit) {
ShowerParticlePtr init=(*cit).first->progenitor();
assert(init->thePEGBase());
PPtr original = (*cit).first->original();
if(original->parents().empty()) continue;
PPtr hadron= original->parents()[0];
assert(!original->children().empty());
PPtr copy=cit->first->copy();
ParticleVector intermediates=original->children();
for(unsigned int ix=0;ix<intermediates.size();++ix) {
init->abandonChild(intermediates[ix]);
copy->abandonChild(intermediates[ix]);
}
// if not from a matrix element correction
if(cit->first->perturbative()) {
// break mother/daugther relations
init->addChild(original);
hadron->abandonChild(original);
// if particle showers add shower
if(cit->first->hasEmitted()) {
addInitialStateShower(init,hadron,pstep,false);
}
// no showering for this particle
else {
updateColour(init,false);
hadron->addChild(init);
pstep->addIntermediate(init);
init->setLifeLength(Lorentz5Distance());
init->setVertex(LorentzPoint());
}
}
// from matrix element correction
else {
// break mother/daugther relations
hadron->abandonChild(original);
copy->addChild(original);
updateColour(copy,false);
init->addChild(copy);
pstep->addIntermediate(copy);
copy->setLifeLength(Lorentz5Distance());
copy->setVertex(LorentzPoint());
// if particle showers add shower
if(cit->first->hasEmitted()) {
addInitialStateShower(init,hadron,pstep,false);
}
// no showering for this particle
else {
updateColour(init,false);
hadron->addChild(init);
pstep->addIntermediate(init);
init->setLifeLength(Lorentz5Distance());
init->setVertex(LorentzPoint());
}
}
}
}
else {
for(cit=incomingLines().begin();cit!=incomingLines().end();++cit) {
ShowerParticlePtr init=(*cit).first->progenitor();
assert(init->thePEGBase());
PPtr original = (*cit).first->original();
if(original->parents().empty()) continue;
PPtr hadron= original->parents()[0];
assert(!original->children().empty());
PPtr copy=cit->first->copy();
ParticleVector intermediates=original->children();
for(unsigned int ix=0;ix<intermediates.size();++ix) {
init->abandonChild(intermediates[ix]);
copy->abandonChild(intermediates[ix]);
}
// break mother/daugther relations
init->addChild(original);
hadron->abandonChild(original);
// no showering for this particle
updateColour(init,false);
hadron->addChild(init);
pstep->addIntermediate(init);
init->setLifeLength(Lorentz5Distance());
init->setVertex(LorentzPoint());
original->setLifeLength(Lorentz5Distance());
original->setVertex(LorentzPoint());
}
}
// final-state radiation
for(cjt=outgoingLines().begin();cjt!=outgoingLines().end();++cjt) {
ShowerParticlePtr init=(*cjt).first->progenitor();
assert(init->thePEGBase());
// ZERO the distance of original
(*cjt).first->original()->setLifeLength(Lorentz5Distance());
(*cjt).first->original()->setVertex(LorentzPoint());
// if not from a matrix element correction
if(cjt->first->perturbative()) {
// register the shower particle as a
// copy of the one from the hard process
tParticleVector parents=init->parents();
for(unsigned int ix=0;ix<parents.size();++ix)
parents[ix]->abandonChild(init);
(*cjt).first->original()->addChild(init);
pstep->addDecayProduct(init);
}
// from a matrix element correction
else {
if(cjt->first->original()==_incoming.first||
cjt->first->original()==_incoming.second) {
updateColour((*cjt).first->copy(),false);
(*cjt).first->original()->parents()[0]->
addChild((*cjt).first->copy());
pstep->addDecayProduct((*cjt).first->copy());
(*cjt).first->copy()->addChild(init);
pstep->addDecayProduct(init);
}
else {
updateColour((*cjt).first->copy(),false);
(*cjt).first->original()->addChild((*cjt).first->copy());
pstep->addDecayProduct((*cjt).first->copy());
(*cjt).first->copy()->addChild(init);
pstep->addDecayProduct(init);
}
// ZERO the distance of copy ??? \todo change if add space-time
(*cjt).first->copy()->setLifeLength(Lorentz5Distance());
(*cjt).first->copy()->setVertex(LorentzPoint());
}
// copy so travels no distance
init->setLifeLength(Lorentz5Distance());
init->setVertex(init->parents()[0]->decayVertex());
// sort out the colour
updateColour(init,false);
// insert shower products
addFinalStateShower(init,pstep);
}
colourLines().clear();
}
void ShowerTree::addFinalStateShower(PPtr p, StepPtr s) {
// if endpoint assume doesn't travel
if(p->children().empty()) {
if(p->dataPtr()->stable()||ShowerHandler::currentHandler()->decaysInShower(p->id()))
p->setLifeLength(Lorentz5Distance());
else {
- Length ctau = p->dataPtr()->generateLifeTime(p->mass(), p->dataPtr()->width());
- Lorentz5Distance lifeLength(ctau,p->momentum().vect()*(ctau/p->mass()));
+ Energy mass = p->mass()!=ZERO ? p->mass() : p->dataPtr()->mass();
+ Length ctau = p->dataPtr()->generateLifeTime(mass, p->dataPtr()->width());
+ Lorentz5Distance lifeLength(ctau,p->momentum().vect()*(ctau/mass));
p->setLifeLength(lifeLength);
}
return;
}
// set the space-time distance
else {
p->setLifeLength(spaceTimeDistance(p));
}
ParticleVector::const_iterator child;
for(child=p->children().begin(); child != p->children().end(); ++child) {
updateColour(*child,false);
s->addDecayProduct(*child);
(**child).setVertex(p->decayVertex());
addFinalStateShower(*child,s);
}
}
void ShowerTree::addInitialStateShower(PPtr p, PPtr hadron,
StepPtr s, bool addchildren) {
// Each parton here should only have one parent
if(!p->parents().empty()) {
if(p->parents().size()!=1)
throw Exception() << "Particle must only have one parent in ShowerTree"
<< "::addInitialStateShower" << Exception::runerror;
// set the space-time distances
if(addchildren) {
p->setLifeLength(spaceTimeDistance(p));
p->setVertex(p->children()[0]->vertex()-p->lifeLength());
}
else {
p->setLifeLength(spaceTimeDistance(p));
p->setVertex(-p->lifeLength());
}
// recurse
addInitialStateShower(p->parents()[0],hadron,s);
}
else {
hadron->addChild(p);
s->addIntermediate(p);
p->setVertex(p->children()[0]->vertex());
p->setLifeLength(Lorentz5Distance());
}
updateColour(p,false);
// if not adding children return
if(!addchildren) return;
// add children
ParticleVector::const_iterator child;
for(child = p->children().begin(); child != p->children().end(); ++child) {
// if a final-state particle update the colour
ShowerParticlePtr schild =
dynamic_ptr_cast<ShowerParticlePtr>(*child);
(**child).setVertex(p->decayVertex());
if(schild && schild->isFinalState()) updateColour(*child,false);
// if there are grandchildren of p
if(!(*child)->children().empty()) {
// Add child as intermediate
s->addIntermediate(*child);
// If child is shower particle and final-state, add children
if(schild && schild->isFinalState()) addFinalStateShower(schild,s);
}
else
s->addDecayProduct(*child);
}
}
void ShowerTree::update(PerturbativeProcessPtr newProcess) {
// must be one incoming particle
assert(_incomingLines.size()==1);
colourLines().clear();
// copy the particles and isolate the colour
vector<PPtr> original,copy;
for(unsigned int ix=0;ix<newProcess->incoming().size();++ix) {
original.push_back(newProcess->incoming()[ix].first);
copy .push_back(new_ptr(Particle(*original.back())));
}
for(unsigned int ix=0;ix<newProcess->outgoing().size();++ix) {
original.push_back(newProcess->outgoing()[ix].first);
copy .push_back(new_ptr(Particle(*original.back())));
}
// isolate the colour
colourIsolate(original,copy);
// make the new progenitor
ShowerParticlePtr stemp=new_ptr(ShowerParticle(*copy[0],2,false));
fixColour(stemp);
ShowerProgenitorPtr newprog=new_ptr(ShowerProgenitor(original[0],copy[0],stemp));
_incomingLines.clear();
_incomingLines.insert(make_pair(newprog,stemp));
// create the children
assert(copy.size() == original.size());
for (unsigned int ix=newProcess->incoming().size();ix<original.size();++ix) {
ShowerParticlePtr stemp= new_ptr(ShowerParticle(*copy[ix],2,true));
fixColour(stemp);
_outgoingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[ix],copy[ix],
stemp)),
stemp));
_forward.insert(stemp);
}
}
void ShowerTree::insertDecay(StepPtr pstep,bool ISR, bool) {
assert(_incomingLines.size()==1);
colourLines().clear();
// find final particle from previous tree
PPtr final;
if(_parent&&!_parent->_treelinks.empty())
final = _parent->_treelinks[this].second;
else
final=_incomingLines.begin()->first->original();
// construct the map of colour lines
PPtr copy=_incomingLines.begin()->first->copy();
mapColour(final,copy);
// now this is the ONE instance of the particle which should have a life length
// \todo change if space-time picture added
// set the lifelength, need this so that still in right direction after
// any ISR recoils
Length ctau = copy->lifeTime();
Lorentz5Distance lifeLength(ctau,final->momentum().vect()*(ctau/final->mass()));
final->setLifeLength(lifeLength);
// initial-state radiation
if(ISR&&!_incomingLines.begin()->first->progenitor()->children().empty()) {
ShowerParticlePtr init=_incomingLines.begin()->first->progenitor();
updateColour(init,false);
final->addChild(init);
pstep->addDecayProduct(init);
// just a copy doesn't travel
init->setLifeLength(Lorentz5Distance());
init->setVertex(final->decayVertex());
// insert shower products
addFinalStateShower(init,pstep);
// sort out colour
final=_incomingLines.begin()->second;
colourLines().clear();
mapColour(final,copy);
}
// get the decaying particles
// make the copy
tColinePair cline=make_pair(copy->colourLine(),copy->antiColourLine());
updateColour(copy,false);
// sort out sinks and sources if needed
if(cline.first) {
if(cline.first->sourceNeighbours().first) {
copy->colourLine()->setSourceNeighbours(cline.first->sourceNeighbours().first,
cline.first->sourceNeighbours().second);
}
else if (cline.first->sinkNeighbours().first) {
copy->colourLine()->setSinkNeighbours(cline.first->sinkNeighbours().first,
cline.first->sinkNeighbours().second);
}
}
if(cline.second) {
if(cline.second->sourceNeighbours().first) {
copy->antiColourLine()->setSourceNeighbours(cline.second->sourceNeighbours().first,
cline.second->sourceNeighbours().second);
}
else if (cline.second->sinkNeighbours().first) {
copy->antiColourLine()->setSinkNeighbours(cline.second->sinkNeighbours().first,
cline.second->sinkNeighbours().second);
}
}
// copy of the one from the hard process
tParticleVector dpar=copy->parents();
for(unsigned int ix=0;ix<dpar.size();++ix) dpar[ix]->abandonChild(copy);
final->addChild(copy);
pstep->addDecayProduct(copy);
// just a copy does not move
copy->setLifeLength(Lorentz5Distance());
copy->setVertex(final->decayVertex());
// final-state radiation
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
for(cit=outgoingLines().begin();cit!=outgoingLines().end();++cit) {
ShowerParticlePtr init=cit->first->progenitor();
// ZERO the distance
init->setLifeLength(Lorentz5Distance());
if(!init->thePEGBase())
throw Exception() << "Final-state particle must have a ThePEGBase"
<< " in ShowerTree::insertDecay()"
<< Exception::runerror;
// if not from matrix element correction
if(cit->first->perturbative()) {
// add the child
updateColour(cit->first->copy(),false);
PPtr orig=cit->first->original();
orig->setLifeLength(Lorentz5Distance());
orig->setVertex(copy->decayVertex());
copy->addChild(orig);
pstep->addDecayProduct(orig);
orig->addChild(cit->first->copy());
pstep->addDecayProduct(cit->first->copy());
// register the shower particle as a
// copy of the one from the hard process
tParticleVector parents=init->parents();
for(unsigned int ix=0;ix<parents.size();++ix)
{parents[ix]->abandonChild(init);}
(*cit).first->copy()->addChild(init);
pstep->addDecayProduct(init);
updateColour(init,false);
}
// from a matrix element correction
else {
if(copy->children().end()==
find(copy->children().begin(),copy->children().end(),
cit->first->original())) {
updateColour(cit->first->original(),false);
copy->addChild(cit->first->original());
pstep->addDecayProduct(cit->first->original());
}
updateColour(cit->first->copy(),false);
cit->first->original()->addChild(cit->first->copy());
pstep->addDecayProduct(cit->first->copy());
// register the shower particle as a
// copy of the one from the hard process
tParticleVector parents=init->parents();
for(unsigned int ix=0;ix<parents.size();++ix)
{parents[ix]->abandonChild(init);}
(*cit).first->copy()->addChild(init);
pstep->addDecayProduct(init);
updateColour(init,false);
}
// ZERO the distances as just copies
cit->first->copy()->setLifeLength(Lorentz5Distance());
init->setLifeLength(Lorentz5Distance());
cit->first->copy()->setVertex(copy->decayVertex());
init->setVertex(copy->decayVertex());
// insert shower products
addFinalStateShower(init,pstep);
}
colourLines().clear();
}
void ShowerTree::clear() {
// reset the has showered flag
_hasShowered=false;
// clear the colour map
colourLines().clear();
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit;
map<ShowerProgenitorPtr, ShowerParticlePtr>::const_iterator cjt;
// abandon the children of the outgoing particles
for(cit=_outgoingLines.begin();cit!=_outgoingLines.end();++cit) {
ShowerParticlePtr orig=cit->first->progenitor();
orig->set5Momentum(cit->first->copy()->momentum());
ParticleVector children=orig->children();
for(unsigned int ix=0;ix<children.size();++ix) orig->abandonChild(children[ix]);
_outgoingLines[cit->first]=orig;
cit->first->hasEmitted(false);
cit->first->reconstructed(ShowerProgenitor::notReconstructed);
}
// forward products
_forward.clear();
for(cit=_outgoingLines.begin();cit!=_outgoingLines.end();++cit)
_forward.insert(cit->first->progenitor());
// if a decay
if(!_wasHard) {
ShowerParticlePtr orig=_incomingLines.begin()->first->progenitor();
orig->set5Momentum(_incomingLines.begin()->first->copy()->momentum());
ParticleVector children=orig->children();
for(unsigned int ix=0;ix<children.size();++ix) orig->abandonChild(children[ix]);
_incomingLines.begin()->first->reconstructed(ShowerProgenitor::notReconstructed);
}
// if a hard process
else {
for(cjt=_incomingLines.begin();cjt!=_incomingLines.end();++cjt) {
tPPtr parent = cjt->first->original()->parents().empty() ?
tPPtr() : cjt->first->original()->parents()[0];
ShowerParticlePtr temp=
new_ptr(ShowerParticle(*cjt->first->copy(),
cjt->first->progenitor()->perturbative(),
cjt->first->progenitor()->isFinalState()));
fixColour(temp);
temp->x(cjt->first->progenitor()->x());
cjt->first->hasEmitted(false);
if(!(cjt->first->progenitor()==cjt->second)&&cjt->second&&parent)
parent->abandonChild(cjt->second);
cjt->first->progenitor(temp);
_incomingLines[cjt->first]=temp;
cjt->first->reconstructed(ShowerProgenitor::notReconstructed);
}
}
// reset the particles at the end of the shower
_backward.clear();
// if hard process backward products
if(_wasHard)
for(cjt=_incomingLines.begin();cjt!=_incomingLines.end();++cjt)
_backward.insert(cjt->first->progenitor());
clearTransforms();
}
void ShowerTree::resetShowerProducts() {
map<ShowerProgenitorPtr, ShowerParticlePtr>::const_iterator cit;
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
_backward.clear();
_forward.clear();
for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit)
_backward.insert(cit->second);
for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt)
_forward.insert(cjt->second);
}
void ShowerTree::updateAfterShower(ShowerDecayMap & decay) {
// update the links
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator mit;
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::iterator tit;
for(tit=_treelinks.begin();tit!=_treelinks.end();++tit) {
if(tit->second.first) {
mit=_outgoingLines.find(tit->second.first);
if(mit!=_outgoingLines.end()) tit->second.second=mit->second;
}
}
// get the particles coming from those in the hard process
set<tShowerParticlePtr> hard;
for(mit=_outgoingLines.begin();mit!=_outgoingLines.end();++mit)
hard.insert(mit->second);
// find the shower particles which should be decayed in the
// shower but didn't come from the hard process
set<tShowerParticlePtr>::const_iterator cit;
for(cit=_forward.begin();cit!=_forward.end();++cit) {
if((ShowerHandler::currentHandler()->decaysInShower((**cit).id())&&
!(**cit).dataPtr()->stable()) &&
hard.find(*cit)==hard.end()) {
PerturbativeProcessPtr newProcess(new_ptr(PerturbativeProcess()));
newProcess->incoming().push_back(make_pair(*cit,PerturbativeProcessPtr()));
ShowerTreePtr newtree=new_ptr(ShowerTree(newProcess));
newtree->setParents();
newtree->_parent=this;
Energy width=(**cit).dataPtr()->generateWidth((**cit).mass());
decay.insert(make_pair(width,newtree));
_treelinks.insert(make_pair(newtree,
make_pair(tShowerProgenitorPtr(),*cit)));
}
}
}
void ShowerTree::addFinalStateBranching(ShowerParticlePtr parent,
const ShowerParticleVector & children) {
assert(children.size()==2);
_forward.erase(parent);
for(unsigned int ix=0; ix<children.size(); ++ix) {
_forward.insert(children[ix]);
}
}
void ShowerTree::addInitialStateBranching(ShowerParticlePtr oldParent,
ShowerParticlePtr newParent,
ShowerParticlePtr otherChild) {
_backward.erase(oldParent);
_backward.insert(newParent);
_forward.insert(otherChild);
}
void ShowerTree::setParents() {
// set the parent tree of the children
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit;
for(tit=_treelinks.begin();tit!=_treelinks.end();++tit)
tit->first->_parent=this;
}
vector<ShowerProgenitorPtr> ShowerTree::extractProgenitors() {
// extract the particles from the ShowerTree
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator mit;
vector<ShowerProgenitorPtr> ShowerHardJets;
for(mit=incomingLines().begin();mit!=incomingLines().end();++mit)
ShowerHardJets.push_back((*mit).first);
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator mjt;
for(mjt=outgoingLines().begin();mjt!=outgoingLines().end();++mjt)
ShowerHardJets.push_back((*mjt).first);
return ShowerHardJets;
}
void ShowerTree::transform(const LorentzRotation & boost, bool applyNow) {
if(applyNow) {
// now boost all the particles
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
// incoming
for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) {
cit->first->progenitor()->deepTransform(boost);
cit->first->copy()->deepTransform(boost);
}
// outgoing
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) {
cjt->first->progenitor()->deepTransform(boost);
cjt->first->copy()->deepTransform(boost);
}
}
else {
_transforms.transform(boost);
}
// child trees
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit=_treelinks.begin();tit!=_treelinks.end();++tit)
tit->first->transform(boost,applyNow);
}
void ShowerTree::applyTransforms() {
// now boost all the particles
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
// incoming
for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) {
cit->first->progenitor()->deepTransform(_transforms);
cit->first->copy()->deepTransform(_transforms);
}
// outgoing
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) {
cjt->first->progenitor()->deepTransform(_transforms);
cjt->first->copy()->deepTransform(_transforms);
}
// child trees
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit=_treelinks.begin();tit!=_treelinks.end();++tit)
tit->first->applyTransforms();
_transforms = LorentzRotation();
}
void ShowerTree::clearTransforms() {
_transforms = LorentzRotation();
// // child trees
// for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
// tit=_treelinks.begin();tit!=_treelinks.end();++tit)
// tit->first->clearTransforms();
}
void ShowerTree::fixColour(tShowerParticlePtr part) {
if(!part->colourInfo()->colourLines().empty()) {
if(part->colourInfo()->colourLines().size()==1) {
ColinePtr line=part->colourLine();
if(line) {
line->removeColoured(part);
line->addColoured(part);
}
}
else {
Ptr<MultiColour>::pointer colour =
dynamic_ptr_cast<Ptr<MultiColour>::pointer>(part->colourInfo());
vector<tcColinePtr> lines = colour->colourLines();
for(unsigned int ix=0;ix<lines.size();++ix) {
ColinePtr line = const_ptr_cast<ColinePtr>(lines[ix]);
if(line) {
line->removeColoured(part);
line->addColoured(part);
}
}
}
}
if(!part->colourInfo()->antiColourLines().empty()) {
if(part->colourInfo()->antiColourLines().size()==1) {
ColinePtr line=part->antiColourLine();
if(line) {
line->removeAntiColoured(part);
line->addAntiColoured(part);
}
}
else {
Ptr<MultiColour>::pointer colour =
dynamic_ptr_cast<Ptr<MultiColour>::pointer>(part->colourInfo());
vector<tcColinePtr> lines = colour->antiColourLines();
for(unsigned int ix=0;ix<lines.size();++ix) {
ColinePtr line = const_ptr_cast<ColinePtr>(lines[ix]);
if(line) {
line->removeAntiColoured(part);
line->addAntiColoured(part);
}
}
}
}
}
vector<ShowerParticlePtr> ShowerTree::extractProgenitorParticles() {
vector<ShowerParticlePtr> particles;
// incoming particles
for(map<ShowerProgenitorPtr, ShowerParticlePtr>::const_iterator
cit=incomingLines().begin(); cit!=incomingLines().end();++cit)
particles.push_back(cit->first->progenitor());
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt=outgoingLines().begin(); cjt!=outgoingLines().end();++cjt)
particles.push_back(cjt->first->progenitor());
return particles;
}
Lorentz5Distance ShowerTree::spaceTimeDistance(tPPtr particle) {
if(!_spaceTime) return Lorentz5Distance();
Energy2 q2 = particle->mass() > ZERO ? sqr(particle->mass()) : -sqr(particle->mass());
const tcPDPtr data = particle->dataPtr();
// calculate width imposing min value
Energy conMass = max(data->constituentMass(),200*MeV);
Energy width = max(data->generateWidth(particle->mass()),_vmin2/conMass);
// offshellness
Energy2 offShell = q2-sqr(data->constituentMass());
if(abs(offShell)<1e-10*GeV2) offShell = ZERO;
InvEnergy2 fact = UseRandom::rndExp(1./sqrt((sqr(offShell)+sqr(q2*width/conMass))));
Lorentz5Distance output = (hbarc*fact)*particle->momentum();
return output;
}
void ShowerTree::constructTrees(ShowerTreePtr & hardTree,
ShowerDecayMap & decayTrees,
PerturbativeProcessPtr hard,
DecayProcessMap decay) {
map<PerturbativeProcessPtr,ShowerTreePtr> treeMap;
// convert the hard process
if(hardTree) {
if(hardTree->isDecay()) hardTree->update(hard);
}
else {
hardTree = new_ptr(ShowerTree(hard));
}
treeMap.insert(make_pair(hard,hardTree));
for(DecayProcessMap::const_iterator it=decay.begin();it!=decay.end();++it) {
ShowerTreePtr newTree = new_ptr(ShowerTree(it->second));
treeMap.insert(make_pair(it->second,newTree));
decayTrees.insert(make_pair(it->first,newTree));
}
// set up the links between the trees
for(map<PerturbativeProcessPtr,ShowerTreePtr>::const_iterator it=treeMap.begin();
it!=treeMap.end();++it) {
// links to daughter trees
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator mit;
for(mit=it->second->_outgoingLines.begin();
mit!=it->second->_outgoingLines.end();++mit) {
unsigned int iloc=0;
for(;iloc<it->first->outgoing().size();++iloc) {
if(it->first->outgoing()[iloc].first==mit->first->original())
break;
}
if(it->first->outgoing()[iloc].second)
it->second->_treelinks.insert(make_pair(treeMap[it->first->outgoing()[iloc].second],
make_pair(mit->first,mit->first->progenitor())));
}
// links to parent trees
if(it->first->incoming()[0].second) {
it->second->_parent = treeMap[it->first->incoming()[0].second];
}
}
}
namespace {
Lorentz5Momentum sumMomenta(tPPtr particle) {
if(particle->children().empty())
return particle->momentum();
Lorentz5Momentum output;
for(unsigned int ix=0;ix<particle->children().size();++ix) {
output += sumMomenta(particle->children()[ix]);
}
return output;
}
}
void ShowerTree::checkMomenta() {
vector<Lorentz5Momentum> pin;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator it=_incomingLines.begin();
it!=_incomingLines.end();++it) {
if(isDecay()) {
tPPtr parent = it->first->progenitor();
pin.push_back(parent->momentum());
while(!parent->children().empty()) {
pin.back() -= sumMomenta(parent->children()[1]);
parent = parent->children()[0];
}
}
else {
tPPtr parent = it->second;
pin.push_back(parent->momentum());
while(!parent->children().empty()&&parent->children().size()==2) {
pin.back() -= sumMomenta(parent->children()[1]);
parent = parent->children()[0];
if(parent==it->first->progenitor()) break;
}
}
}
vector<Lorentz5Momentum> pout;
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator it= _outgoingLines.begin();
it!=_outgoingLines.end();++it) {
pout.push_back(sumMomenta(it->first->progenitor()));
}
Lorentz5Momentum psum;
for(unsigned int ix=0;ix< pin.size();++ix) {
CurrentGenerator::log() << "pin " << ix << pin[ix]/GeV << "\n";
psum +=pin[ix];
}
CurrentGenerator::log() << "In total " << psum/GeV << " " << psum.m()/GeV << "\n";
Lorentz5Momentum psum2;
for(unsigned int ix=0;ix< pout.size();++ix) {
CurrentGenerator::log() << "pout " << ix << pout[ix]/GeV << "\n";
psum2 +=pout[ix];
}
CurrentGenerator::log() << "Out total " << psum2/GeV << " " << psum2.m()/GeV << "\n";
CurrentGenerator::log() << "Total " << (psum-psum2)/GeV << "\n";
}
RealEmissionProcessPtr ShowerTree::perturbativeProcess() {
RealEmissionProcessPtr output(new_ptr(RealEmissionProcess()));
// add the incoming particles
unsigned int ix=0;
pair<double,double> x;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator it=_incomingLines.begin();
it!=_incomingLines.end();++it) {
output->bornIncoming().push_back(it->first->progenitor());
if(!it->first->original()->parents().empty())
output->hadrons().push_back(it->first->original()->parents()[0]);
else
output->hadrons().push_back(it->first->progenitor());
if(ix==0) x.first = it->second->x();
else x.second = it->second->x();
++ix;
}
output->x(x);
// add the outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator it= _outgoingLines.begin();
it!=_outgoingLines.end();++it) {
output->bornOutgoing().push_back(it->first->progenitor());
}
return output;
}
void ShowerTree::setVetoes(const map<ShowerInteraction,Energy> & pTs,
unsigned int type) {
if(type==1||type==3) {
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator it=_incomingLines.begin();
it!=_incomingLines.end();++it) {
for(map<ShowerInteraction,Energy>::const_iterator jt=pTs.begin();jt!=pTs.end();++jt)
it->first->maximumpT(jt->second,jt->first);
}
}
if(type==2||type==3) {
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator it= _outgoingLines.begin();
it!=_outgoingLines.end();++it) {
for(map<ShowerInteraction,Energy>::const_iterator jt=pTs.begin();jt!=pTs.end();++jt)
it->first->maximumpT(jt->second,jt->first);
}
}
}
diff --git a/Shower/QTilde/Couplings/ShowerAlphaQCD.cc b/Shower/QTilde/Couplings/ShowerAlphaQCD.cc
--- a/Shower/QTilde/Couplings/ShowerAlphaQCD.cc
+++ b/Shower/QTilde/Couplings/ShowerAlphaQCD.cc
@@ -1,453 +1,453 @@
// -*- C++ -*-
//
// ShowerAlphaQCD.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ShowerAlphaQCD class.
//
#include "ShowerAlphaQCD.h"
#include "ThePEG/PDT/ParticleData.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ParVector.h"
#include "ThePEG/Interface/Command.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Utilities/Throw.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Config/Constants.h"
using namespace Herwig;
DescribeClass<ShowerAlphaQCD,ShowerAlpha>
describeShowerAlphaQCD("Herwig::ShowerAlphaQCD","HwShower.so");
IBPtr ShowerAlphaQCD::clone() const {
return new_ptr(*this);
}
IBPtr ShowerAlphaQCD::fullclone() const {
return new_ptr(*this);
}
void ShowerAlphaQCD::persistentOutput(PersistentOStream & os) const {
os << _asType << _asMaxNP << ounit(_qmin,GeV) << _nloop << _lambdaopt << _thresopt
<< ounit(_lambdain,GeV) << _alphain << _inopt
<< _tolerance << _maxtry << _alphamin
<< ounit(_thresholds,GeV) << ounit(_lambda,GeV)
<< _val0 << ounit(_optInputScale,GeV) << ounit(_quarkMasses,GeV);
}
void ShowerAlphaQCD::persistentInput(PersistentIStream & is, int) {
is >> _asType >> _asMaxNP >> iunit(_qmin,GeV) >> _nloop >> _lambdaopt >> _thresopt
>> iunit(_lambdain,GeV) >> _alphain >> _inopt
>> _tolerance >> _maxtry >> _alphamin
>> iunit(_thresholds,GeV) >> iunit(_lambda,GeV)
>> _val0 >> iunit(_optInputScale,GeV) >> iunit(_quarkMasses,GeV);
}
void ShowerAlphaQCD::Init() {
static ClassDocumentation<ShowerAlphaQCD> documentation
("This (concrete) class describes the QCD alpha running.");
static Switch<ShowerAlphaQCD, int> intAsType
("NPAlphaS",
"Behaviour of AlphaS in the NP region",
&ShowerAlphaQCD::_asType, 1, false, false);
static SwitchOption intAsTypeZero
(intAsType, "Zero","zero below Q_min", 1);
static SwitchOption intAsTypeConst
(intAsType, "Const","const as(qmin) below Q_min", 2);
static SwitchOption intAsTypeLin
(intAsType, "Linear","growing linearly below Q_min", 3);
static SwitchOption intAsTypeQuad
(intAsType, "Quadratic","growing quadratically below Q_min", 4);
static SwitchOption intAsTypeExx1
(intAsType, "Exx1", "quadratic from AlphaMaxNP down to as(Q_min)", 5);
static SwitchOption intAsTypeExx2
(intAsType, "Exx2", "const = AlphaMaxNP below Q_min", 6);
// default such that as(qmin) = 1 in the current parametrization.
// min = Lambda3
static Parameter<ShowerAlphaQCD,Energy> intQmin
("Qmin", "Q < Qmin is treated with NP parametrization as of (unit [GeV]),"
" if negative it is solved for at initialisation such that alpha_S(Qmin)=AlphaMaxNP",
&ShowerAlphaQCD::_qmin, GeV, 0.630882*GeV, 0.330445*GeV,
100.0*GeV,false,false,false);
static Parameter<ShowerAlphaQCD,double> interfaceAlphaMaxNP
("AlphaMaxNP",
"Max value of alpha in NP region, only relevant if NPAlphaS = 5,6",
&ShowerAlphaQCD::_asMaxNP, 1.0, 0., 100.0,
false, false, Interface::limited);
static Parameter<ShowerAlphaQCD,unsigned int> interfaceNumberOfLoops
("NumberOfLoops",
"The number of loops to use in the alpha_S calculation",
&ShowerAlphaQCD::_nloop, 3, 1, 3,
false, false, Interface::limited);
static Switch<ShowerAlphaQCD,bool> interfaceLambdaOption
("LambdaOption",
"Option for the calculation of the Lambda used in the simulation from the input"
" Lambda_MSbar",
&ShowerAlphaQCD::_lambdaopt, false, false, false);
static SwitchOption interfaceLambdaOptionfalse
(interfaceLambdaOption,
"Same",
"Use the same value",
false);
static SwitchOption interfaceLambdaOptionConvert
(interfaceLambdaOption,
"Convert",
"Use the conversion to the Herwig scheme from NPB349, 635",
true);
static Parameter<ShowerAlphaQCD,Energy> interfaceLambdaQCD
("LambdaQCD",
"Input value of Lambda_MSBar",
&ShowerAlphaQCD::_lambdain, MeV, 0.208364*GeV, 100.0*MeV, 500.0*MeV,
false, false, Interface::limited);
static Parameter<ShowerAlphaQCD,double> interfaceAlphaMZ
("AlphaMZ",
"The input value of the strong coupling at the Z mass ",
&ShowerAlphaQCD::_alphain, 0.118, 0.1, 0.2,
false, false, Interface::limited);
static Switch<ShowerAlphaQCD,bool> interfaceInputOption
("InputOption",
"Option for inputing the initial value of the coupling",
&ShowerAlphaQCD::_inopt, true, false, false);
static SwitchOption interfaceInputOptionAlphaMZ
(interfaceInputOption,
"AlphaMZ",
"Use the value of alpha at MZ to calculate the coupling",
true);
static SwitchOption interfaceInputOptionLambdaQCD
(interfaceInputOption,
"LambdaQCD",
"Use the input value of Lambda to calculate the coupling",
false);
static Parameter<ShowerAlphaQCD,double> interfaceTolerance
("Tolerance",
"The tolerance for discontinuities in alphaS at thresholds.",
&ShowerAlphaQCD::_tolerance, 1e-10, 1e-20, 1e-4,
false, false, Interface::limited);
static Parameter<ShowerAlphaQCD,unsigned int> interfaceMaximumIterations
("MaximumIterations",
"The maximum number of iterations for the Newton-Raphson method to converge.",
&ShowerAlphaQCD::_maxtry, 100, 10, 1000,
false, false, Interface::limited);
static Switch<ShowerAlphaQCD,bool> interfaceThresholdOption
("ThresholdOption",
"Whether to use the consistuent or normal masses for the thresholds",
&ShowerAlphaQCD::_thresopt, true, false, false);
static SwitchOption interfaceThresholdOptionCurrent
(interfaceThresholdOption,
"Current",
"Use the current masses",
true);
static SwitchOption interfaceThresholdOptionConstituent
(interfaceThresholdOption,
"Constituent",
"Use the constitent masses.",
false);
static Command<ShowerAlphaQCD> interfaceValue
("Value",
"",
&ShowerAlphaQCD::value, false);
static Command<ShowerAlphaQCD> interfacecheck
("check",
"check",
&ShowerAlphaQCD::check, false);
static Parameter<ShowerAlphaQCD,Energy> interfaceInputScale
("InputScale",
"An optional input scale. MZ will be used if not set.",
&ShowerAlphaQCD::_optInputScale, GeV, ZERO, ZERO, 0*GeV,
false, false, Interface::lowerlim);
static ParVector<ShowerAlphaQCD,Energy> interfaceQuarkMasses
("QuarkMasses",
"The quark masses to be used instead of the masses set in the particle data.",
&ShowerAlphaQCD::_quarkMasses, GeV, -1, 0.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
}
void ShowerAlphaQCD::doinit() {
ShowerAlpha::doinit();
// calculate the value of 5-flavour lambda
// evaluate the initial
// value of Lambda from alphas if needed using Newton-Raphson
if(_inopt) {
_lambda[2]=computeLambda(_optInputScale == ZERO ?
getParticleData(ParticleID::Z0)->mass() :
_optInputScale,
_alphain,5);
}
// otherwise it was an input parameter
else{_lambda[2]=_lambdain;}
// convert lambda to the Monte Carlo scheme if needed
using Constants::pi;
if(_lambdaopt) _lambda[2] *=exp(0.5*(67.-3.*sqr(pi)-50./3.)/23.)/sqrt(2.);
// compute the threshold matching
// top threshold
for(int ix=1;ix<4;++ix) {
if ( _quarkMasses.empty() ) {
if(_thresopt)
_thresholds[ix]=getParticleData(ix+3)->mass();
else
_thresholds[ix]=getParticleData(ix+3)->constituentMass();
} else {
// starting at zero rather than one, cf the other alphas's
_thresholds[ix] = _quarkMasses[ix+2];
}
}
// compute 6 flavour lambda by matching at top mass using Newton Raphson
_lambda[3]=computeLambda(_thresholds[3],alphaS(_thresholds[3],_lambda[2],5),6);
// bottom threshold
// compute 4 flavour lambda by matching at bottom mass using Newton Raphson
_lambda[1]=computeLambda(_thresholds[2],alphaS(_thresholds[2],_lambda[2],5),4);
// charm threshold
// compute 3 flavour lambda by matching at charm mass using Newton Raphson
_lambda[0]=computeLambda(_thresholds[1],alphaS(_thresholds[1],_lambda[1],4),3);
// if qmin less than zero solve for alphaS(_qmin) = 1.
if(_qmin<ZERO ) {
Energy low = _lambda[0]+MeV;
if(value(sqr(low))<_asMaxNP)
Throw<InitException>() << "The value of Qmin is less than Lambda_3 in"
<< " ShowerAlphaQCD::doinit " << Exception::abortnow;
Energy high = 10*GeV;
while (value(sqr(high))>_asMaxNP) high *=2.;
double as;
do {
_qmin = 0.5*(low+high);
as = value(sqr(_qmin));
if(_asMaxNP>as) high = _qmin;
else if(_asMaxNP<as) low = _qmin;
}
while ( abs(as-_asMaxNP) > _tolerance );
}
// final threshold is qmin
_thresholds[0]=_qmin;
// value of alphaS at threshold
pair<short,Energy> nflam = getLamNfTwoLoop(_qmin);
_val0 = alphaS(_qmin, nflam.second, nflam.first);
// compute the maximum value of as
if ( _asType < 5 )
_alphamin = _val0;
else
_alphamin = max(_asMaxNP, _val0);
// check consistency lambda_3 < qmin
if(_lambda[0]>_qmin)
Throw<InitException>() << "The value of Qmin is less than Lambda_3 in"
<< " ShowerAlphaQCD::doinit " << Exception::abortnow;
}
string ShowerAlphaQCD::check(string args) {
doinit();
istringstream argin(args);
double Q_low, Q_high;
long n_steps;
argin >> Q_low >> Q_high >> n_steps;
string fname;
argin >> fname;
- generator()->log() << "checking alpha_s in range [" << Q_low << "," << Q_high << "] GeV in "
- << n_steps << " steps.\nResults are written to " << fname << "\n";
+ Repository::clog() << "checking alpha_s in range [" << Q_low << "," << Q_high << "] GeV in "
+ << n_steps << " steps.\nResults are written to " << fname << "\n";
double step_width = (Q_high-Q_low)/n_steps;
ofstream out (fname.c_str());
for (long k = 0; k <= n_steps; ++k) {
Energy Q = Q_low*GeV + k*step_width*GeV;
out << (Q/GeV) << " " << value(Q*Q) << "\n";
}
return "alpha_s check finished";
}
double ShowerAlphaQCD::value(const Energy2 scale) const {
Energy q = scaleFactor()*sqrt(scale);
double val(0.);
// normal case
if (q >= _qmin) {
pair<short,Energy> nflam = getLamNfTwoLoop(q);
val = alphaS(q, nflam.second, nflam.first);
}
// special handling if the scale is less than Qmin
else {
switch (_asType) {
case 1:
// flat, zero; the default type with no NP effects.
val = 0.;
break;
case 2:
// flat, non-zero alpha_s = alpha_s(q2min).
val = _val0;
break;
case 3:
// linear in q
val = _val0*q/_qmin;
break;
case 4:
// quadratic in q
val = _val0*sqr(q/_qmin);
break;
case 5:
// quadratic in q, starting off at asMaxNP, ending on as(qmin)
val = (_val0 - _asMaxNP)*sqr(q/_qmin) + _asMaxNP;
break;
case 6:
// just asMaxNP and constant
val = _asMaxNP;
break;
}
}
return val;
}
double ShowerAlphaQCD::overestimateValue() const {
return _alphamin;
}
double ShowerAlphaQCD::ratio(const Energy2 scale, double factor) const {
Energy q = scaleFactor()*factor*sqrt(scale);
double val(0.);
// normal case
if (q >= _qmin) {
pair<short,Energy> nflam = getLamNfTwoLoop(q);
val = alphaS(q, nflam.second, nflam.first);
}
// special handling if the scale is less than Qmin
else {
switch (_asType) {
case 1:
// flat, zero; the default type with no NP effects.
val = 0.;
break;
case 2:
// flat, non-zero alpha_s = alpha_s(q2min).
val = _val0;
break;
case 3:
// linear in q
val = _val0*q/_qmin;
break;
case 4:
// quadratic in q
val = _val0*sqr(q/_qmin);
break;
case 5:
// quadratic in q, starting off at asMaxNP, ending on as(qmin)
val = (_val0 - _asMaxNP)*sqr(q/_qmin) + _asMaxNP;
break;
case 6:
// just asMaxNP and constant
val = _asMaxNP;
break;
}
}
// denominator
return val/_alphamin;
}
string ShowerAlphaQCD::value (string scale) {
istringstream readscale(scale);
double inScale; readscale >> inScale;
Energy theScale = inScale * GeV;
initialize();
ostringstream showvalue ("");
showvalue << "alpha_s (" << theScale/GeV << " GeV) = "
<< value (sqr(theScale));
return showvalue.str();
}
pair<short, Energy> ShowerAlphaQCD::getLamNfTwoLoop(Energy q) const {
short nf = 6;
// get lambda and nf according to the thresholds
if (q < _thresholds[1]) nf = 3;
else if (q < _thresholds[2]) nf = 4;
else if (q < _thresholds[3]) nf = 5;
return pair<short,Energy>(nf, _lambda[nf-3]);
}
Energy ShowerAlphaQCD::computeLambda(Energy match,
double alpha,
unsigned int nflav) const {
Energy lamtest=200.0*MeV;
double xtest;
unsigned int ntry=0;
do {
++ntry;
xtest = log(sqr(match/lamtest));
xtest += (alpha-alphaS(match,lamtest,nflav))/derivativealphaS(match,lamtest,nflav);
Energy newLambda = match/exp(0.5*xtest);
lamtest = newLambda<match ? newLambda : 0.5*(lamtest+match);
}
while(abs(alpha-alphaS(match,lamtest,nflav)) > _tolerance && ntry < _maxtry);
return lamtest;
}
double ShowerAlphaQCD::derivativealphaS(Energy q, Energy lam, int nf) const {
using Constants::pi;
double lx = log(sqr(q/lam));
double b0 = 11. - 2./3.*nf;
double b1 = 51. - 19./3.*nf;
double b2 = 2857. - 5033./9.*nf + 325./27.*sqr(nf);
if(_nloop==1)
return -4.*pi/(b0*sqr(lx));
else if(_nloop==2)
return -4.*pi/(b0*sqr(lx))*(1.+2.*b1/sqr(b0)/lx*(1.-2.*log(lx)));
else
return -4.*pi/(b0*sqr(lx))*
(1. + 2.*b1/sqr(b0)/lx*(1.-2.*log(lx))
+ 4.*sqr(b1)/(sqr(sqr(b0))*sqr(lx))*(1. - 2.*log(lx)
+ 3.*(sqr(log(lx) - 0.5)+b2*b0/(8.*sqr(b1))-1.25)));
}
double ShowerAlphaQCD::alphaS(Energy q, Energy lam, int nf) const {
using Constants::pi;
double lx(log(sqr(q/lam)));
double b0 = 11. - 2./3.*nf;
double b1 = 51. - 19./3.*nf;
double b2 = 2857. - 5033./9.*nf + 325./27.*sqr(nf);
// one loop
if(_nloop==1)
{return 4.*pi/(b0*lx);}
// two loop
else if(_nloop==2) {
return 4.*pi/(b0*lx)*(1.-2.*b1/sqr(b0)*log(lx)/lx);
}
// three loop
else
{return 4.*pi/(b0*lx)*(1.-2.*b1/sqr(b0)*log(lx)/lx +
4.*sqr(b1)/(sqr(sqr(b0))*sqr(lx))*
(sqr(log(lx) - 0.5) + b2*b0/(8.*sqr(b1)) - 5./4.));}
}
diff --git a/Shower/QTilde/Default/QTildeReconstructor.cc b/Shower/QTilde/Default/QTildeReconstructor.cc
--- a/Shower/QTilde/Default/QTildeReconstructor.cc
+++ b/Shower/QTilde/Default/QTildeReconstructor.cc
@@ -1,2942 +1,2942 @@
// -*- C++ -*-
//
// QTildeReconstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the QTildeReconstructor class.
//
#include "QTildeReconstructor.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/EventRecord/Event.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/RefVector.h"
#include "Herwig/Shower/QTilde/Base/PartnerFinder.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/EventRecord/ColourLine.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Shower/QTilde/QTildeShowerHandler.h"
#include <cassert>
using namespace Herwig;
DescribeClass<QTildeReconstructor,KinematicsReconstructor>
describeQTildeReconstructor("Herwig::QTildeReconstructor", "HwShower.so");
namespace {
/**
* Struct to order the jets in off-shellness
*/
struct JetOrdering {
bool operator() (const JetKinStruct & j1, const JetKinStruct & j2) {
Energy diff1 = j1.q.m()-j1.p.m();
Energy diff2 = j2.q.m()-j2.p.m();
if(diff1!=diff2) {
return diff1>diff2;
}
else if( j1.q.e() != j2.q.e() )
return j1.q.e()>j2.q.e();
else
return j1.parent->uniqueId>j2.parent->uniqueId;
}
};
}
void QTildeReconstructor::persistentOutput(PersistentOStream & os) const {
os << _reconopt << _initialBoost << ounit(_minQ,GeV) << _noRescale
<< _noRescaleVector << _finalStateReconOption
<< _initialStateReconOption;
}
void QTildeReconstructor::persistentInput(PersistentIStream & is, int) {
is >> _reconopt >> _initialBoost >> iunit(_minQ,GeV) >> _noRescale
>> _noRescaleVector >> _finalStateReconOption
>> _initialStateReconOption;
}
void QTildeReconstructor::Init() {
static ClassDocumentation<QTildeReconstructor> documentation
( "This class is responsible for the kinematics reconstruction of the showering,",
" including the kinematics reshuffling necessary to compensate for the recoil"
"of the emissions." );
static Switch<QTildeReconstructor,unsigned int> interfaceReconstructionOption
("ReconstructionOption",
"Option for the kinematics reconstruction",
&QTildeReconstructor::_reconopt, 0, false, false);
static SwitchOption interfaceReconstructionOptionGeneral
(interfaceReconstructionOption,
"General",
"Use the general solution which ignores the colour structure for all processes",
0);
static SwitchOption interfaceReconstructionOptionColour
(interfaceReconstructionOption,
"Colour",
"Use the colour structure of the process to determine the reconstruction procedure.",
1);
static SwitchOption interfaceReconstructionOptionColour2
(interfaceReconstructionOption,
"Colour2",
"Make the most use possible of the colour structure of the process to determine the reconstruction procedure. "
"Start with FF, then IF then II colour connections",
2);
static SwitchOption interfaceReconstructionOptionColour3
(interfaceReconstructionOption,
"Colour3",
"Make the most use possible of the colour structure of the process to determine the reconstruction procedure. "
"Do the colour connections in order of the pT's emitted in the shower starting with the hardest."
" The colour partner is fully reconstructed at the same time.",
3);
static SwitchOption interfaceReconstructionOptionColour4
(interfaceReconstructionOption,
"Colour4",
"Make the most use possible of the colour structure of the process to determine the reconstruction procedure. "
"Do the colour connections in order of the pT's emitted in the shower starting with the hardest, while leaving"
" the colour partner on mass-shell",
4);
static Parameter<QTildeReconstructor,Energy> interfaceMinimumQ2
("MinimumQ2",
"The minimum Q2 for the reconstruction of initial-final systems",
&QTildeReconstructor::_minQ, GeV, 0.001*GeV, 1e-6*GeV, 10.0*GeV,
false, false, Interface::limited);
static RefVector<QTildeReconstructor,ParticleData> interfaceNoRescale
("NoRescale",
"Particles which shouldn't be rescaled to be on shell by the shower",
&QTildeReconstructor::_noRescaleVector, -1, false, false, true, false, false);
static Switch<QTildeReconstructor,unsigned int> interfaceInitialInitialBoostOption
("InitialInitialBoostOption",
"Option for how the boost from the system before ISR to that after ISR is applied.",
&QTildeReconstructor::_initialBoost, 0, false, false);
static SwitchOption interfaceInitialInitialBoostOptionOneBoost
(interfaceInitialInitialBoostOption,
"OneBoost",
"Apply one boost from old CMS to new CMS",
0);
static SwitchOption interfaceInitialInitialBoostOptionLongTransBoost
(interfaceInitialInitialBoostOption,
"LongTransBoost",
"First apply a longitudinal and then a transverse boost",
1);
static Switch<QTildeReconstructor,unsigned int> interfaceFinalStateReconOption
("FinalStateReconOption",
"Option for how to reconstruct the momenta of the final-state system",
&QTildeReconstructor::_finalStateReconOption, 0, false, false);
static SwitchOption interfaceFinalStateReconOptionDefault
(interfaceFinalStateReconOption,
"Default",
"All the momenta are rescaled in the rest frame",
0);
static SwitchOption interfaceFinalStateReconOptionMostOffShell
(interfaceFinalStateReconOption,
"MostOffShell",
"All particles put on the new-mass shell and then the most off-shell and"
" recoiling system are rescaled to ensure 4-momentum is conserved.",
1);
static SwitchOption interfaceFinalStateReconOptionRecursive
(interfaceFinalStateReconOption,
"Recursive",
"Recursively put on shell by putting the most off-shell particle which"
" hasn't been rescaled on-shell by rescaling the particles and the recoiling system. ",
2);
static SwitchOption interfaceFinalStateReconOptionRestMostOffShell
(interfaceFinalStateReconOption,
"RestMostOffShell",
"The most off-shell is put on shell by rescaling it and the recoiling system,"
" the recoiling system is then put on-shell in its rest frame.",
3);
static SwitchOption interfaceFinalStateReconOptionRestRecursive
(interfaceFinalStateReconOption,
"RestRecursive",
"As 3 but recursive treated the currently most-off shell,"
" only makes a difference if more than 3 partons.",
4);
static Switch<QTildeReconstructor,unsigned int> interfaceInitialStateReconOption
("InitialStateReconOption",
"Option for the reconstruction of initial state radiation",
&QTildeReconstructor::_initialStateReconOption, 0, false, false);
static SwitchOption interfaceInitialStateReconOptionRapidity
(interfaceInitialStateReconOption,
"Rapidity",
"Preserve shat and rapidity",
0);
static SwitchOption interfaceInitialStateReconOptionLongitudinal
(interfaceInitialStateReconOption,
"Longitudinal",
"Preserve longitudinal momentum",
1);
static SwitchOption interfaceInitialStateReconOptionSofterFraction
(interfaceInitialStateReconOption,
"SofterFraction",
"Preserve the momentum fraction of the parton which has emitted softer.",
2);
}
void QTildeReconstructor::doinit() {
KinematicsReconstructor::doinit();
_noRescale = set<cPDPtr>(_noRescaleVector.begin(),_noRescaleVector.end());
}
bool QTildeReconstructor::
reconstructTimeLikeJet(const tShowerParticlePtr particleJetParent) const {
assert(particleJetParent);
bool emitted=true;
// if this is not a fixed point in the reconstruction
if( !particleJetParent->children().empty() ) {
// if not a reconstruction fixpoint, dig deeper for all children:
for ( ParticleVector::const_iterator cit =
particleJetParent->children().begin();
cit != particleJetParent->children().end(); ++cit )
reconstructTimeLikeJet(dynamic_ptr_cast<ShowerParticlePtr>(*cit));
}
// it is a reconstruction fixpoint, ie kinematical data has to be available
else {
// check if the parent was part of the shower
ShowerParticlePtr jetGrandParent;
if(!particleJetParent->parents().empty())
jetGrandParent= dynamic_ptr_cast<ShowerParticlePtr>
(particleJetParent->parents()[0]);
// update if so
if (jetGrandParent) {
if (jetGrandParent->showerKinematics()) {
if(particleJetParent->id()==_progenitor->id()&&
- !_progenitor->data().stable()) {
+ !_progenitor->data().stable()&&abs(_progenitor->data().id())!=ParticleID::tauminus) {
jetGrandParent->showerKinematics()->reconstructLast(particleJetParent,
_progenitor->mass());
}
else {
jetGrandParent->showerKinematics()->reconstructLast(particleJetParent);
}
}
}
// otherwise
else {
Energy dm = particleJetParent->data().constituentMass();
if (abs(dm-particleJetParent->momentum().m())>0.001*MeV
- &&particleJetParent->dataPtr()->stable()
+ &&(particleJetParent->dataPtr()->stable() || abs(particleJetParent->id())==ParticleID::tauminus)
&&particleJetParent->id()!=ParticleID::gamma
&&_noRescale.find(particleJetParent->dataPtr())==_noRescale.end()) {
Lorentz5Momentum dum = particleJetParent->momentum();
dum.setMass(dm);
dum.rescaleEnergy();
particleJetParent->set5Momentum(dum);
}
else {
emitted=false;
}
}
}
// recursion has reached an endpoint once, ie we can reconstruct the
// kinematics from the children.
if( !particleJetParent->children().empty() )
particleJetParent->showerKinematics()
->reconstructParent( particleJetParent, particleJetParent->children() );
return emitted;
}
bool QTildeReconstructor::
reconstructHardJets(ShowerTreePtr hard,
const map<tShowerProgenitorPtr,
pair<Energy,double> > & intrinsic,
ShowerInteraction type,
bool switchRecon) const {
_currentTree = hard;
_intrinsic=intrinsic;
// extract the particles from the ShowerTree
vector<ShowerProgenitorPtr> ShowerHardJets=hard->extractProgenitors();
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
_boosts[ShowerHardJets[ix]->progenitor()] = vector<LorentzRotation>();
}
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit = _currentTree->treelinks().begin();
tit != _currentTree->treelinks().end();++tit) {
_treeBoosts[tit->first] = vector<LorentzRotation>();
}
try {
// old recon method, using new member functions
if(_reconopt == 0 || switchRecon ) {
reconstructGeneralSystem(ShowerHardJets);
}
// reconstruction based on coloured systems
else if( _reconopt == 1) {
reconstructColourSinglets(ShowerHardJets,type);
}
// reconstruction of FF, then IF, then II
else if( _reconopt == 2) {
reconstructFinalFirst(ShowerHardJets);
}
// reconstruction based on coloured systems
else if( _reconopt == 3 || _reconopt == 4) {
reconstructColourPartner(ShowerHardJets);
}
else
assert(false);
}
catch(KinematicsReconstructionVeto) {
_progenitor=tShowerParticlePtr();
_intrinsic.clear();
for(map<tPPtr,vector<LorentzRotation> >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) {
for(vector<LorentzRotation>::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) {
LorentzRotation rot = rit->inverse();
bit->first->transform(rot);
}
}
_boosts.clear();
for(map<tShowerTreePtr,vector<LorentzRotation> >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) {
for(vector<LorentzRotation>::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) {
LorentzRotation rot = rit->inverse();
bit->first->transform(rot,false);
}
}
_currentTree = tShowerTreePtr();
_treeBoosts.clear();
return false;
}
catch (Exception & ex) {
_progenitor=tShowerParticlePtr();
_intrinsic.clear();
_currentTree = tShowerTreePtr();
_boosts.clear();
_treeBoosts.clear();
throw ex;
}
_progenitor=tShowerParticlePtr();
_intrinsic.clear();
// ensure x<1
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=hard->incomingLines().begin();cit!=hard->incomingLines().end();++cit) {
tPPtr parent = cit->first->progenitor();
while (!parent->parents().empty()) {
parent = parent->parents()[0];
}
tPPtr hadron;
if ( cit->first->original()->parents().empty() ) {
hadron = cit->first->original();
}
else {
hadron = cit->first->original()->parents()[0];
}
if( ! (hadron->id() == parent->id() && hadron->children().size() <= 1)
&& parent->momentum().rho() > hadron->momentum().rho()) {
_progenitor=tShowerParticlePtr();
_intrinsic.clear();
for(map<tPPtr,vector<LorentzRotation> >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) {
for(vector<LorentzRotation>::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) {
LorentzRotation rot = rit->inverse();
bit->first->transform(rot);
}
}
_boosts.clear();
for(map<tShowerTreePtr,vector<LorentzRotation> >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) {
for(vector<LorentzRotation>::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) {
LorentzRotation rot = rit->inverse();
bit->first->transform(rot,false);
}
}
_currentTree = tShowerTreePtr();
_treeBoosts.clear();
return false;
}
}
_boosts.clear();
_treeBoosts.clear();
_currentTree = tShowerTreePtr();
return true;
}
double
QTildeReconstructor::solveKfactor(const Energy & root_s,
const JetKinVect & jets) const {
Energy2 s = sqr(root_s);
// must be at least two jets
if ( jets.size() < 2) throw KinematicsReconstructionVeto();
// sum of jet masses must be less than roots
if(momConsEq( 0.0, root_s, jets )>ZERO) throw KinematicsReconstructionVeto();
// if two jets simple solution
if ( jets.size() == 2 ) {
static const Energy2 eps = 1.0e-4 * MeV2;
if ( sqr(jets[0].p.x()+jets[1].p.x()) < eps &&
sqr(jets[0].p.y()+jets[1].p.y()) < eps &&
sqr(jets[0].p.z()+jets[1].p.z()) < eps ) {
Energy test = (jets[0].p+jets[1].p).vect().mag();
if(test > 1.0e-4 * MeV) throw KinematicsReconstructionVeto();
if ( jets[0].p.vect().mag2() < eps ) throw KinematicsReconstructionVeto();
Energy2 m1sq(jets[0].q.m2()),m2sq(jets[1].q.m2());
return sqrt( ( sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq )
/(4.*s*jets[0].p.vect().mag2()) );
}
else throw KinematicsReconstructionVeto();
}
// i.e. jets.size() > 2, numerically
// check convergence, if it's a problem maybe use Newton iteration?
else {
double k1 = 0.,k2 = 1.,k = 0.;
if ( momConsEq( k1, root_s, jets ) < ZERO ) {
while ( momConsEq( k2, root_s, jets ) < ZERO ) {
k1 = k2;
k2 *= 2;
}
while ( fabs( (k1 - k2)/(k1 + k2) ) > 1.e-10 ) {
if( momConsEq( k2, root_s, jets ) == ZERO ) {
return k2;
} else {
k = (k1+k2)/2.;
if ( momConsEq( k, root_s, jets ) > ZERO ) {
k2 = k;
} else {
k1 = k;
}
}
}
return k1;
} else throw KinematicsReconstructionVeto();
}
throw KinematicsReconstructionVeto();
}
bool QTildeReconstructor::
reconstructSpaceLikeJet( const tShowerParticlePtr p) const {
bool emitted = true;
tShowerParticlePtr child;
tShowerParticlePtr parent;
if(!p->parents().empty())
parent = dynamic_ptr_cast<ShowerParticlePtr>(p->parents()[0]);
if(parent) {
emitted=true;
reconstructSpaceLikeJet(parent);
}
// if branching reconstruct time-like child
if(p->children().size()==2)
child = dynamic_ptr_cast<ShowerParticlePtr>(p->children()[1]);
if(p->perturbative()==0 && child) {
dynamic_ptr_cast<ShowerParticlePtr>(p->children()[0])->
showerKinematics()->reconstructParent(p,p->children());
if(!child->children().empty()) {
_progenitor=child;
reconstructTimeLikeJet(child);
// calculate the momentum of the particle
Lorentz5Momentum pnew=p->momentum()-child->momentum();
pnew.rescaleMass();
p->children()[0]->set5Momentum(pnew);
}
}
return emitted;
}
Boost QTildeReconstructor::
solveBoostBeta( const double k, const Lorentz5Momentum & newq,
const Lorentz5Momentum & oldp ) {
// try something different, purely numerical first:
// a) boost to rest frame of newq, b) boost with kp/E
Energy q = newq.vect().mag();
Energy2 qs = sqr(q);
Energy2 Q2 = newq.m2();
Energy kp = k*(oldp.vect().mag());
Energy2 kps = sqr(kp);
// usually we take the minus sign, since this boost will be smaller.
// we only require |k \vec p| = |\vec q'| which leaves the sign of
// the boost open but the 'minus' solution gives a smaller boost
// parameter, i.e. the result should be closest to the previous
// result. this is to be changed if we would get many momentum
// conservation violations at the end of the shower from a hard
// process.
double betam = (q*sqrt(qs + Q2) - kp*sqrt(kps + Q2))/(kps + qs + Q2);
// move directly to 'return'
Boost beta = -betam*(k/kp)*oldp.vect();
// note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper.
// leave this out if it's running properly!
if ( betam >= 0 ) return beta;
else return Boost(0., 0., 0.);
}
bool QTildeReconstructor::
reconstructDecayJets(ShowerTreePtr decay,
ShowerInteraction) const {
_currentTree = decay;
// extract the particles from the ShowerTree
vector<ShowerProgenitorPtr> ShowerHardJets=decay->extractProgenitors();
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
_boosts[ShowerHardJets[ix]->progenitor()] = vector<LorentzRotation>();
}
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit = _currentTree->treelinks().begin();
tit != _currentTree->treelinks().end();++tit) {
_treeBoosts[tit->first] = vector<LorentzRotation>();
}
try {
bool radiated[2]={false,false};
// find the decaying particle and check if particles radiated
ShowerProgenitorPtr initial;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
// only consider initial-state jets
if(ShowerHardJets[ix]->progenitor()->isFinalState()) {
radiated[1] |=ShowerHardJets[ix]->hasEmitted();
}
else {
initial=ShowerHardJets[ix];
radiated[0]|=ShowerHardJets[ix]->hasEmitted();
}
}
// find boost to the rest frame if needed
Boost boosttorest=-initial->progenitor()->momentum().boostVector();
double gammarest =
initial->progenitor()->momentum().e()/
initial->progenitor()->momentum().mass();
// check if need to boost to rest frame
bool gottaBoost = (boosttorest.mag() > 1e-12);
// if initial state radiation reconstruct the jet and set up the basis vectors
Lorentz5Momentum pjet;
Lorentz5Momentum nvect;
// find the partner
ShowerParticlePtr partner = initial->progenitor()->partner();
Lorentz5Momentum ppartner[2];
if(partner) ppartner[0]=partner->momentum();
// get the n reference vector
if(partner) {
if(initial->progenitor()->showerKinematics()) {
nvect = initial->progenitor()->showerBasis()->getBasis()[1];
}
else {
Lorentz5Momentum ppartner=initial->progenitor()->partner()->momentum();
if(gottaBoost) ppartner.boost(boosttorest,gammarest);
nvect = Lorentz5Momentum( ZERO,0.5*initial->progenitor()->mass()*
ppartner.vect().unit());
nvect.boost(-boosttorest,gammarest);
}
}
// if ISR
if(radiated[0]) {
// reconstruct the decay jet
reconstructDecayJet(initial->progenitor());
// momentum of decaying particle after ISR
pjet=initial->progenitor()->momentum()
-decay->incomingLines().begin()->second->momentum();
pjet.rescaleMass();
}
// boost initial state jet and basis vector if needed
if(gottaBoost) {
pjet.boost(boosttorest,gammarest);
nvect.boost(boosttorest,gammarest);
ppartner[0].boost(boosttorest,gammarest);
}
// loop over the final-state particles and do the reconstruction
JetKinVect possiblepartners;
JetKinVect jetKinematics;
bool atLeastOnce = radiated[0];
LorentzRotation restboost(boosttorest,gammarest);
Energy inmass(ZERO);
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
// only consider final-state jets
if(!ShowerHardJets[ix]->progenitor()->isFinalState()) {
inmass=ShowerHardJets[ix]->progenitor()->mass();
continue;
}
// do the reconstruction
JetKinStruct tempJetKin;
tempJetKin.parent = ShowerHardJets[ix]->progenitor();
if(ShowerHardJets.size()==2) {
Lorentz5Momentum dum=ShowerHardJets[ix]->progenitor()->momentum();
dum.setMass(inmass);
dum.rescaleRho();
tempJetKin.parent->set5Momentum(dum);
}
tempJetKin.p = ShowerHardJets[ix]->progenitor()->momentum();
if(gottaBoost) tempJetKin.p.boost(boosttorest,gammarest);
_progenitor=tempJetKin.parent;
if(ShowerHardJets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) {
atLeastOnce |= reconstructTimeLikeJet(tempJetKin.parent);
ShowerHardJets[ix]->reconstructed(ShowerProgenitor::done);
}
if(gottaBoost) deepTransform(tempJetKin.parent,restboost);
tempJetKin.q = ShowerHardJets[ix]->progenitor()->momentum();
jetKinematics.push_back(tempJetKin);
}
if(partner) ppartner[1]=partner->momentum();
// calculate the rescaling parameters
double k1,k2;
Lorentz5Momentum qt;
if(!solveDecayKFactor(initial->progenitor()->mass(),nvect,pjet,
jetKinematics,partner,ppartner,k1,k2,qt)) {
for(map<tPPtr,vector<LorentzRotation> >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) {
for(vector<LorentzRotation>::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) {
LorentzRotation rot = rit->inverse();
bit->first->transform(rot);
}
}
_boosts.clear();
for(map<tShowerTreePtr,vector<LorentzRotation> >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) {
for(vector<LorentzRotation>::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) {
LorentzRotation rot = rit->inverse();
bit->first->transform(rot,false);
}
}
_treeBoosts.clear();
_currentTree = tShowerTreePtr();
return false;
}
// apply boosts and rescalings to final-state jets
for(JetKinVect::iterator it = jetKinematics.begin();
it != jetKinematics.end(); ++it) {
LorentzRotation Trafo = LorentzRotation();
if(it->parent!=partner) {
// boost for rescaling
if(atLeastOnce) {
map<tShowerTreePtr,pair<tShowerProgenitorPtr,
tShowerParticlePtr> >::const_iterator tit;
for(tit = _currentTree->treelinks().begin();
tit != _currentTree->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==it->parent)
break;
}
if(it->parent->children().empty()&&!it->parent->spinInfo() &&
tit==_currentTree->treelinks().end()) {
Lorentz5Momentum pnew(k2*it->p.vect(),
sqrt(sqr(k2*it->p.vect().mag())+it->q.mass2()),
it->q.mass());
it->parent->set5Momentum(pnew);
}
else {
// rescaling boost can't ever work in this case
if(k2<0. && it->q.mass()==ZERO)
throw KinematicsReconstructionVeto();
Trafo = solveBoost(k2, it->q, it->p);
}
}
if(gottaBoost) Trafo.boost(-boosttorest,gammarest);
if(atLeastOnce || gottaBoost) deepTransform(it->parent,Trafo);
}
else {
Lorentz5Momentum pnew=ppartner[0];
pnew *=k1;
pnew-=qt;
pnew.setMass(ppartner[1].mass());
pnew.rescaleEnergy();
LorentzRotation Trafo=solveBoost(1.,ppartner[1],pnew);
if(gottaBoost) Trafo.boost(-boosttorest,gammarest);
deepTransform(partner,Trafo);
}
}
}
catch(KinematicsReconstructionVeto) {
for(map<tPPtr,vector<LorentzRotation> >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) {
for(vector<LorentzRotation>::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) {
LorentzRotation rot = rit->inverse();
bit->first->transform(rot);
}
}
_boosts.clear();
for(map<tShowerTreePtr,vector<LorentzRotation> >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) {
for(vector<LorentzRotation>::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) {
LorentzRotation rot = rit->inverse();
bit->first->transform(rot,false);
}
}
_treeBoosts.clear();
_currentTree = tShowerTreePtr();
return false;
}
catch (Exception & ex) {
_currentTree = tShowerTreePtr();
_boosts.clear();
_treeBoosts.clear();
throw ex;
}
_boosts.clear();
_treeBoosts.clear();
_currentTree = tShowerTreePtr();
return true;
}
bool QTildeReconstructor::
reconstructDecayJet( const tShowerParticlePtr p) const {
if(p->children().empty()) return false;
tShowerParticlePtr child;
// if branching reconstruct time-like child
child = dynamic_ptr_cast<ShowerParticlePtr>(p->children()[1]);
if(child) {
_progenitor=child;
reconstructTimeLikeJet(child);
// calculate the momentum of the particle
Lorentz5Momentum pnew=p->momentum()-child->momentum();
pnew.rescaleMass();
p->children()[0]->set5Momentum(pnew);
child=dynamic_ptr_cast<ShowerParticlePtr>(p->children()[0]);
reconstructDecayJet(child);
return true;
}
return false;
}
bool QTildeReconstructor::
solveDecayKFactor(Energy mb,
const Lorentz5Momentum & n,
const Lorentz5Momentum & pjet,
const JetKinVect & jetKinematics,
ShowerParticlePtr partner,
Lorentz5Momentum ppartner[2],
double & k1, double & k2,
Lorentz5Momentum & qt) const {
Energy2 pjn = partner ? pjet.vect()*n.vect() : ZERO;
Energy2 pcn = partner ? ppartner[0].vect()*n.vect() : 1.*MeV2;
Energy2 nmag = n.vect().mag2();
Lorentz5Momentum pn = partner ? (pjn/nmag)*n : Lorentz5Momentum();
qt=pjet-pn; qt.setE(ZERO);
Energy2 pt2=qt.vect().mag2();
Energy Ejet = pjet.e();
// magnitudes of the momenta for fast access
vector<Energy2> pmag;
Energy total(Ejet);
for(unsigned int ix=0;ix<jetKinematics.size();++ix) {
pmag.push_back(jetKinematics[ix].p.vect().mag2());
total+=jetKinematics[ix].q.mass();
}
// return if no possible solution
if(total>mb) return false;
Energy2 pcmag=ppartner[0].vect().mag2();
// used newton-raphson to get the rescaling
static const Energy eps=1e-8*GeV;
long double d1(1.),d2(1.);
Energy roots, ea, ec, ds;
unsigned int ix=0;
do {
++ix;
d2 = d1 + pjn/pcn;
roots = Ejet;
ds = ZERO;
for(unsigned int iy=0;iy<jetKinematics.size();++iy) {
if(jetKinematics[iy].parent==partner) continue;
ea = sqrt(sqr(d2)*pmag[iy]+jetKinematics[iy].q.mass2());
roots += ea;
ds += d2/ea*pmag[iy];
}
if(partner) {
ec = sqrt(sqr(d1)*pcmag + pt2 + ppartner[1].mass2());
roots += ec;
ds += d1/ec*pcmag;
}
d1 += (mb-roots)/ds;
d2 = d1 + pjn/pcn;
}
while(abs(mb-roots)>eps && ix<100);
k1=d1;
k2=d2;
// return true if N-R succeed, otherwise false
return ix<100;
}
bool QTildeReconstructor::
deconstructDecayJets(HardTreePtr decay,ShowerInteraction) const {
// extract the momenta of the particles
vector<Lorentz5Momentum> pin;
vector<Lorentz5Momentum> pout;
// on-shell masses of the decay products
vector<Energy> mon;
Energy mbar(-GeV);
// the hard branchings of the particles
set<HardBranchingPtr>::iterator cit;
set<HardBranchingPtr> branchings=decay->branchings();
// properties of the incoming particle
bool ISR = false;
HardBranchingPtr initial;
Lorentz5Momentum qisr;
// find the incoming particle, both before and after
// any ISR
for(cit=branchings.begin();cit!=branchings.end();++cit){
if((*cit)->status()==HardBranching::Incoming||
(*cit)->status()==HardBranching::Decay) {
// search back up isr if needed
HardBranchingPtr branch = *cit;
while(branch->parent()) branch=branch->parent();
initial=branch;
// momentum or original parent
pin.push_back(branch->branchingParticle()->momentum());
// ISR?
ISR = !branch->branchingParticle()->children().empty();
// ISR momentum
qisr = pin.back()-(**cit).branchingParticle()->momentum();
qisr.rescaleMass();
}
}
assert(pin.size()==1);
// compute boost to rest frame
Boost boostv=-pin[0].boostVector();
// partner for ISR
ShowerParticlePtr partner;
Lorentz5Momentum ppartner;
if(initial->branchingParticle()->partner()) {
partner=initial->branchingParticle()->partner();
ppartner=partner->momentum();
}
// momentum of the decay products
for(cit=branchings.begin();cit!=branchings.end();++cit) {
if((*cit)->status()!=HardBranching::Outgoing) continue;
// find the mass of the particle
// including special treatment for off-shell resonances
// to preserve off-shell mass
Energy mass;
if(!(**cit).branchingParticle()->dataPtr()->stable()) {
HardBranchingPtr branch=*cit;
while(!branch->children().empty()) {
for(unsigned int ix=0;ix<branch->children().size();++ix) {
if(branch->children()[ix]->branchingParticle()->id()==
(**cit).branchingParticle()->id()) {
branch = branch->children()[ix];
continue;
}
}
};
mass = branch->branchingParticle()->mass();
}
else {
mass = (**cit).branchingParticle()->dataPtr()->mass();
}
// if not evolution partner of decaying particle
if((*cit)->branchingParticle()!=partner) {
pout.push_back((*cit)->branchingParticle()->momentum());
mon.push_back(mass);
}
// evolution partner of decaying particle
else {
mbar = mass;
}
}
// boost all the momenta to the rest frame of the decaying particle
for(unsigned int ix=0;ix<pout.size();++ix) pout[ix].boost(boostv);
if(initial->branchingParticle()->partner()) {
ppartner.boost(boostv);
qisr.boost(boostv);
}
// compute the rescaling factors
double k1,k2;
if(!ISR) {
if(partner) {
pout.push_back(ppartner);
mon.push_back(mbar);
}
k1=k2=inverseRescalingFactor(pout,mon,pin[0].mass());
if(partner) {
pout.pop_back();
mon.pop_back();
}
}
else {
if(!inverseDecayRescalingFactor(pout,mon,pin[0].mass(),
ppartner,mbar,k1,k2)) return false;
}
// now calculate the p reference vectors
unsigned int ifinal=0;
for(cit=branchings.begin();cit!=branchings.end();++cit) {
if((**cit).status()!=HardBranching::Outgoing) continue;
// for partners other than colour partner of decaying particle
if((*cit)->branchingParticle()!=partner) {
Lorentz5Momentum pvect = (*cit)->branchingParticle()->momentum();
pvect.boost(boostv);
pvect /= k1;
pvect.setMass(mon[ifinal]);
++ifinal;
pvect.rescaleEnergy();
pvect.boost(-boostv);
(*cit)->pVector(pvect);
(*cit)->showerMomentum(pvect);
}
// for colour partner of decaying particle
else {
Lorentz5Momentum pvect = (*cit)->branchingParticle()->momentum();
pvect.boost(boostv);
Lorentz5Momentum qtotal;
for(unsigned int ix=0;ix<pout.size();++ix) qtotal+=pout[ix];
Lorentz5Momentum qperp =
qisr-(qisr.vect()*qtotal.vect())/(qtotal.vect().mag2())*qtotal;
pvect +=qperp;
pvect /=k2;
pvect.setMass(mbar);
pvect.rescaleEnergy();
pvect.boost(-boostv);
(*cit)->pVector(pvect);
(*cit)->showerMomentum(pvect);
}
}
// For initial-state if needed
if(initial) {
tShowerParticlePtr newPartner=initial->branchingParticle()->partner();
if(newPartner) {
tHardBranchingPtr branch;
for( set<HardBranchingPtr>::iterator clt = branchings.begin();
clt != branchings.end(); ++clt ) {
if((**clt).branchingParticle()==newPartner) {
initial->colourPartner(*clt);
branch=*clt;
break;
}
}
Lorentz5Momentum pvect = initial->branchingParticle()->momentum();
initial->pVector(pvect);
Lorentz5Momentum ptemp = branch->pVector();
ptemp.boost(boostv);
Lorentz5Momentum nvect = Lorentz5Momentum( ZERO,
0.5*initial->branchingParticle()->mass()*
ptemp.vect().unit());
nvect.boost(-boostv);
initial->nVector(nvect);
}
}
// calculate the reference vectors, then for outgoing particles
for(cit=branchings.begin();cit!=branchings.end();++cit){
if((**cit).status()!=HardBranching::Outgoing) continue;
// find the partner branchings
tShowerParticlePtr newPartner=(*cit)->branchingParticle()->partner();
if(!newPartner) continue;
tHardBranchingPtr branch;
for( set<HardBranchingPtr>::iterator clt = branchings.begin();
clt != branchings.end(); ++clt ) {
if(cit==clt) continue;
if((**clt).branchingParticle()==newPartner) {
(**cit).colourPartner(*clt);
branch=*clt;
break;
}
}
if((**decay->incoming().begin()).branchingParticle()==newPartner) {
(**cit).colourPartner(*decay->incoming().begin());
branch = *decay->incoming().begin();
}
// final-state colour partner
if(branch->status()==HardBranching::Outgoing) {
Boost boost=((*cit)->pVector()+branch->pVector()).findBoostToCM();
Lorentz5Momentum pcm = branch->pVector();
pcm.boost(boost);
Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect());
nvect.boost( -boost);
(*cit)->nVector(nvect);
}
// initial-state colour partner
else {
Boost boost=branch->pVector().findBoostToCM();
Lorentz5Momentum pcm = (*cit)->pVector();
pcm.boost(boost);
Lorentz5Momentum nvect = Lorentz5Momentum( ZERO, -pcm.vect());
nvect.boost( -boost);
(*cit)->nVector(nvect);
}
}
// now compute the new momenta
// and calculate the shower variables
for(cit=branchings.begin();cit!=branchings.end();++cit) {
if((**cit).status()!=HardBranching::Outgoing) continue;
LorentzRotation B=LorentzRotation(-boostv);
LorentzRotation A=LorentzRotation(boostv),R;
if((*cit)->branchingParticle()==partner) {
Lorentz5Momentum qnew;
Energy2 dot=(*cit)->pVector()*(*cit)->nVector();
double beta = 0.5*((*cit)->branchingParticle()->momentum().m2()
-sqr((*cit)->pVector().mass()))/dot;
qnew=(*cit)->pVector()+beta*(*cit)->nVector();
qnew.rescaleMass();
// compute the boost
R=B*solveBoost(A*qnew,A*(*cit)->branchingParticle()->momentum())*A;
}
else {
Lorentz5Momentum qnew;
if((*cit)->branchingParticle()->partner()) {
Energy2 dot=(*cit)->pVector()*(*cit)->nVector();
double beta = 0.5*((*cit)->branchingParticle()->momentum().m2()
-sqr((*cit)->pVector().mass()))/dot;
qnew=(*cit)->pVector()+beta*(*cit)->nVector();
qnew.rescaleMass();
}
else {
qnew = (*cit)->pVector();
}
// compute the boost
R=B*solveBoost(A*qnew,A*(*cit)->branchingParticle()->momentum())*A;
}
// reconstruct the momenta
(*cit)->setMomenta(R,1.0,Lorentz5Momentum());
}
if(initial) {
initial->setMomenta(LorentzRotation(),1.0,Lorentz5Momentum());
}
return true;
}
double QTildeReconstructor::
inverseRescalingFactor(vector<Lorentz5Momentum> pout,
vector<Energy> mon, Energy roots) const {
double lambda=1.;
if(pout.size()==2) {
double mu_q1(pout[0].m()/roots), mu_q2(pout[1].m()/roots);
double mu_p1(mon[0]/roots) , mu_p2(mon[1]/roots);
lambda =
((1.+mu_q1+mu_q2)*(1.-mu_q1-mu_q2)*(mu_q1-1.-mu_q2)*(mu_q2-1.-mu_q1))/
((1.+mu_p1+mu_p2)*(1.-mu_p1-mu_p2)*(mu_p1-1.-mu_p2)*(mu_p2-1.-mu_p1));
if(lambda<0.)
throw Exception() << "Rescaling factor is imaginary in QTildeReconstructor::"
<< "inverseRescalingFactor lambda^2= " << lambda
<< Exception::eventerror;
lambda = sqrt(lambda);
}
else {
unsigned int ntry=0;
// compute magnitudes once for speed
vector<Energy2> pmag;
for(unsigned int ix=0;ix<pout.size();++ix) {
pmag.push_back(pout[ix].vect().mag2());
}
// Newton-Raphson for the rescaling
vector<Energy> root(pout.size());
do {
// compute new energies
Energy sum(ZERO);
for(unsigned int ix=0;ix<pout.size();++ix) {
root[ix] = sqrt(pmag[ix]/sqr(lambda)+sqr(mon[ix]));
sum+=root[ix];
}
// if accuracy reached exit
if(abs(sum/roots-1.)<1e-10) break;
// use Newton-Raphson to compute new guess for lambda
Energy numer(ZERO),denom(ZERO);
for(unsigned int ix=0;ix<pout.size();++ix) {
numer +=root[ix];
denom +=pmag[ix]/root[ix];
}
numer-=roots;
double fact = 1.+sqr(lambda)*numer/denom;
if(fact<0.) fact=0.5;
lambda *=fact;
++ntry;
}
while(ntry<100);
}
if(std::isnan(lambda))
throw Exception() << "Rescaling factor is nan in QTildeReconstructor::"
<< "inverseRescalingFactor "
<< Exception::eventerror;
return lambda;
}
bool QTildeReconstructor::
deconstructGeneralSystem(HardTreePtr tree,
ShowerInteraction type) const {
// extract incoming and outgoing particles
ColourSingletShower in,out;
for(set<HardBranchingPtr>::const_iterator it=tree->branchings().begin();
it!=tree->branchings().end();++it) {
if((**it).status()==HardBranching::Incoming) in .jets.push_back(*it);
else out.jets.push_back(*it);
}
LorentzRotation toRest,fromRest;
bool applyBoost(false);
// do the initial-state reconstruction
deconstructInitialInitialSystem(applyBoost,toRest,fromRest,
tree,in.jets,type);
// do the final-state reconstruction
deconstructFinalStateSystem(toRest,fromRest,tree,
out.jets,type);
// only at this point that we can be sure all the reference vectors
// are correct
for(set<HardBranchingPtr>::const_iterator it=tree->branchings().begin();
it!=tree->branchings().end();++it) {
if((**it).status()==HardBranching::Incoming) continue;
if((**it).branchingParticle()->coloured())
(**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false);
}
for(set<HardBranchingPtr>::const_iterator it=tree->incoming().begin();
it!=tree->incoming().end();++it) {
(**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false);
}
return true;
}
bool QTildeReconstructor::deconstructHardJets(HardTreePtr tree,
ShowerInteraction type) const {
// inverse of old recon method
if(_reconopt == 0) {
return deconstructGeneralSystem(tree,type);
}
else if(_reconopt == 1) {
return deconstructColourSinglets(tree,type);
}
else if(_reconopt == 2) {
throw Exception() << "Inverse reconstruction is not currently supported for ReconstructionOption Colour2 "
<< "in QTildeReconstructor::deconstructHardJets(). Please use one of the other options\n"
<< Exception::runerror;
}
else if(_reconopt == 3 || _reconopt == 4 ) {
return deconstructColourPartner(tree,type);
}
else
assert(false);
}
bool QTildeReconstructor::
deconstructColourSinglets(HardTreePtr tree,
ShowerInteraction type) const {
// identify the colour singlet systems
unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0);
vector<ColourSingletShower>
systems(identifySystems(tree->branchings(),nnun,nnii,nnif,nnf,nni));
// now decide what to do
LorentzRotation toRest,fromRest;
bool applyBoost(false);
bool general(false);
// initial-initial connection and final-state colour singlet systems
// Drell-Yan type
if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) {
// reconstruct initial-initial system
for(unsigned int ix=0;ix<systems.size();++ix) {
if(systems[ix].type==II)
deconstructInitialInitialSystem(applyBoost,toRest,fromRest,tree,
systems[ix].jets,type);
}
if(type!=ShowerInteraction::QCD) {
combineFinalState(systems);
general=false;
}
}
// DIS and VBF type
else if(nnun==0&&nnii==0&&((nnif==1&&nnf>0&&nni==1)||
(nnif==2&& nni==0))) {
for(unsigned int ix=0;ix<systems.size();++ix) {
if(systems[ix].type==IF)
deconstructInitialFinalSystem(tree,systems[ix].jets,type);
}
}
// e+e- type
else if(nnun==0&&nnii==0&&nnif==0&&nnf>0&&nni==2) {
// only FS needed
// but need to boost to rest frame if QED ISR
Lorentz5Momentum ptotal;
for(unsigned int ix=0;ix<systems.size();++ix) {
if(systems[ix].type==I)
ptotal += systems[ix].jets[0]->branchingParticle()->momentum();
}
toRest = LorentzRotation(ptotal.findBoostToCM());
fromRest = toRest;
fromRest.invert();
if(type!=ShowerInteraction::QCD) {
combineFinalState(systems);
general=false;
}
}
// general type
else {
general = true;
}
// final-state systems except for general recon
if(!general) {
for(unsigned int ix=0;ix<systems.size();++ix) {
if(systems[ix].type==F)
deconstructFinalStateSystem(toRest,fromRest,tree,
systems[ix].jets,type);
}
// only at this point that we can be sure all the reference vectors
// are correct
for(set<HardBranchingPtr>::const_iterator it=tree->branchings().begin();
it!=tree->branchings().end();++it) {
if((**it).status()==HardBranching::Incoming) continue;
if((**it).branchingParticle()->coloured())
(**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false);
}
for(set<HardBranchingPtr>::const_iterator it=tree->incoming().begin();
it!=tree->incoming().end();++it) {
(**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false);
}
return true;
}
else {
return deconstructGeneralSystem(tree,type);
}
return true;
}
bool QTildeReconstructor::
deconstructColourPartner(HardTreePtr tree,
ShowerInteraction type) const {
Lorentz5Momentum ptotal;
HardBranchingPtr emitter;
ColourSingletShower incomingShower,outgoingShower;
for(set<HardBranchingPtr>::const_iterator it=tree->branchings().begin();
it!=tree->branchings().end();++it) {
if((**it).status()==HardBranching::Incoming) {
incomingShower.jets.push_back(*it);
ptotal += (*it)->branchingParticle()->momentum();
// check for emitting particle
if((**it).parent() ) {
if(!emitter)
emitter = *it;
else
throw Exception() << "Only one emitting particle allowed in "
<< "QTildeReconstructor::deconstructColourPartner()"
<< Exception::runerror;
}
}
else if ((**it).status()==HardBranching::Outgoing) {
outgoingShower.jets.push_back(*it);
// check for emitting particle
if(!(**it).children().empty() ) {
if(!emitter)
emitter = *it;
else
throw Exception() << "Only one emitting particle allowed in "
<< "QTildeReconstructor::deconstructColourPartner()"
<< Exception::runerror;
}
}
}
assert(emitter);
assert(emitter->colourPartner());
ColourSingletShower system;
system.jets.push_back(emitter);
system.jets.push_back(emitter->colourPartner());
LorentzRotation toRest,fromRest;
bool applyBoost(false);
// identify the colour singlet system
if(emitter->status() == HardBranching::Outgoing &&
emitter->colourPartner()->status() == HardBranching::Outgoing ) {
system.type=F;
// need to boost to rest frame if QED ISR
if( !incomingShower.jets[0]->branchingParticle()->coloured() &&
!incomingShower.jets[1]->branchingParticle()->coloured() ) {
Boost boost = ptotal.findBoostToCM();
toRest = LorentzRotation( boost);
fromRest = LorentzRotation(-boost);
}
else
findInitialBoost(ptotal,ptotal,toRest,fromRest);
deconstructFinalStateSystem(toRest,fromRest,tree,
system.jets,type);
}
else if (emitter->status() == HardBranching::Incoming &&
emitter->colourPartner()->status() == HardBranching::Incoming) {
system.type=II;
deconstructInitialInitialSystem(applyBoost,toRest,fromRest,tree,system.jets,type);
// make sure the recoil gets applied
deconstructFinalStateSystem(toRest,fromRest,tree,
outgoingShower.jets,type);
}
else if ((emitter->status() == HardBranching::Outgoing &&
emitter->colourPartner()->status() == HardBranching::Incoming ) ||
(emitter->status() == HardBranching::Incoming &&
emitter->colourPartner()->status() == HardBranching::Outgoing)) {
system.type=IF;
// enusre incoming first
if(system.jets[0]->status() == HardBranching::Outgoing)
swap(system.jets[0],system.jets[1]);
deconstructInitialFinalSystem(tree,system.jets,type);
}
else {
throw Exception() << "Unknown type of system in "
<< "QTildeReconstructor::deconstructColourPartner()"
<< Exception::runerror;
}
// only at this point that we can be sure all the reference vectors
// are correct
for(set<HardBranchingPtr>::const_iterator it=tree->branchings().begin();
it!=tree->branchings().end();++it) {
if((**it).status()==HardBranching::Incoming) continue;
if((**it).branchingParticle()->coloured())
(**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false);
}
for(set<HardBranchingPtr>::const_iterator it=tree->incoming().begin();
it!=tree->incoming().end();++it) {
(**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false);
}
for(set<HardBranchingPtr>::const_iterator it=tree->branchings().begin();
it!=tree->branchings().end();++it) {
if((**it).status()!=HardBranching::Incoming) continue;
if(*it==system.jets[0] || *it==system.jets[1]) continue;
if((**it).branchingParticle()->momentum().z()>ZERO) {
(**it).z((**it).branchingParticle()->momentum().plus()/(**it).beam()->momentum().plus());
}
else {
(**it).z((**it).branchingParticle()->momentum().minus()/(**it).beam()->momentum().minus());
}
}
return true;
}
void QTildeReconstructor::
reconstructInitialFinalSystem(vector<ShowerProgenitorPtr> jets) const {
Lorentz5Momentum pin[2],pout[2],pbeam;
for(unsigned int ix=0;ix<jets.size();++ix) {
// final-state parton
if(jets[ix]->progenitor()->isFinalState()) {
pout[0] +=jets[ix]->progenitor()->momentum();
_progenitor = jets[ix]->progenitor();
if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) {
reconstructTimeLikeJet(jets[ix]->progenitor());
jets[ix]->reconstructed(ShowerProgenitor::done);
}
}
// initial-state parton
else {
pin[0] +=jets[ix]->progenitor()->momentum();
if(jets[ix]->progenitor()->showerKinematics()) {
pbeam = jets[ix]->progenitor()->showerBasis()->getBasis()[0];
}
else {
if ( jets[ix]->original()->parents().empty() ) {
pbeam = jets[ix]->progenitor()->momentum();
}
else {
pbeam = jets[ix]->original()->parents()[0]->momentum();
}
}
if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) {
reconstructSpaceLikeJet(jets[ix]->progenitor());
jets[ix]->reconstructed(ShowerProgenitor::done);
}
assert(!jets[ix]->original()->parents().empty());
}
}
// add intrinsic pt if needed
addIntrinsicPt(jets);
// momenta after showering
for(unsigned int ix=0;ix<jets.size();++ix) {
if(jets[ix]->progenitor()->isFinalState())
pout[1] += jets[ix]->progenitor()->momentum();
else
pin[1] += jets[ix]->progenitor()->momentum();
}
// work out the boost to the Breit frame
Lorentz5Momentum pa = pout[0]-pin[0];
Axis axis(pa.vect().unit());
LorentzRotation rot;
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
if ( sinth > 1.e-9 )
rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot.rotateX(Constants::pi);
rot.boostZ( pa.e()/pa.vect().mag());
Lorentz5Momentum ptemp=rot*pbeam;
Boost trans = -1./ptemp.e()*ptemp.vect();
trans.setZ(0.);
if ( trans.mag2() - 1. >= 0. ) throw KinematicsReconstructionVeto();
rot.boost(trans);
pa *=rot;
// project and calculate rescaling
// reference vectors
Lorentz5Momentum n1(ZERO,ZERO,-pa.z(),-pa.z());
Lorentz5Momentum n2(ZERO,ZERO, pa.z(),-pa.z());
Energy2 n1n2 = n1*n2;
// decompose the momenta
Lorentz5Momentum qbp=rot*pin[1],qcp=rot*pout[1];
qbp.rescaleMass();
qcp.rescaleMass();
double a[2],b[2];
a[0] = n2*qbp/n1n2;
b[0] = n1*qbp/n1n2;
Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2;
b[1] = 0.5;
a[1] = 0.5*(qcp.m2()-qperp.m2())/n1n2/b[1];
double kb;
if(a[0]!=0.) {
double A(0.5*a[0]),B(b[0]*a[0]-a[1]*b[1]-0.25),C(-0.5*b[0]);
if(sqr(B)-4.*A*C<0.) throw KinematicsReconstructionVeto();
kb = 0.5*(-B+sqrt(sqr(B)-4.*A*C))/A;
}
else {
kb = 0.5*b[0]/(b[0]*a[0]-a[1]*b[1]-0.25);
}
// changed to improve stability
if(kb==0.) throw KinematicsReconstructionVeto();
if ( a[1]>b[1] && abs(a[1]) < 1e-12 )
throw KinematicsReconstructionVeto();
if ( a[1]<=b[1] && abs(0.5+b[0]/kb) < 1e-12 )
throw KinematicsReconstructionVeto();
double kc = (a[1]>b[1]) ? (a[0]*kb-0.5)/a[1] : b[1]/(0.5+b[0]/kb);
if(kc==0.) throw KinematicsReconstructionVeto();
Lorentz5Momentum pnew[2] = { a[0]*kb*n1+b[0]/kb*n2+qperp,
a[1]*kc*n1+b[1]/kc*n2+qperp};
LorentzRotation rotinv=rot.inverse();
for(unsigned int ix=0;ix<jets.size();++ix) {
if(jets[ix]->progenitor()->isFinalState()) {
deepTransform(jets[ix]->progenitor(),rot);
deepTransform(jets[ix]->progenitor(),solveBoost(pnew[1],qcp));
Energy delta = jets[ix]->progenitor()->momentum().m()-jets[ix]->progenitor()->momentum().mass();
if ( abs(delta) > MeV ) throw KinematicsReconstructionVeto();
deepTransform(jets[ix]->progenitor(),rotinv);
}
else {
tPPtr parent;
boostChain(jets[ix]->progenitor(),rot,parent);
boostChain(jets[ix]->progenitor(),solveBoostZ(pnew[0],qbp),parent);
// check the first boost worked, and if not apply small correction to
// fix energy/momentum conservation
// this is a kludge but it reduces momentum non-conservation dramatically
Lorentz5Momentum pdiff = pnew[0]-jets[ix]->progenitor()->momentum();
Energy2 delta = sqr(pdiff.x())+sqr(pdiff.y())+sqr(pdiff.z())+sqr(pdiff.t());
unsigned int ntry=0;
while(delta>1e-6*GeV2 && ntry<5 ) {
ntry +=1;
boostChain(jets[ix]->progenitor(),solveBoostZ(pnew[0],jets[ix]->progenitor()->momentum()),parent);
pdiff = pnew[0]-jets[ix]->progenitor()->momentum();
delta = sqr(pdiff.x())+sqr(pdiff.y())+sqr(pdiff.z())+sqr(pdiff.t());
}
// apply test in breit-frame
Lorentz5Momentum ptest1 = parent->momentum();
Lorentz5Momentum ptest2 = rot*pbeam;
if(ptest1.z()/ptest2.z()<0. || ptest1.z()/ptest2.z()>1.)
throw KinematicsReconstructionVeto();
boostChain(jets[ix]->progenitor(),rotinv,parent);
}
}
}
bool QTildeReconstructor::addIntrinsicPt(vector<ShowerProgenitorPtr> jets) const {
bool added=false;
// add the intrinsic pt if needed
for(unsigned int ix=0;ix<jets.size();++ix) {
// only for initial-state particles which haven't radiated
if(jets[ix]->progenitor()->isFinalState()||
jets[ix]->hasEmitted()||
jets[ix]->reconstructed()==ShowerProgenitor::dontReconstruct) continue;
if(_intrinsic.find(jets[ix])==_intrinsic.end()) continue;
pair<Energy,double> pt=_intrinsic[jets[ix]];
Energy etemp = jets[ix]->original()->parents()[0]->momentum().z();
Lorentz5Momentum
p_basis(ZERO, ZERO, etemp, abs(etemp)),
n_basis(ZERO, ZERO,-etemp, abs(etemp));
double alpha = jets[ix]->progenitor()->x();
double beta = 0.5*(sqr(jets[ix]->progenitor()->data().mass())+
sqr(pt.first))/alpha/(p_basis*n_basis);
Lorentz5Momentum pnew=alpha*p_basis+beta*n_basis;
pnew.setX(pt.first*cos(pt.second));
pnew.setY(pt.first*sin(pt.second));
pnew.rescaleMass();
jets[ix]->progenitor()->set5Momentum(pnew);
added = true;
}
return added;
}
namespace {
double defaultSolveBoostGamma(const double & betam,const Energy2 & kps,
const Energy2 & qs, const Energy2 & Q2,
const Energy & kp,
const Energy & q, const Energy & qE) {
if(betam<0.5) {
return 1./sqrt(1.-sqr(betam));
}
else {
return ( kps+ qs + Q2)/
sqrt(2.*kps*qs + kps*Q2 + qs*Q2 + sqr(Q2) + 2.*q*qE*kp*sqrt(kps + Q2));
}
}
}
LorentzRotation QTildeReconstructor::
solveBoost(const double k, const Lorentz5Momentum & newq,
const Lorentz5Momentum & oldp ) const {
Energy q = newq.vect().mag();
Energy2 qs = sqr(q);
Energy2 Q2 = newq.mass2();
Energy kp = k*(oldp.vect().mag());
Energy2 kps = sqr(kp);
double betam = (q*newq.e() - kp*sqrt(kps + Q2))/(kps + qs + Q2);
if ( abs(betam) - 1. >= 0. ) throw KinematicsReconstructionVeto();
Boost beta = -betam*(k/kp)*oldp.vect();
double gamma = 0.;
if(Q2/sqr(oldp.e())>1e-4) {
gamma = defaultSolveBoostGamma(betam,kps,qs,Q2,kp,q,newq.e());
}
else {
if(k>0) {
gamma = 4.*kps*qs/sqr(kps +qs) + 2.*sqr(kps-qs)*Q2/pow<3,1>(kps +qs)
- 0.25*( sqr(kps) + 14.*kps*qs + sqr(qs))*sqr(kps-qs)/(pow<4,1>(kps +qs)*kps*qs)*sqr(Q2);
}
else {
gamma = 0.25*sqr(Q2)/(kps*qs)*(1. - 0.5*(kps+qs)/(kps*qs)*Q2);
}
if(gamma<=0.) throw KinematicsReconstructionVeto();
gamma = 1./sqrt(gamma);
if(gamma>2.) gamma = defaultSolveBoostGamma(betam,kps,qs,Q2,kp,q,newq.e());
}
// note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper.
ThreeVector<Energy2> ax = newq.vect().cross( oldp.vect() );
double delta;
if (newq.x()*oldp.x()+newq.y()*oldp.y()+newq.z()*oldp.z()< 1e-16*GeV2) {
throw KinematicsReconstructionVeto();
}else{
delta = newq.vect().angle( oldp.vect() );
}
LorentzRotation R;
using Constants::pi;
Energy2 scale1 = sqr(newq.x())+ sqr(newq.y())+sqr(newq.z());
Energy2 scale2 = sqr(oldp.x())+ sqr(oldp.y())+sqr(oldp.z());
if ( ax.mag2()/scale1/scale2 > 1e-28 ) {
R.rotate( delta, unitVector(ax) ).boost( beta , gamma );
}
else if(abs(delta-pi)/pi < 0.001) {
double phi=2.*pi*UseRandom::rnd();
Axis axis(cos(phi),sin(phi),0.);
axis.rotateUz(newq.vect().unit());
R.rotate(delta,axis).boost( beta , gamma );
}
else {
R.boost( beta , gamma );
}
return R;
}
LorentzRotation QTildeReconstructor::solveBoost(const Lorentz5Momentum & q,
const Lorentz5Momentum & p ) const {
Energy modp = p.vect().mag();
Energy modq = q.vect().mag();
double betam = (p.e()*modp-q.e()*modq)/(sqr(modq)+sqr(modp)+p.mass2());
if ( abs(betam)-1. >= 0. ) throw KinematicsReconstructionVeto();
Boost beta = -betam*q.vect().unit();
ThreeVector<Energy2> ax = p.vect().cross( q.vect() );
double delta = p.vect().angle( q.vect() );
LorentzRotation R;
using Constants::pi;
if ( beta.mag2() - 1. >= 0. ) throw KinematicsReconstructionVeto();
if ( ax.mag2()/GeV2/MeV2 > 1e-16 ) {
R.rotate( delta, unitVector(ax) ).boost( beta );
}
else {
R.boost( beta );
}
return R;
}
LorentzRotation QTildeReconstructor::solveBoostZ(const Lorentz5Momentum & q,
const Lorentz5Momentum & p ) const {
static const double eps = 1e-6;
LorentzRotation R;
double beta;
Energy2 mt2 = p.mass()<ZERO ? -sqr(p.mass())+sqr(p.x())+sqr(p.y()) : sqr(p.mass())+sqr(p.x())+sqr(p.y()) ;
double ratio = mt2/(sqr(p.t())+sqr(q.t()));
if(abs(ratio)>eps) {
double erat = (q.t()+q.z())/(p.t()+p.z());
Energy2 den = mt2*(erat+1./erat);
Energy2 num = (q.z()-p.z())*(q.t()+p.t()) + (p.z()+q.z())*(p.t()-q.t());
beta = num/den;
if ( abs(beta) - 1. >= 0. ) throw KinematicsReconstructionVeto();
R.boostZ(beta);
}
else {
double er = sqr(p.t()/q.t());
double x = ratio+0.125*(er+10.+1./er)*sqr(ratio);
beta = -(p.t()-q.t())*(p.t()+q.t())/(sqr(p.t())+sqr(q.t()))*(1.+x);
double gamma = (4.*sqr(p.t()*q.t()) +sqr(p.t()-q.t())*sqr(p.t()+q.t())*
(-2.*x+sqr(x)))/sqr(sqr(p.t())+sqr(q.t()));
if ( abs(beta) - 1. >= 0. ) throw KinematicsReconstructionVeto();
gamma = 1./sqrt(gamma);
R.boost(0.,0.,beta,gamma);
}
Lorentz5Momentum ptest = R*p;
if(ptest.z()/q.z() < 0. || ptest.t()/q.t() < 0. ) {
throw KinematicsReconstructionVeto();
}
return R;
}
void QTildeReconstructor::
reconstructFinalStateSystem(bool applyBoost,
const LorentzRotation & toRest,
const LorentzRotation & fromRest,
vector<ShowerProgenitorPtr> jets) const {
LorentzRotation trans = applyBoost? toRest : LorentzRotation();
// special for case of individual particle
if(jets.size()==1) {
deepTransform(jets[0]->progenitor(),trans);
deepTransform(jets[0]->progenitor(),fromRest);
return;
}
bool radiated(false);
// find the hard process centre-of-mass energy
Lorentz5Momentum pcm;
// check if radiated and calculate total momentum
for(unsigned int ix=0;ix<jets.size();++ix) {
radiated |=jets[ix]->hasEmitted();
pcm += jets[ix]->progenitor()->momentum();
}
if(applyBoost) pcm *= trans;
// check if in CMF frame
Boost beta_cm = pcm.findBoostToCM();
bool gottaBoost(false);
if(beta_cm.mag() > 1e-12) {
gottaBoost = true;
trans.boost(beta_cm);
}
// collection of pointers to initial hard particle and jet momenta
// for final boosts
JetKinVect jetKinematics;
vector<ShowerProgenitorPtr>::const_iterator cit;
for(cit = jets.begin(); cit != jets.end(); cit++) {
JetKinStruct tempJetKin;
tempJetKin.parent = (*cit)->progenitor();
if(applyBoost || gottaBoost) {
deepTransform(tempJetKin.parent,trans);
}
tempJetKin.p = (*cit)->progenitor()->momentum();
_progenitor=tempJetKin.parent;
if((**cit).reconstructed()==ShowerProgenitor::notReconstructed) {
radiated |= reconstructTimeLikeJet((*cit)->progenitor());
(**cit).reconstructed(ShowerProgenitor::done);
}
else {
radiated |= !(*cit)->progenitor()->children().empty();
}
tempJetKin.q = (*cit)->progenitor()->momentum();
jetKinematics.push_back(tempJetKin);
}
// default option rescale everything with the same factor
if( _finalStateReconOption == 0 || jetKinematics.size() <= 2 ) {
// find the rescaling factor
double k = 0.0;
if(radiated) {
k = solveKfactor(pcm.m(), jetKinematics);
// perform the rescaling and boosts
for(JetKinVect::iterator it = jetKinematics.begin();
it != jetKinematics.end(); ++it) {
LorentzRotation Trafo = solveBoost(k, it->q, it->p);
deepTransform(it->parent,Trafo);
}
}
}
// different treatment of most off-shell
else if ( _finalStateReconOption <= 4 ) {
// sort the jets by virtuality
std::sort(jetKinematics.begin(),jetKinematics.end(),JetOrdering());
// Bryan's procedures from FORTRAN
if( _finalStateReconOption <=2 ) {
// loop over the off-shell partons, _finalStateReconOption==1 only first ==2 all
JetKinVect::const_iterator jend = _finalStateReconOption==1 ? jetKinematics.begin()+1 : jetKinematics.end();
for(JetKinVect::const_iterator jit=jetKinematics.begin(); jit!=jend;++jit) {
// calculate the 4-momentum of the recoiling system
Lorentz5Momentum psum;
bool done = true;
for(JetKinVect::const_iterator it=jetKinematics.begin();it!=jetKinematics.end();++it) {
if(it==jit) {
done = false;
continue;
}
// first option put on-shell and sum 4-momenta
if( _finalStateReconOption == 1 ) {
LorentzRotation Trafo = solveBoost(1., it->q, it->p);
deepTransform(it->parent,Trafo);
psum += it->parent->momentum();
}
// second option, sum momenta
else {
// already rescaled
if(done) psum += it->parent->momentum();
// still needs to be rescaled
else psum += it->p;
}
}
// set the mass
psum.rescaleMass();
// calculate the 3-momentum rescaling factor
Energy2 s(pcm.m2());
Energy2 m1sq(jit->q.m2()),m2sq(psum.m2());
Energy4 num = sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq;
if(num<ZERO) throw KinematicsReconstructionVeto();
double k = sqrt( num / (4.*s*jit->p.vect().mag2()) );
// boost the off-shell parton
LorentzRotation B1 = solveBoost(k, jit->q, jit->p);
deepTransform(jit->parent,B1);
// boost everything else to rescale
LorentzRotation B2 = solveBoost(k, psum, psum);
for(JetKinVect::iterator it=jetKinematics.begin();it!=jetKinematics.end();++it) {
if(it==jit) continue;
deepTransform(it->parent,B2);
it->p *= B2;
it->q *= B2;
}
}
}
// Peter's C++ procedures
else {
reconstructFinalFinalOffShell(jetKinematics,pcm.m2(), _finalStateReconOption == 4);
}
}
else
assert(false);
// apply the final boosts
if(gottaBoost || applyBoost) {
LorentzRotation finalBoosts;
if(gottaBoost) finalBoosts.boost(-beta_cm);
if(applyBoost) finalBoosts.transform(fromRest);
for(JetKinVect::iterator it = jetKinematics.begin();
it != jetKinematics.end(); ++it) {
deepTransform(it->parent,finalBoosts);
}
}
}
void QTildeReconstructor::
reconstructInitialInitialSystem(bool & applyBoost,
LorentzRotation & toRest,
LorentzRotation & fromRest,
vector<ShowerProgenitorPtr> jets) const {
bool radiated = false;
Lorentz5Momentum pcm;
// check whether particles radiated and calculate total momentum
for( unsigned int ix = 0; ix < jets.size(); ++ix ) {
radiated |= jets[ix]->hasEmitted();
pcm += jets[ix]->progenitor()->momentum();
if(jets[ix]->original()->parents().empty()) return;
}
pcm.rescaleMass();
// check if intrinsic pt to be added
radiated |= !_intrinsic.empty();
// if no radiation return
if(!radiated) {
for(unsigned int ix=0;ix<jets.size();++ix) {
if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed)
jets[ix]->reconstructed(ShowerProgenitor::done);
}
return;
}
// initial state shuffling
applyBoost=false;
vector<Lorentz5Momentum> p, pq, p_in;
vector<Energy> pts;
for(unsigned int ix=0;ix<jets.size();++ix) {
// add momentum to vector
p_in.push_back(jets[ix]->progenitor()->momentum());
// reconstruct the jet
if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) {
radiated |= reconstructSpaceLikeJet(jets[ix]->progenitor());
jets[ix]->reconstructed(ShowerProgenitor::done);
}
assert(!jets[ix]->original()->parents().empty());
Energy etemp = jets[ix]->original()->parents()[0]->momentum().z();
Lorentz5Momentum ptemp = Lorentz5Momentum(ZERO, ZERO, etemp, abs(etemp));
pq.push_back(ptemp);
pts.push_back(jets[ix]->highestpT());
}
// add the intrinsic pt if needed
radiated |=addIntrinsicPt(jets);
for(unsigned int ix=0;ix<jets.size();++ix) {
p.push_back(jets[ix]->progenitor()->momentum());
}
double x1 = p_in[0].z()/pq[0].z();
double x2 = p_in[1].z()/pq[1].z();
vector<double> beta=initialStateRescaling(x1,x2,p_in[0]+p_in[1],p,pq,pts);
// if not need don't apply boosts
if(!(radiated && p.size() == 2 && pq.size() == 2)) return;
applyBoost=true;
// apply the boosts
Lorentz5Momentum newcmf;
for(unsigned int ix=0;ix<jets.size();++ix) {
tPPtr toBoost = jets[ix]->progenitor();
Boost betaboost(0, 0, beta[ix]);
tPPtr parent;
boostChain(toBoost, LorentzRotation(0.,0.,beta[ix]),parent);
if(parent->momentum().e()/pq[ix].e()>1.||
parent->momentum().z()/pq[ix].z()>1.) throw KinematicsReconstructionVeto();
newcmf+=toBoost->momentum();
}
if(newcmf.m()<ZERO||newcmf.e()<ZERO) throw KinematicsReconstructionVeto();
findInitialBoost(pcm,newcmf,toRest,fromRest);
}
void QTildeReconstructor::
deconstructInitialInitialSystem(bool & applyBoost,
LorentzRotation & toRest,
LorentzRotation & fromRest,
HardTreePtr tree,
vector<HardBranchingPtr> jets,
ShowerInteraction) const {
assert(jets.size()==2);
// put beam with +z first
if(jets[0]->beam()->momentum().z()<ZERO) swap(jets[0],jets[1]);
// get the momenta of the particles
vector<Lorentz5Momentum> pin,pq;
for(unsigned int ix=0;ix<jets.size();++ix) {
pin.push_back(jets[ix]->branchingParticle()->momentum());
Energy etemp = jets[ix]->beam()->momentum().z();
pq.push_back(Lorentz5Momentum(ZERO, ZERO,etemp, abs(etemp)));
}
// calculate the rescaling
double x[2];
Lorentz5Momentum pcm=pin[0]+pin[1];
assert(pcm.mass2()>ZERO);
pcm.rescaleMass();
vector<double> boost = inverseInitialStateRescaling(x[0],x[1],pcm,pin,pq);
set<HardBranchingPtr>::const_iterator cjt=tree->incoming().begin();
HardBranchingPtr incoming[2];
incoming[0] = *cjt;
++cjt;
incoming[1] = *cjt;
if((*tree->incoming().begin())->beam()->momentum().z()/pq[0].z()<0.)
swap(incoming[0],incoming[1]);
// apply the boost the the particles
unsigned int iswap[2]={1,0};
for(unsigned int ix=0;ix<2;++ix) {
LorentzRotation R(0.,0.,-boost[ix]);
incoming[ix]->pVector(pq[ix]);
incoming[ix]->nVector(pq[iswap[ix]]);
incoming[ix]->setMomenta(R,1.,Lorentz5Momentum());
jets[ix]->showerMomentum(x[ix]*jets[ix]->pVector());
}
// and calculate the boosts
applyBoost=true;
// do one boost
if(_initialBoost==0) {
toRest = LorentzRotation(-pcm.boostVector());
}
else if(_initialBoost==1) {
// first the transverse boost
Energy pT = sqrt(sqr(pcm.x())+sqr(pcm.y()));
double beta = -pT/pcm.t();
toRest=LorentzRotation(Boost(beta*pcm.x()/pT,beta*pcm.y()/pT,0.));
// the longitudinal
beta = pcm.z()/sqrt(pcm.m2()+sqr(pcm.z()));
toRest.boost(Boost(0.,0.,-beta));
}
else
assert(false);
fromRest = LorentzRotation((jets[0]->showerMomentum()+
jets[1]->showerMomentum()).boostVector());
}
void QTildeReconstructor::
deconstructFinalStateSystem(const LorentzRotation & toRest,
const LorentzRotation & fromRest,
HardTreePtr tree, vector<HardBranchingPtr> jets,
ShowerInteraction type) const {
LorentzRotation trans = toRest;
if(jets.size()==1) {
Lorentz5Momentum pnew = toRest*(jets[0]->branchingParticle()->momentum());
pnew *= fromRest;
jets[0]-> original(pnew);
jets[0]->showerMomentum(pnew);
// find the colour partners
ShowerParticleVector particles;
vector<Lorentz5Momentum> ptemp;
set<HardBranchingPtr>::const_iterator cjt;
for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) {
ptemp.push_back((**cjt).branchingParticle()->momentum());
(**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum());
particles.push_back((**cjt).branchingParticle());
}
dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->showerModel()->partnerFinder()
->setInitialEvolutionScales(particles,false,type,false);
// calculate the reference vectors
unsigned int iloc(0);
set<HardBranchingPtr>::iterator clt;
for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) {
// reset the momentum
(**cjt).branchingParticle()->set5Momentum(ptemp[iloc]);
++iloc;
// sort out the partners
tShowerParticlePtr partner =
(*cjt)->branchingParticle()->partner();
if(!partner) continue;
for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) {
if((**clt).branchingParticle()==partner) {
(**cjt).colourPartner(*clt);
break;
}
}
tHardBranchingPtr branch;
for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) {
if(clt==cjt) continue;
if((*clt)->branchingParticle()==partner) {
branch=*clt;
break;
}
}
}
return;
}
vector<HardBranchingPtr>::iterator cit;
vector<Lorentz5Momentum> pout;
vector<Energy> mon;
Lorentz5Momentum pin;
for(cit=jets.begin();cit!=jets.end();++cit) {
pout.push_back((*cit)->branchingParticle()->momentum());
mon.push_back(findMass(*cit));
pin+=pout.back();
}
// boost all the momenta to the rest frame of the decaying particle
pin.rescaleMass();
pin *=trans;
Boost beta_cm = pin.findBoostToCM();
bool gottaBoost(false);
if(beta_cm.mag() > 1e-12) {
gottaBoost = true;
trans.boost(beta_cm);
pin.boost(beta_cm);
}
for(unsigned int ix=0;ix<pout.size();++ix) {
pout[ix].transform(trans);
}
// rescaling factor
double lambda=inverseRescalingFactor(pout,mon,pin.mass());
if (lambda< 1.e-10) throw KinematicsReconstructionVeto();
// now calculate the p reference vectors
for(unsigned int ix=0;ix<jets.size();++ix) {
Lorentz5Momentum pvect = jets[ix]->branchingParticle()->momentum();
pvect.transform(trans);
pvect /= lambda;
pvect.setMass(mon[ix]);
pvect.rescaleEnergy();
if(gottaBoost) pvect.boost(-beta_cm);
pvect.transform(fromRest);
jets[ix]->pVector(pvect);
jets[ix]->showerMomentum(pvect);
}
// find the colour partners
ShowerParticleVector particles;
vector<Lorentz5Momentum> ptemp;
set<HardBranchingPtr>::const_iterator cjt;
for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) {
ptemp.push_back((**cjt).branchingParticle()->momentum());
(**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum());
particles.push_back((**cjt).branchingParticle());
}
dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->showerModel()->partnerFinder()
->setInitialEvolutionScales(particles,false,type,false);
// calculate the reference vectors
unsigned int iloc(0);
set<HardBranchingPtr>::iterator clt;
for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) {
// reset the momentum
(**cjt).branchingParticle()->set5Momentum(ptemp[iloc]);
++iloc;
}
for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) {
// sort out the partners
tShowerParticlePtr partner =
(*cjt)->branchingParticle()->partner();
if(!partner) continue;
for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) {
if((**clt).branchingParticle()==partner) {
(**cjt).colourPartner(*clt);
break;
}
}
tHardBranchingPtr branch;
for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) {
if(clt==cjt) continue;
if((*clt)->branchingParticle()==partner) {
branch=*clt;
break;
}
}
// compute the reference vectors
// both incoming, should all ready be done
if((**cjt).status()==HardBranching::Incoming &&
(**clt).status()==HardBranching::Incoming) {
continue;
}
// both outgoing
else if((**cjt).status()!=HardBranching::Incoming&&
branch->status()==HardBranching::Outgoing) {
Boost boost=((*cjt)->pVector()+branch->pVector()).findBoostToCM();
Lorentz5Momentum pcm = branch->pVector();
pcm.boost(boost);
Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect());
nvect.boost( -boost);
(**cjt).nVector(nvect);
}
else if((**cjt).status()==HardBranching::Incoming) {
Lorentz5Momentum pa = -(**cjt).showerMomentum()+branch->showerMomentum();
Lorentz5Momentum pb = (**cjt).showerMomentum();
Axis axis(pa.vect().unit());
LorentzRotation rot;
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot.rotateX(Constants::pi);
rot.boostZ( pa.e()/pa.vect().mag());
pb*=rot;
Boost trans = -1./pb.e()*pb.vect();
trans.setZ(0.);
rot.boost(trans);
Energy scale=(**cjt).beam()->momentum().e();
Lorentz5Momentum pbasis(ZERO,(**cjt).beam()->momentum().vect().unit()*scale);
Lorentz5Momentum pcm = rot*pbasis;
rot.invert();
(**cjt).nVector(rot*Lorentz5Momentum(ZERO,-pcm.vect()));
tHardBranchingPtr branch2 = *cjt;;
while (branch2->parent()) {
branch2=branch2->parent();
branch2->nVector(rot*Lorentz5Momentum(ZERO,-pcm.vect()));
}
}
else if(branch->status()==HardBranching::Incoming) {
(**cjt).nVector(Lorentz5Momentum(ZERO,branch->showerMomentum().vect()));
}
}
// now compute the new momenta
for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) {
if(!(*cjt)->branchingParticle()->isFinalState()) continue;
Lorentz5Momentum qnew;
if((*cjt)->branchingParticle()->partner()) {
Energy2 dot=(*cjt)->pVector()*(*cjt)->nVector();
double beta = 0.5*((*cjt)->branchingParticle()->momentum().m2()
-sqr((*cjt)->pVector().mass()))/dot;
qnew=(*cjt)->pVector()+beta*(*cjt)->nVector();
qnew.rescaleMass();
}
else {
qnew = (*cjt)->pVector();
}
// qnew is the unshuffled momentum in the rest frame of the p basis vectors,
// for the simple case Z->q qbar g this was checked against analytic formulae.
// compute the boost
LorentzRotation R=solveBoost(qnew,
toRest*(*cjt)->branchingParticle()->momentum())*toRest;
(*cjt)->setMomenta(R,1.0,Lorentz5Momentum());
}
}
Energy QTildeReconstructor::momConsEq(double k,
const Energy & root_s,
const JetKinVect & jets) const {
static const Energy2 eps=1e-8*GeV2;
Energy dum = ZERO;
for(JetKinVect::const_iterator it = jets.begin(); it != jets.end(); ++it) {
Energy2 dum2 = (it->q).m2() + sqr(k)*(it->p).vect().mag2();
if(dum2 < ZERO) {
if(dum2 < -eps) throw KinematicsReconstructionVeto();
dum2 = ZERO;
}
dum += sqrt(dum2);
}
return dum - root_s;
}
void QTildeReconstructor::boostChain(tPPtr p, const LorentzRotation &bv,
tPPtr & parent) const {
if(!p->parents().empty()) boostChain(p->parents()[0], bv,parent);
else parent=p;
p->transform(bv);
if(p->children().size()==2) {
if(dynamic_ptr_cast<ShowerParticlePtr>(p->children()[1]))
deepTransform(p->children()[1],bv);
}
}
namespace {
bool sortJets(ShowerProgenitorPtr j1, ShowerProgenitorPtr j2) {
return j1->highestpT()>j2->highestpT();
}
}
void QTildeReconstructor::
reconstructGeneralSystem(vector<ShowerProgenitorPtr> & ShowerHardJets) const {
// find initial- and final-state systems
ColourSingletSystem in,out;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
if(ShowerHardJets[ix]->progenitor()->isFinalState())
out.jets.push_back(ShowerHardJets[ix]);
else
in.jets.push_back(ShowerHardJets[ix]);
}
// reconstruct initial-initial system
LorentzRotation toRest,fromRest;
bool applyBoost(false);
// reconstruct initial-initial system
reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets);
// reconstruct the final-state systems
reconstructFinalStateSystem(applyBoost,toRest,fromRest,out.jets);
}
void QTildeReconstructor::
reconstructFinalFirst(vector<ShowerProgenitorPtr> & ShowerHardJets) const {
static const Energy2 minQ2 = 1e-4*GeV2;
map<ShowerProgenitorPtr,bool> used;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
used[ShowerHardJets[ix]] = false;
} // first to the final-state reconstruction of any systems which need it
set<ShowerProgenitorPtr> outgoing;
// first find any particles with final state partners
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
if(ShowerHardJets[ix]->progenitor()->isFinalState()&&
ShowerHardJets[ix]->progenitor()->partner()&&
ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) outgoing.insert(ShowerHardJets[ix]);
}
// then find the colour partners
if(!outgoing.empty()) {
set<ShowerProgenitorPtr> partners;
for(set<ShowerProgenitorPtr>::const_iterator it=outgoing.begin();it!=outgoing.end();++it) {
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
if((**it).progenitor()->partner()==ShowerHardJets[ix]->progenitor()) {
partners.insert(ShowerHardJets[ix]);
break;
}
}
}
outgoing.insert(partners.begin(),partners.end());
}
// do the final-state reconstruction if needed
if(!outgoing.empty()) {
assert(outgoing.size()!=1);
LorentzRotation toRest,fromRest;
vector<ShowerProgenitorPtr> outgoingJets(outgoing.begin(),outgoing.end());
reconstructFinalStateSystem(false,toRest,fromRest,outgoingJets);
}
// Now do any initial-final systems which are needed
vector<ColourSingletSystem> IFSystems;
// find the systems N.B. can have duplicates
// find initial-state with FS partners or FS with IS partners
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
if(!ShowerHardJets[ix]->progenitor()->isFinalState()&&
ShowerHardJets[ix]->progenitor()->partner()&&
ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) {
IFSystems.push_back(ColourSingletSystem(IF,ShowerHardJets[ix]));
}
else if(ShowerHardJets[ix]->progenitor()->isFinalState()&&
ShowerHardJets[ix]->progenitor()->partner()&&
!ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) {
IFSystems.push_back(ColourSingletSystem(IF,ShowerHardJets[ix]));
}
}
// then add the partners
for(unsigned int is=0;is<IFSystems.size();++is) {
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
if(IFSystems[is].jets[0]->progenitor()->partner()==ShowerHardJets[ix]->progenitor()) {
IFSystems[is].jets.push_back(ShowerHardJets[ix]);
}
}
// ensure incoming first
if(IFSystems[is].jets[0]->progenitor()->isFinalState())
swap(IFSystems[is].jets[0],IFSystems[is].jets[1]);
}
if(!IFSystems.empty()) {
unsigned int istart = UseRandom::irnd(IFSystems.size());
unsigned int istop=IFSystems.size();
for(unsigned int is=istart;is<=istop;++is) {
if(is==IFSystems.size()) {
if(istart!=0) {
istop = istart-1;
is=0;
}
else break;
}
// skip duplicates
if(used[IFSystems[is].jets[0]] &&
used[IFSystems[is].jets[1]] ) continue;
if(IFSystems[is].jets[0]->original()&&IFSystems[is].jets[0]->original()->parents().empty()) continue;
Lorentz5Momentum psum;
for(unsigned int ix=0;ix<IFSystems[is].jets.size();++ix) {
if(IFSystems[is].jets[ix]->progenitor()->isFinalState())
psum += IFSystems[is].jets[ix]->progenitor()->momentum();
else
psum -= IFSystems[is].jets[ix]->progenitor()->momentum();
}
if(-psum.m2()>minQ2) {
reconstructInitialFinalSystem(IFSystems[is].jets);
for(unsigned int ix=0;ix<IFSystems[is].jets.size();++ix) {
used[IFSystems[is].jets[ix]] = true;
}
}
}
}
// now we finally need to handle the initial state system
ColourSingletSystem in,out;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
if(ShowerHardJets[ix]->progenitor()->isFinalState())
out.jets.push_back(ShowerHardJets[ix]);
else
in.jets.push_back(ShowerHardJets[ix]);
}
// reconstruct initial-initial system
bool doRecon = false;
for(unsigned int ix=0;ix<in.jets.size();++ix) {
if(!used[in.jets[ix]]) {
doRecon = true;
break;
}
}
LorentzRotation toRest,fromRest;
bool applyBoost(false);
if(doRecon) {
reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets);
}
// reconstruct the final-state systems
if(!doRecon) {
for(unsigned int ix=0;ix<out.jets.size();++ix) {
if(!used[out.jets[ix]]) {
doRecon = true;
break;
}
}
}
if(doRecon) {
reconstructFinalStateSystem(applyBoost,toRest,fromRest,out.jets);
}
}
void QTildeReconstructor::
reconstructColourPartner(vector<ShowerProgenitorPtr> & ShowerHardJets) const {
static const Energy2 minQ2 = 1e-4*GeV2;
// sort the vector by hardness of emission
std::sort(ShowerHardJets.begin(),ShowerHardJets.end(),sortJets);
// map between particles and progenitors for easy lookup
map<ShowerParticlePtr,ShowerProgenitorPtr> progenitorMap;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
progenitorMap[ShowerHardJets[ix]->progenitor()] = ShowerHardJets[ix];
}
// check that the IF systems can be reconstructed
bool canReconstruct = true;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
tShowerParticlePtr progenitor = ShowerHardJets[ix]->progenitor();
tShowerParticlePtr partner = progenitor->partner();
if(!partner) continue;
else if((progenitor->isFinalState() &&
!partner->isFinalState()) ||
(!progenitor->isFinalState() &&
partner->isFinalState()) ) {
vector<ShowerProgenitorPtr> jets(2);
jets[0] = ShowerHardJets[ix];
jets[1] = progenitorMap[partner];
Lorentz5Momentum psum;
for(unsigned int iy=0;iy<jets.size();++iy) {
if(jets[iy]->progenitor()->isFinalState())
psum += jets[iy]->progenitor()->momentum();
else
psum -= jets[iy]->progenitor()->momentum();
}
if(-psum.m2()<minQ2) {
canReconstruct = false;
break;
}
}
}
if(!canReconstruct) {
reconstructGeneralSystem(ShowerHardJets);
return;
}
map<ShowerProgenitorPtr,bool> used;
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
used[ShowerHardJets[ix]] = false;
}
for(unsigned int ix=0;ix<ShowerHardJets.size();++ix) {
// skip jets which have already been handled
if(ShowerHardJets[ix]->reconstructed()==ShowerProgenitor::done) continue;
// already reconstructed
if(used[ShowerHardJets[ix]]) continue;
// no partner continue
tShowerParticlePtr progenitor = ShowerHardJets[ix]->progenitor();
tShowerParticlePtr partner = progenitor->partner();
if(!partner) {
// check if there's a daughter tree which also needs boosting
Lorentz5Momentum porig = progenitor->momentum();
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit;
for(tit = _currentTree->treelinks().begin();
tit != _currentTree->treelinks().end();++tit) {
// if there is, boost it
if(tit->second.first && tit->second.second==progenitor) {
Lorentz5Momentum pnew = tit->first->incomingLines().begin()
->first->progenitor()->momentum();
pnew *= tit->first->transform();
Lorentz5Momentum pdiff = porig-pnew;
Energy2 test = sqr(pdiff.x()) + sqr(pdiff.y()) +
sqr(pdiff.z()) + sqr(pdiff.t());
LorentzRotation rot;
if(test>1e-6*GeV2) rot = solveBoost(porig,pnew);
tit->first->transform(rot,false);
_treeBoosts[tit->first].push_back(rot);
}
}
ShowerHardJets[ix]->reconstructed(ShowerProgenitor::done);
continue;
}
// do the reconstruction
// final-final
if(progenitor->isFinalState() &&
partner->isFinalState() ) {
LorentzRotation toRest,fromRest;
vector<ShowerProgenitorPtr> jets(2);
jets[0] = ShowerHardJets[ix];
jets[1] = progenitorMap[partner];
if(_reconopt==4 && jets[1]->reconstructed()==ShowerProgenitor::notReconstructed)
jets[1]->reconstructed(ShowerProgenitor::dontReconstruct);
reconstructFinalStateSystem(false,toRest,fromRest,jets);
if(_reconopt==4 && jets[1]->reconstructed()==ShowerProgenitor::dontReconstruct)
jets[1]->reconstructed(ShowerProgenitor::notReconstructed);
used[jets[0]] = true;
if(_reconopt==3) used[jets[1]] = true;
}
// initial-final
else if((progenitor->isFinalState() &&
!partner->isFinalState()) ||
(!progenitor->isFinalState() &&
partner->isFinalState()) ) {
vector<ShowerProgenitorPtr> jets(2);
jets[0] = ShowerHardJets[ix];
jets[1] = progenitorMap[partner];
if(jets[0]->progenitor()->isFinalState()) swap(jets[0],jets[1]);
if(jets[0]->original()&&jets[0]->original()->parents().empty()) continue;
Lorentz5Momentum psum;
for(unsigned int iy=0;iy<jets.size();++iy) {
if(jets[iy]->progenitor()->isFinalState())
psum += jets[iy]->progenitor()->momentum();
else
psum -= jets[iy]->progenitor()->momentum();
}
if(_reconopt==4 && progenitorMap[partner]->reconstructed()==ShowerProgenitor::notReconstructed)
progenitorMap[partner]->reconstructed(ShowerProgenitor::dontReconstruct);
reconstructInitialFinalSystem(jets);
if(_reconopt==4 && progenitorMap[partner]->reconstructed()==ShowerProgenitor::dontReconstruct)
progenitorMap[partner]->reconstructed(ShowerProgenitor::notReconstructed);
used[ShowerHardJets[ix]] = true;
if(_reconopt==3) used[progenitorMap[partner]] = true;
}
// initial-initial
else if(!progenitor->isFinalState() &&
!partner->isFinalState() ) {
ColourSingletSystem in,out;
in.jets.push_back(ShowerHardJets[ix]);
in.jets.push_back(progenitorMap[partner]);
for(unsigned int iy=0;iy<ShowerHardJets.size();++iy) {
if(ShowerHardJets[iy]->progenitor()->isFinalState())
out.jets.push_back(ShowerHardJets[iy]);
}
LorentzRotation toRest,fromRest;
bool applyBoost(false);
if(_reconopt==4 && in.jets[1]->reconstructed()==ShowerProgenitor::notReconstructed)
in.jets[1]->reconstructed(ShowerProgenitor::dontReconstruct);
reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets);
if(_reconopt==4 && in.jets[1]->reconstructed()==ShowerProgenitor::dontReconstruct)
in.jets[1]->reconstructed(ShowerProgenitor::notReconstructed);
used[in.jets[0]] = true;
if(_reconopt==3) used[in.jets[1]] = true;
for(unsigned int iy=0;iy<out.jets.size();++iy) {
if(out.jets[iy]->reconstructed()==ShowerProgenitor::notReconstructed)
out.jets[iy]->reconstructed(ShowerProgenitor::dontReconstruct);
}
// reconstruct the final-state systems
LorentzRotation finalBoosts;
finalBoosts.transform( toRest);
finalBoosts.transform(fromRest);
for(unsigned int iy=0;iy<out.jets.size();++iy) {
deepTransform(out.jets[iy]->progenitor(),finalBoosts);
}
for(unsigned int iy=0;iy<out.jets.size();++iy) {
if(out.jets[iy]->reconstructed()==ShowerProgenitor::dontReconstruct)
out.jets[iy]->reconstructed(ShowerProgenitor::notReconstructed);
}
}
}
}
bool QTildeReconstructor::
inverseDecayRescalingFactor(vector<Lorentz5Momentum> pout,
vector<Energy> mon,Energy roots,
Lorentz5Momentum ppartner, Energy mbar,
double & k1, double & k2) const {
ThreeVector<Energy> qtotal;
vector<Energy2> pmag;
for(unsigned int ix=0;ix<pout.size();++ix) {
pmag.push_back(pout[ix].vect().mag2());
qtotal+=pout[ix].vect();
}
Energy2 dot1 = qtotal*ppartner.vect();
Energy2 qmag2=qtotal.mag2();
double a = -dot1/qmag2;
static const Energy eps=1e-10*GeV;
unsigned int itry(0);
Energy numer(ZERO),denom(ZERO);
k1=1.;
do {
++itry;
numer=denom=0.*GeV;
double k12=sqr(k1);
for(unsigned int ix=0;ix<pout.size();++ix) {
Energy en = sqrt(pmag[ix]/k12+sqr(mon[ix]));
numer += en;
denom += pmag[ix]/en;
}
Energy en = sqrt(qmag2/k12+sqr(mbar));
numer += en-roots;
denom += qmag2/en;
k1 += numer/denom*k12*k1;
if(abs(k1)>1e10) return false;
}
while (abs(numer)>eps&&itry<100);
k1 = abs(k1);
k2 = a*k1;
return itry<100;
}
void QTildeReconstructor::
deconstructInitialFinalSystem(HardTreePtr tree,vector<HardBranchingPtr> jets,
ShowerInteraction type) const {
HardBranchingPtr incoming;
Lorentz5Momentum pin[2],pout[2],pbeam;
HardBranchingPtr initial;
Energy mc(ZERO);
for(unsigned int ix=0;ix<jets.size();++ix) {
// final-state parton
if(jets[ix]->status()==HardBranching::Outgoing) {
pout[0] += jets[ix]->branchingParticle()->momentum();
mc = jets[ix]->branchingParticle()->thePEGBase() ?
jets[ix]->branchingParticle()->thePEGBase()->mass() :
jets[ix]->branchingParticle()->dataPtr()->mass();
}
// initial-state parton
else {
pin[0] += jets[ix]->branchingParticle()->momentum();
initial = jets[ix];
pbeam = jets[ix]->beam()->momentum();
Energy scale=pbeam.t();
pbeam = Lorentz5Momentum(ZERO,pbeam.vect().unit()*scale);
incoming = jets[ix];
while(incoming->parent()) incoming = incoming->parent();
}
}
if(jets.size()>2) {
pout[0].rescaleMass();
mc = pout[0].mass();
}
// work out the boost to the Breit frame
Lorentz5Momentum pa = pout[0]-pin[0];
Axis axis(pa.vect().unit());
LorentzRotation rot;
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
if(axis.perp2()>0.) {
rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot.rotateX(Constants::pi);
rot.boostZ( pa.e()/pa.vect().mag());
}
// transverse part
Lorentz5Momentum paxis=rot*pbeam;
Boost trans = -1./paxis.e()*paxis.vect();
trans.setZ(0.);
rot.boost(trans);
pa *= rot;
// reference vectors
Lorentz5Momentum n1(ZERO,ZERO,-pa.z(),-pa.z());
Lorentz5Momentum n2(ZERO,ZERO, pa.z(),-pa.z());
Energy2 n1n2 = n1*n2;
// decompose the momenta
Lorentz5Momentum qbp=rot*pin[0],qcp= rot*pout[0];
double a[2],b[2];
a[0] = n2*qbp/n1n2;
b[0] = n1*qbp/n1n2;
a[1] = n2*qcp/n1n2;
b[1] = n1*qcp/n1n2;
Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2;
// before reshuffling
Energy Q = abs(pa.z());
double c = sqr(mc/Q);
Lorentz5Momentum pb(ZERO,ZERO,0.5*Q*(1.+c),0.5*Q*(1.+c));
Lorentz5Momentum pc(ZERO,ZERO,0.5*Q*(c-1.),0.5*Q*(1.+c));
double anew[2],bnew[2];
anew[0] = pb*n2/n1n2;
bnew[0] = 0.5*(qbp.m2()-qperp.m2())/n1n2/anew[0];
bnew[1] = pc*n1/n1n2;
anew[1] = 0.5*qcp.m2()/bnew[1]/n1n2;
Lorentz5Momentum qnewb = (anew[0]*n1+bnew[0]*n2+qperp);
Lorentz5Momentum qnewc = (anew[1]*n1+bnew[1]*n2);
// initial-state boost
LorentzRotation rotinv=rot.inverse();
LorentzRotation transb=rotinv*solveBoostZ(qnewb,qbp)*rot;
// final-state boost
LorentzRotation transc=rotinv*solveBoost(qnewc,qcp)*rot;
// this will need changing for more than one outgoing particle
// set the pvectors
for(unsigned int ix=0;ix<jets.size();++ix) {
if(jets[ix]->status()==HardBranching::Incoming) {
jets[ix]->pVector(pbeam);
jets[ix]->showerMomentum(rotinv*pb);
incoming->pVector(jets[ix]->pVector());
}
else {
jets[ix]->pVector(rotinv*pc);
jets[ix]->showerMomentum(jets[ix]->pVector());
}
}
// find the colour partners
ShowerParticleVector particles;
vector<Lorentz5Momentum> ptemp;
set<HardBranchingPtr>::const_iterator cjt;
for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) {
ptemp.push_back((**cjt).branchingParticle()->momentum());
(**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum());
particles.push_back((**cjt).branchingParticle());
}
dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->showerModel()->partnerFinder()
->setInitialEvolutionScales(particles,false,type,false);
unsigned int iloc(0);
for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) {
// reset the momentum
(**cjt).branchingParticle()->set5Momentum(ptemp[iloc]);
++iloc;
}
for(vector<HardBranchingPtr>::const_iterator cjt=jets.begin();
cjt!=jets.end();++cjt) {
// sort out the partners
tShowerParticlePtr partner =
(*cjt)->branchingParticle()->partner();
if(!partner) continue;
tHardBranchingPtr branch;
for(set<HardBranchingPtr>::const_iterator
clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) {
if((**clt).branchingParticle()==partner) {
(**cjt).colourPartner(*clt);
branch=*clt;
break;
}
}
// compute the reference vectors
// both incoming, should all ready be done
if((**cjt).status()==HardBranching::Incoming &&
branch->status()==HardBranching::Incoming) {
Energy etemp = (*cjt)->beam()->momentum().z();
Lorentz5Momentum nvect(ZERO, ZERO,-etemp, abs(etemp));
tHardBranchingPtr branch2 = *cjt;
(**cjt).nVector(nvect);
while (branch2->parent()) {
branch2=branch2->parent();
branch2->nVector(nvect);
}
}
// both outgoing
else if((**cjt).status()==HardBranching::Outgoing&&
branch->status()==HardBranching::Outgoing) {
Boost boost=((*cjt)->pVector()+branch->pVector()).findBoostToCM();
Lorentz5Momentum pcm = branch->pVector();
pcm.boost(boost);
Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect());
nvect.boost( -boost);
(**cjt).nVector(nvect);
}
else if((**cjt).status()==HardBranching::Incoming) {
Lorentz5Momentum pa = -(**cjt).showerMomentum()+branch->showerMomentum();
Lorentz5Momentum pb = (**cjt).showerMomentum();
Axis axis(pa.vect().unit());
LorentzRotation rot;
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
if(axis.perp2()>1e-20) {
rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
rot.rotateX(Constants::pi);
}
if(abs(1.-pa.e()/pa.vect().mag())>1e-6) rot.boostZ( pa.e()/pa.vect().mag());
pb*=rot;
Boost trans = -1./pb.e()*pb.vect();
trans.setZ(0.);
rot.boost(trans);
Energy scale=(**cjt).beam()->momentum().t();
Lorentz5Momentum pbasis(ZERO,(**cjt).beam()->momentum().vect().unit()*scale);
Lorentz5Momentum pcm = rot*pbasis;
rot.invert();
Lorentz5Momentum nvect = rot*Lorentz5Momentum(ZERO,-pcm.vect());
(**cjt).nVector(nvect);
tHardBranchingPtr branch2 = *cjt;
while (branch2->parent()) {
branch2=branch2->parent();
branch2->nVector(nvect);
}
}
else if(branch->status()==HardBranching::Incoming) {
Lorentz5Momentum nvect=Lorentz5Momentum(ZERO,branch->showerMomentum().vect());
(**cjt).nVector(nvect);
}
}
// now compute the new momenta
for(vector<HardBranchingPtr>::const_iterator cjt=jets.begin();
cjt!=jets.end();++cjt) {
if((**cjt).status()==HardBranching::Outgoing) {
(**cjt).setMomenta(transc,1.,Lorentz5Momentum());
}
}
incoming->setMomenta(transb,1.,Lorentz5Momentum());
}
void QTildeReconstructor::deepTransform(PPtr particle,
const LorentzRotation & r,
bool match,
PPtr original) const {
if(_boosts.find(particle)!=_boosts.end()) {
_boosts[particle].push_back(r);
}
Lorentz5Momentum porig = particle->momentum();
if(!original) original = particle;
for ( int i = 0, N = particle->children().size(); i < N; ++i ) {
deepTransform(particle->children()[i],r,
particle->children()[i]->id()==original->id()&&match,original);
}
particle->transform(r);
// transform the p and n vectors
ShowerParticlePtr sparticle = dynamic_ptr_cast<ShowerParticlePtr>(particle);
if(sparticle && sparticle->showerBasis()) {
sparticle->showerBasis()->transform(r);
}
if ( particle->next() ) deepTransform(particle->next(),r,match,original);
if(!match) return;
if(!particle->children().empty()) return;
// force the mass shell
if(particle->dataPtr()->stable()) {
Lorentz5Momentum ptemp = particle->momentum();
ptemp.rescaleEnergy();
particle->set5Momentum(ptemp);
}
// check if there's a daughter tree which also needs boosting
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit;
for(tit = _currentTree->treelinks().begin();
tit != _currentTree->treelinks().end();++tit) {
// if there is, boost it
if(tit->second.first && tit->second.second==original) {
Lorentz5Momentum pnew = tit->first->incomingLines().begin()
->first->progenitor()->momentum();
pnew *= tit->first->transform();
Lorentz5Momentum pdiff = porig-pnew;
Energy2 test = sqr(pdiff.x()) + sqr(pdiff.y()) +
sqr(pdiff.z()) + sqr(pdiff.t());
LorentzRotation rot;
if(test>1e-6*GeV2) rot = solveBoost(porig,pnew);
tit->first->transform(r*rot,false);
_treeBoosts[tit->first].push_back(r*rot);
}
}
}
void QTildeReconstructor::reconstructFinalFinalOffShell(JetKinVect orderedJets,
Energy2 s,
bool recursive) const {
JetKinVect::iterator jit;
jit = orderedJets.begin(); ++jit;
// 4-momentum of recoiling system
Lorentz5Momentum psum;
for( ; jit!=orderedJets.end(); ++jit) psum += jit->p;
psum.rescaleMass();
// calculate the 3-momentum rescaling factor
Energy2 m1sq(orderedJets.begin()->q.m2()),m2sq(psum.m2());
Energy4 num = sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq;
if(num<ZERO) throw KinematicsReconstructionVeto();
double k = sqrt( num / (4.*s*orderedJets.begin()->p.vect().mag2()) );
// boost the most off-shell
LorentzRotation B1 = solveBoost(k, orderedJets.begin()->q, orderedJets.begin()->p);
deepTransform(orderedJets.begin()->parent,B1);
// boost everything else
// first to rescale
LorentzRotation B2 = solveBoost(k, psum, psum);
// and then to rest frame of new system
Lorentz5Momentum pnew = B2*psum;
pnew.rescaleMass();
B2.transform(pnew.findBoostToCM());
// apply transform (calling routine ensures at least 3 elements)
jit = orderedJets.begin(); ++jit;
for(;jit!=orderedJets.end();++jit) {
deepTransform(jit->parent,B2);
jit->p *= B2;
jit->q *= B2;
}
JetKinVect newJets(orderedJets.begin()+1,orderedJets.end());
// final reconstruction
if(newJets.size()==2 || !recursive ) {
// rescaling factor
double k = solveKfactor(psum.m(), newJets);
// rescale jets in the new CMF
for(JetKinVect::iterator it = newJets.begin(); it != newJets.end(); ++it) {
LorentzRotation Trafo = solveBoost(k, it->q, it->p);
deepTransform(it->parent,Trafo);
}
}
// recursive
else {
std::sort(newJets.begin(),newJets.end(),JetOrdering());
reconstructFinalFinalOffShell(newJets,psum.m2(),recursive);
}
// finally boost back from new CMF
LorentzRotation back(-pnew.findBoostToCM());
for(JetKinVect::iterator it = newJets.begin(); it != newJets.end(); ++it) {
deepTransform(it->parent,back);
}
}
Energy QTildeReconstructor::findMass(HardBranchingPtr branch) const {
// KH - 230909 - If the particle has no children then it will
// not have showered and so it should be "on-shell" so we can
// get it's mass from it's momentum. This means that the
// inverseRescalingFactor doesn't give any nans or do things
// it shouldn't if it gets e.g. two Z bosons generated with
// off-shell masses. This is for sure not the best solution.
// PR 1/1/10 modification to previous soln
// PR 28/8/14 change to procedure and factorize into a function
if(branch->children().empty()) {
return branch->branchingParticle()->mass();
}
else if(!branch->children().empty() &&
!branch->branchingParticle()->dataPtr()->stable() ) {
for(unsigned int ix=0;ix<branch->children().size();++ix) {
if(branch->branchingParticle()->id()==
branch->children()[ix]->branchingParticle()->id())
return findMass(branch->children()[ix]);
}
}
return branch->branchingParticle()->dataPtr()->mass();
}
vector<double>
QTildeReconstructor::inverseInitialStateRescaling(double & x1, double & x2,
const Lorentz5Momentum & pold,
const vector<Lorentz5Momentum> & p,
const vector<Lorentz5Momentum> & pq) const {
// hadronic CMS
Energy2 s = (pq[0] +pq[1] ).m2();
// partonic CMS
Energy MDY = pold.m();
// find alpha, beta and pt
Energy2 p12=pq[0]*pq[1];
double a[2],b[2];
Lorentz5Momentum pt[2];
for(unsigned int ix=0;ix<2;++ix) {
a[ix] = p[ix]*pq[1]/p12;
b [ix] = p[ix]*pq[0]/p12;
pt[ix] = p[ix]-a[ix]*pq[0]-b[ix]*pq[1];
}
// compute kappa
// we always want to preserve the mass of the system
double k1(1.),k2(1.);
if(_initialStateReconOption==0) {
double rap=pold.rapidity();
x2 = MDY/sqrt(s*exp(2.*rap));
x1 = sqr(MDY)/s/x2;
k1=a[0]/x1;
k2=b[1]/x2;
}
// longitudinal momentum
else if(_initialStateReconOption==1) {
double A = 1.;
double C = -sqr(MDY)/s;
double B = 2.*pold.z()/sqrt(s);
if(abs(B)>1e-10) {
double discrim = 1.-4.*A*C/sqr(B);
if(discrim < 0.) throw KinematicsReconstructionVeto();
x1 = B>0. ? 0.5*B/A*(1.+sqrt(discrim)) : 0.5*B/A*(1.-sqrt(discrim));
}
else {
x1 = -C/A;
if( x1 <= 0.) throw KinematicsReconstructionVeto();
x1 = sqrt(x1);
}
x2 = sqr(MDY)/s/x1;
k1=a[0]/x1;
k2=b[1]/x2;
}
// preserve mass and don't scale the softer system
// to reproduce the dipole kinematics
else if(_initialStateReconOption==2) {
// in this case kp = k1 or k2 depending on who's the harder guy
k1 = a[0]*b[1]*s/sqr(MDY);
if ( pt[0].perp2() < pt[1].perp2() ) swap(k1,k2);
x1 = a[0]/k1;
x2 = b[1]/k2;
}
else
assert(false);
// decompose the momenta
double anew[2] = {a[0]/k1,a[1]*k2};
double bnew[2] = {b[0]*k1,b[1]/k2};
vector<double> boost(2);
for(unsigned int ix=0;ix<2;++ix) {
boost[ix] = getBeta(a [ix]+b [ix], a[ix] -b [ix],
anew[ix]+bnew[ix], anew[ix]-bnew[ix]);
}
return boost;
}
vector<double>
QTildeReconstructor::initialStateRescaling(double x1, double x2,
const Lorentz5Momentum & pold,
const vector<Lorentz5Momentum> & p,
const vector<Lorentz5Momentum> & pq,
const vector<Energy>& highestpts) const {
Energy2 S = (pq[0]+pq[1]).m2();
// find alphas and betas in terms of desired basis
Energy2 p12 = pq[0]*pq[1];
double a[2] = {p[0]*pq[1]/p12,p[1]*pq[1]/p12};
double b[2] = {p[0]*pq[0]/p12,p[1]*pq[0]/p12};
Lorentz5Momentum p1p = p[0] - a[0]*pq[0] - b[0]*pq[1];
Lorentz5Momentum p2p = p[1] - a[1]*pq[0] - b[1]*pq[1];
// compute kappa
// we always want to preserve the mass of the system
Energy MDY = pold.m();
Energy2 A = a[0]*b[1]*S;
Energy2 B = Energy2(sqr(MDY)) - (a[0]*b[0]+a[1]*b[1])*S - (p1p+p2p).m2();
Energy2 C = a[1]*b[0]*S;
double rad = 1.-4.*A*C/sqr(B);
if(rad < 0.) throw KinematicsReconstructionVeto();
double kp = B/(2.*A)*(1.+sqrt(rad));
// now compute k1
// conserve rapidity
double k1(0.);
double k2(0.);
if(_initialStateReconOption==0) {
rad = kp*(b[0]+kp*b[1])/(kp*a[0]+a[1]);
rad *= pq[0].z()<ZERO ? exp(-2.*pold.rapidity()) : exp(2.*pold.rapidity());
if(rad <= 0.) throw KinematicsReconstructionVeto();
k1 = sqrt(rad);
k2 = kp/k1;
}
// conserve longitudinal momentum
else if(_initialStateReconOption==1) {
double a2 = (a[0]+a[1]/kp);
double b2 = -x2+x1;
double c2 = -(b[1]*kp+b[0]);
if(abs(b2)>1e-10) {
double discrim = 1.-4.*a2*c2/sqr(b2);
if(discrim < 0.) throw KinematicsReconstructionVeto();
k1 = b2>0. ? 0.5*b2/a2*(1.+sqrt(discrim)) : 0.5*b2/a2*(1.-sqrt(discrim));
}
else {
k1 = -c2/a2;
if( k1 <= 0.) throw KinematicsReconstructionVeto();
k1 = sqrt(k1);
}
k2 = kp/k1;
}
// preserve mass and don't scale the softer system
// to reproduce the dipole kinematics
else if(_initialStateReconOption==2) {
// in this case kp = k1 or k2 depending on who's the harder guy
k1 = kp; k2 = 1.;
if ( highestpts[0] < highestpts[1] )
swap(k1,k2);
}
else
assert(false);
// calculate the boosts
vector<double> beta(2);
beta[0] = getBeta((a[0]+b[0]), (a[0]-b[0]), (k1*a[0]+b[0]/k1), (k1*a[0]-b[0]/k1));
beta[1] = getBeta((a[1]+b[1]), (a[1]-b[1]), (a[1]/k2+k2*b[1]), (a[1]/k2-k2*b[1]));
if (pq[0].z() > ZERO) {
beta[0] = -beta[0];
beta[1] = -beta[1];
}
return beta;
}
void QTildeReconstructor::
reconstructColourSinglets(vector<ShowerProgenitorPtr> & ShowerHardJets,
ShowerInteraction type) const {
// identify and catagorize the colour singlet systems
unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0);
vector<ColourSingletSystem>
systems(identifySystems(set<ShowerProgenitorPtr>(ShowerHardJets.begin(),ShowerHardJets.end()),
nnun,nnii,nnif,nnf,nni));
// now decide what to do
// initial-initial connection and final-state colour singlet systems
LorentzRotation toRest,fromRest;
bool applyBoost(false),general(false);
// Drell-Yan type
if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) {
// reconstruct initial-initial system
for(unsigned int ix=0;ix<systems.size();++ix) {
if(systems[ix].type==II)
reconstructInitialInitialSystem(applyBoost,toRest,fromRest,
systems[ix].jets);
}
if(type!=ShowerInteraction::QCD) {
combineFinalState(systems);
general=false;
}
}
// DIS and VBF type
else if(nnun==0&&nnii==0&&((nnif==1&&nnf>0&&nni==1)||
(nnif==2&& nni==0))) {
// check these systems can be reconstructed
for(unsigned int ix=0;ix<systems.size();++ix) {
// compute q^2
if(systems[ix].type!=IF) continue;
Lorentz5Momentum q;
for(unsigned int iy=0;iy<systems[ix].jets.size();++iy) {
if(systems[ix].jets[iy]->progenitor()->isFinalState())
q += systems[ix].jets[iy]->progenitor()->momentum();
else
q -= systems[ix].jets[iy]->progenitor()->momentum();
}
q.rescaleMass();
// check above cut
if(abs(q.m())>=_minQ) continue;
if(nnif==1&&nni==1) {
throw KinematicsReconstructionVeto();
}
else {
general = true;
break;
}
}
if(!general) {
for(unsigned int ix=0;ix<systems.size();++ix) {
if(systems[ix].type==IF)
reconstructInitialFinalSystem(systems[ix].jets);
}
}
}
// e+e- type
else if(nnun==0&&nnii==0&&nnif==0&&nnf>0&&nni==2) {
general = type !=ShowerInteraction::QCD;
}
// general type
else {
general = true;
}
// final-state systems except for general recon
if(!general) {
for(unsigned int ix=0;ix<systems.size();++ix) {
if(systems[ix].type==F)
reconstructFinalStateSystem(applyBoost,toRest,fromRest,
systems[ix].jets);
}
}
else {
reconstructGeneralSystem(ShowerHardJets);
}
}
void QTildeReconstructor::findInitialBoost(const Lorentz5Momentum & pold,
const Lorentz5Momentum & pnew,
LorentzRotation & toRest,
LorentzRotation & fromRest) const {
// do one boost
if(_initialBoost==0) {
toRest = LorentzRotation(pold.findBoostToCM());
fromRest = LorentzRotation(pnew.boostVector());
}
else if(_initialBoost==1) {
// boost to rest frame
// first transverse
toRest = Boost(-pold.x()/pold.t(),-pold.y()/pold.t(),0.);
// then longitudinal
double beta = pold.z()/sqrt(pold.m2()+sqr(pold.z()));
toRest.boost((Boost(0.,0.,-beta)));
// boost from rest frame
// first apply longitudinal boost
beta = pnew.z()/sqrt(pnew.m2()+sqr(pnew.z()));
fromRest=LorentzRotation(Boost(0.,0.,beta));
// then transverse one
fromRest.boost(Boost(pnew.x()/pnew.t(),
pnew.y()/pnew.t(),0.));
}
else
assert(false);
}
diff --git a/Shower/QTilde/Default/QTildeSudakov.cc b/Shower/QTilde/Default/QTildeSudakov.cc
--- a/Shower/QTilde/Default/QTildeSudakov.cc
+++ b/Shower/QTilde/Default/QTildeSudakov.cc
@@ -1,1061 +1,1069 @@
// -*- C++ -*-
//
// QTildeSudakov.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the QTildeSudakov class.
//
#include "QTildeSudakov.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/PDT/ParticleData.h"
#include "ThePEG/EventRecord/Event.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Shower/QTilde/Default/FS_QTildeShowerKinematics1to2.h"
#include "Herwig/Shower/QTilde/Default/IS_QTildeShowerKinematics1to2.h"
#include "Herwig/Shower/QTilde/Default/Decay_QTildeShowerKinematics1to2.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Shower/QTilde/Base/ShowerVertex.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/QTilde/QTildeShowerHandler.h"
#include "Herwig/Shower/QTilde/Base/PartnerFinder.h"
#include "Herwig/Shower/QTilde/Base/ShowerModel.h"
#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h"
using namespace Herwig;
DescribeNoPIOClass<QTildeSudakov,Herwig::SudakovFormFactor>
describeQTildeSudakov ("Herwig::QTildeSudakov","HwShower.so");
void QTildeSudakov::Init() {
static ClassDocumentation<QTildeSudakov> documentation
("The QTildeSudakov class implements the Sudakov form factor for ordering it"
" qtilde");
}
bool QTildeSudakov::guessTimeLike(Energy2 &t,Energy2 tmin,double enhance,
double detune) {
Energy2 told = t;
// calculate limits on z and if lower>upper return
if(!computeTimeLikeLimits(t)) return false;
// guess values of t and z
t = guesst(told,0,ids_,enhance,ids_[1]==ids_[2],detune);
z(guessz(0,ids_));
// actual values for z-limits
if(!computeTimeLikeLimits(t)) return false;
if(t<tmin) {
t=-1.0*GeV2;
return false;
}
else
return true;
}
bool QTildeSudakov::guessSpaceLike(Energy2 &t, Energy2 tmin, const double x,
double enhance,
double detune) {
Energy2 told = t;
// calculate limits on z if lower>upper return
if(!computeSpaceLikeLimits(t,x)) return false;
// guess values of t and z
t = guesst(told,1,ids_,enhance,ids_[1]==ids_[2],detune);
z(guessz(1,ids_));
// actual values for z-limits
if(!computeSpaceLikeLimits(t,x)) return false;
if(t<tmin) {
t=-1.0*GeV2;
return false;
}
else
return true;
}
bool QTildeSudakov::PSVeto(const Energy2 t,
const Energy2 maxQ2) {
// still inside PS, return true if outside
// check vs overestimated limits
if(z() < zLimits().first || z() > zLimits().second) return true;
Energy2 q2 = z()*(1.-z())*t;
if(ids_[0]->id()!=ParticleID::g &&
ids_[0]->id()!=ParticleID::gamma ) q2 += masssquared_[0];
if(q2>maxQ2) return true;
// compute the pts
Energy2 pt2 = z()*(1.-z())*q2 - masssquared_[1]*(1.-z()) - masssquared_[2]*z();
// if pt2<0 veto
if(pt2<pT2min()) return true;
// otherwise calculate pt and return
pT(sqrt(pt2));
return false;
}
ShoKinPtr QTildeSudakov::generateNextTimeBranching(const Energy startingScale,
const IdList &ids,
const RhoDMatrix & rho,
double enhance,
double detuning,
Energy2 maxQ2) {
// First reset the internal kinematics variables that can
// have been eventually set in the previous call to the method.
q_ = ZERO;
z(0.);
phi(0.);
// perform initialization
Energy2 tmax(sqr(startingScale)),tmin;
initialize(ids,tmin);
// check max > min
if(tmax<=tmin) return ShoKinPtr();
// calculate next value of t using veto algorithm
Energy2 t(tmax);
// no shower variations to calculate
if(ShowerHandler::currentHandler()->showerVariations().empty()){
// Without variations do the usual Veto algorithm
// No need for more if-statements in this loop.
do {
if(!guessTimeLike(t,tmin,enhance,detuning)) break;
}
while(PSVeto(t,maxQ2) ||
SplittingFnVeto(z()*(1.-z())*t,ids,true,rho,detuning) ||
alphaSVeto(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t));
}
else {
bool alphaRew(true),PSRew(true),SplitRew(true);
do {
if(!guessTimeLike(t,tmin,enhance,detuning)) break;
PSRew=PSVeto(t,maxQ2);
if (PSRew) continue;
SplitRew=SplittingFnVeto(z()*(1.-z())*t,ids,true,rho,detuning);
alphaRew=alphaSVeto(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t);
double factor=alphaSVetoRatio(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t,1.)*
SplittingFnVetoRatio(z()*(1.-z())*t,ids,true,rho,detuning);
tShowerHandlerPtr ch = ShowerHandler::currentHandler();
if( !(SplitRew || alphaRew) ) {
//Emission
q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV;
if (q_ <= ZERO) break;
}
for ( map<string,ShowerVariation>::const_iterator var =
ch->showerVariations().begin();
var != ch->showerVariations().end(); ++var ) {
if ( ( ch->firstInteraction() && var->second.firstInteraction ) ||
( !ch->firstInteraction() && var->second.secondaryInteractions ) ) {
double newfactor = alphaSVetoRatio(splittingFn()->pTScale() ?
sqr(z()*(1.-z()))*t :
z()*(1.-z())*t,var->second.renormalizationScaleFactor)
* SplittingFnVetoRatio(z()*(1.-z())*t,ids,true,rho,detuning);
double varied;
if ( SplitRew || alphaRew ) {
// No Emission
varied = (1. - newfactor) / (1. - factor);
} else {
// Emission
varied = newfactor / factor;
}
map<string,double>::iterator wi = ch->currentWeights().find(var->first);
if ( wi != ch->currentWeights().end() )
wi->second *= varied;
else {
assert(false);
//ch->currentWeights()[var->first] = varied;
}
}
}
}
while(PSRew || SplitRew || alphaRew);
}
q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV;
if(q_ < ZERO) return ShoKinPtr();
// return the ShowerKinematics object
return createFinalStateBranching(q_,z(),phi(),pT());
}
ShoKinPtr QTildeSudakov::
generateNextSpaceBranching(const Energy startingQ,
const IdList &ids,
double x,
const RhoDMatrix & rho,
double enhance,
Ptr<BeamParticleData>::transient_const_pointer beam,
double detuning) {
// First reset the internal kinematics variables that can
// have been eventually set in the previous call to the method.
q_ = ZERO;
z(0.);
phi(0.);
// perform the initialization
Energy2 tmax(sqr(startingQ)),tmin;
initialize(ids,tmin);
// check max > min
if(tmax<=tmin) return ShoKinPtr();
// calculate next value of t using veto algorithm
Energy2 t(tmax),pt2(ZERO);
// no shower variations
if(ShowerHandler::currentHandler()->showerVariations().empty()) {
// Without variations do the usual Veto algorithm
// No need for more if-statements in this loop.
do {
if(!guessSpaceLike(t,tmin,x,enhance,detuning)) break;
pt2=sqr(1.-z())*t-z()*masssquared_[2];
}
while(pt2 < pT2min()||
z() > zLimits().second||
SplittingFnVeto((1.-z())*t/z(),ids,false,rho,detuning)||
alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t)||
PDFVeto(t,x,ids[0],ids[1],beam));
}
// shower variations
else {
bool alphaRew(true),PDFRew(true),ptRew(true),zRew(true),SplitRew(true);
do {
if(!guessSpaceLike(t,tmin,x,enhance,detuning)) break;
pt2=sqr(1.-z())*t-z()*masssquared_[2];
ptRew=pt2 < pT2min();
zRew=z() > zLimits().second;
if (ptRew||zRew) continue;
SplitRew=SplittingFnVeto((1.-z())*t/z(),ids,false,rho,detuning);
alphaRew=alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t);
PDFRew=PDFVeto(t,x,ids[0],ids[1],beam);
double factor=PDFVetoRatio(t,x,ids[0],ids[1],beam,1.)*
alphaSVetoRatio(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t,1.)*
SplittingFnVetoRatio((1.-z())*t/z(),ids,false,rho,detuning);
tShowerHandlerPtr ch = ShowerHandler::currentHandler();
if( !(PDFRew || SplitRew || alphaRew) ) {
//Emission
q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV;
if (q_ <= ZERO) break;
}
for ( map<string,ShowerVariation>::const_iterator var =
ch->showerVariations().begin();
var != ch->showerVariations().end(); ++var ) {
if ( ( ch->firstInteraction() && var->second.firstInteraction ) ||
( !ch->firstInteraction() && var->second.secondaryInteractions ) ) {
double newfactor = PDFVetoRatio(t,x,ids[0],ids[1],beam,var->second.factorizationScaleFactor)*
alphaSVetoRatio(splittingFn()->pTScale() ?
sqr(1.-z())*t : (1.-z())*t,var->second.renormalizationScaleFactor)
*SplittingFnVetoRatio((1.-z())*t/z(),ids,false,rho,detuning);
double varied;
if( PDFRew || SplitRew || alphaRew) {
// No Emission
varied = (1. - newfactor) / (1. - factor);
} else {
// Emission
varied = newfactor / factor;
}
map<string,double>::iterator wi = ch->currentWeights().find(var->first);
if ( wi != ch->currentWeights().end() )
wi->second *= varied;
else {
assert(false);
//ch->currentWeights()[var->first] = varied;
}
}
}
}
while( PDFRew || SplitRew || alphaRew);
}
if(t > ZERO && zLimits().first < zLimits().second) q_ = sqrt(t);
else return ShoKinPtr();
pT(sqrt(pt2));
// create the ShowerKinematics and return it
return createInitialStateBranching(q_,z(),phi(),pT());
}
void QTildeSudakov::initialize(const IdList & ids, Energy2 & tmin) {
ids_=ids;
tmin = cutOffOption() != 2 ? ZERO : 4.*pT2min();
masses_ = virtualMasses(ids);
masssquared_.clear();
for(unsigned int ix=0;ix<masses_.size();++ix) {
masssquared_.push_back(sqr(masses_[ix]));
if(ix>0) tmin=max(masssquared_[ix],tmin);
}
}
ShoKinPtr QTildeSudakov::generateNextDecayBranching(const Energy startingScale,
const Energy stoppingScale,
const Energy minmass,
const IdList &ids,
const RhoDMatrix & rho,
double enhance,
double detuning) {
// First reset the internal kinematics variables that can
// have been eventually set in the previous call to this method.
q_ = Constants::MaxEnergy;
z(0.);
phi(0.);
// perform initialisation
Energy2 tmax(sqr(stoppingScale)),tmin;
initialize(ids,tmin);
tmin=sqr(startingScale);
// check some branching possible
if(tmax<=tmin) return ShoKinPtr();
// perform the evolution
Energy2 t(tmin),pt2(-MeV2);
do {
if(!guessDecay(t,tmax,minmass,enhance,detuning)) break;
pt2 = sqr(1.-z())*(t-masssquared_[0])-z()*masssquared_[2];
}
while(SplittingFnVeto((1.-z())*t/z(),ids,true,rho,detuning)||
alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t ) ||
pt2<pT2min() ||
t*(1.-z())>masssquared_[0]-sqr(minmass));
if(t > ZERO) {
q_ = sqrt(t);
pT(sqrt(pt2));
}
else return ShoKinPtr();
phi(0.);
// create the ShowerKinematics object
return createDecayBranching(q_,z(),phi(),pT());
}
bool QTildeSudakov::guessDecay(Energy2 &t,Energy2 tmax, Energy minmass,
double enhance, double detune) {
// previous scale
Energy2 told = t;
// overestimated limits on z
if(tmax<masssquared_[0]) {
t=-1.0*GeV2;
return false;
}
Energy2 tm2 = tmax-masssquared_[0];
Energy tm = sqrt(tm2);
pair<double,double> limits=make_pair(sqr(minmass/masses_[0]),
1.-sqrt(masssquared_[2]+pT2min()+
0.25*sqr(masssquared_[2])/tm2)/tm
+0.5*masssquared_[2]/tm2);
zLimits(limits);
if(zLimits().second<zLimits().first) {
t=-1.0*GeV2;
return false;
}
// guess values of t and z
t = guesst(told,2,ids_,enhance,ids_[1]==ids_[2],detune);
z(guessz(2,ids_));
// actual values for z-limits
if(t<masssquared_[0]) {
t=-1.0*GeV2;
return false;
}
tm2 = t-masssquared_[0];
tm = sqrt(tm2);
limits=make_pair(sqr(minmass/masses_[0]),
1.-sqrt(masssquared_[2]+pT2min()+
0.25*sqr(masssquared_[2])/tm2)/tm
+0.5*masssquared_[2]/tm2);
zLimits(limits);
if(t>tmax||zLimits().second<zLimits().first) {
t=-1.0*GeV2;
return false;
}
else
return true;
}
bool QTildeSudakov::computeTimeLikeLimits(Energy2 & t) {
if (t < 1e-20 * GeV2) {
t=-1.*GeV2;
return false;
}
// special case for gluon radiating
pair<double,double> limits;
if(ids_[0]->id()==ParticleID::g||ids_[0]->id()==ParticleID::gamma) {
// no emission possible
if(t<16.*(masssquared_[1]+pT2min())) {
t=-1.*GeV2;
return false;
}
// overestimate of the limits
limits.first = 0.5*(1.-sqrt(1.-4.*sqrt((masssquared_[1]+pT2min())/t)));
limits.second = 1.-limits.first;
}
// special case for radiated particle is gluon
else if(ids_[2]->id()==ParticleID::g||ids_[2]->id()==ParticleID::gamma) {
limits.first = sqrt((masssquared_[1]+pT2min())/t);
limits.second = 1.-sqrt((masssquared_[2]+pT2min())/t);
}
else if(ids_[1]->id()==ParticleID::g||ids_[1]->id()==ParticleID::gamma) {
limits.second = sqrt((masssquared_[2]+pT2min())/t);
limits.first = 1.-sqrt((masssquared_[1]+pT2min())/t);
}
else {
limits.first = (masssquared_[1]+pT2min())/t;
limits.second = 1.-(masssquared_[2]+pT2min())/t;
}
if(limits.first>=limits.second) {
t=-1.*GeV2;
return false;
}
zLimits(limits);
return true;
}
bool QTildeSudakov::computeSpaceLikeLimits(Energy2 & t, double x) {
if (t < 1e-20 * GeV2) {
t=-1.*GeV2;
return false;
}
pair<double,double> limits;
// compute the limits
limits.first = x;
double yy = 1.+0.5*masssquared_[2]/t;
limits.second = yy - sqrt(sqr(yy)-1.+pT2min()/t);
// return false if lower>upper
zLimits(limits);
if(limits.second<limits.first) {
t=-1.*GeV2;
return false;
}
else
return true;
}
namespace {
tShowerParticlePtr findCorrelationPartner(ShowerParticle & particle,
bool forward,
ShowerInteraction inter) {
tPPtr child = &particle;
tShowerParticlePtr mother;
if(forward) {
mother = !particle.parents().empty() ?
dynamic_ptr_cast<tShowerParticlePtr>(particle.parents()[0]) : tShowerParticlePtr();
}
else {
mother = particle.children().size()==2 ?
dynamic_ptr_cast<tShowerParticlePtr>(&particle) : tShowerParticlePtr();
}
tShowerParticlePtr partner;
while(mother) {
tPPtr otherChild;
if(forward) {
for (unsigned int ix=0;ix<mother->children().size();++ix) {
if(mother->children()[ix]!=child) {
otherChild = mother->children()[ix];
break;
}
}
}
else {
otherChild = mother->children()[1];
}
tShowerParticlePtr other = dynamic_ptr_cast<tShowerParticlePtr>(otherChild);
if((inter==ShowerInteraction::QCD && otherChild->dataPtr()->coloured()) ||
(inter==ShowerInteraction::QED && otherChild->dataPtr()->charged())) {
partner = other;
break;
}
if(forward && !other->isFinalState()) {
partner = dynamic_ptr_cast<tShowerParticlePtr>(mother);
break;
}
child = mother;
if(forward) {
mother = ! mother->parents().empty() ?
dynamic_ptr_cast<tShowerParticlePtr>(mother->parents()[0]) : tShowerParticlePtr();
}
else {
if(mother->children()[0]->children().size()!=2)
break;
tShowerParticlePtr mtemp =
dynamic_ptr_cast<tShowerParticlePtr>(mother->children()[0]);
if(!mtemp)
break;
else
mother=mtemp;
}
}
if(!partner) {
if(forward) {
partner = dynamic_ptr_cast<tShowerParticlePtr>( child)->partner();
}
else {
if(mother) {
tShowerParticlePtr parent;
if(!mother->children().empty()) {
parent = dynamic_ptr_cast<tShowerParticlePtr>(mother->children()[0]);
}
if(!parent) {
parent = dynamic_ptr_cast<tShowerParticlePtr>(mother);
}
partner = parent->partner();
}
else {
partner = dynamic_ptr_cast<tShowerParticlePtr>(&particle)->partner();
}
}
}
return partner;
}
pair<double,double> softPhiMin(double phi0, double phi1, double A, double B, double C, double D) {
double c01 = cos(phi0 - phi1);
double s01 = sin(phi0 - phi1);
double s012(sqr(s01)), c012(sqr(c01));
double A2(A*A), B2(B*B), C2(C*C), D2(D*D);
if(abs(B/A)<1e-10 && abs(D/C)<1e-10) return make_pair(phi0,phi0+Constants::pi);
double root = sqr(B2)*C2*D2*sqr(s012) + 2.*A*B2*B*C2*C*D*c01*s012 + 2.*A*B2*B*C*D2*D*c01*s012
+ 4.*A2*B2*C2*D2*c012 - A2*B2*C2*D2*s012 - A2*B2*sqr(D2)*s012 - sqr(B2)*sqr(C2)*s012
- sqr(B2)*C2*D2*s012 - 4.*A2*A*B*C*D2*D*c01 - 4.*A*B2*B*C2*C*D*c01 + sqr(A2)*sqr(D2)
+ 2.*A2*B2*C2*D2 + sqr(B2)*sqr(C2);
if(root<0.) return make_pair(phi0,phi0+Constants::pi);
root = sqrt(root);
double denom = (-2.*A*B*C*D*c01 + A2*D2 + B2*C2);
double denom2 = (-B*C*c01 + A*D);
- if(denom==ZERO || denom2==0)
- return make_pair(phi0,phi0+Constants::pi);
+
double num = B2*C*D*s012;
- return make_pair(atan2(B*s01*(-C*(num + root) / denom + D) / denom2, -(num + root ) / denom) + phi0,
- atan2(B*s01*(-C*(num - root) / denom + D) / denom2, -(num - root ) / denom) + phi0);
+ double y1 = B*s01*(-C*(num + root) + D*denom) / denom2;
+ double y2 = B*s01*(-C*(num - root) + D*denom) / denom2;
+ double x1 = -(num + root );
+ double x2 = -(num - root );
+ if(denom<0.) {
+ y1*=-1.;
+ y2*=-1.;
+ x1*=-1.;
+ x2*=-1.;
+ }
+ return make_pair(atan2(y1,x1) + phi0,atan2(y2,x2) + phi0);
}
}
double QTildeSudakov::generatePhiForward(ShowerParticle & particle,
const IdList & ids,
ShoKinPtr kinematics,
const RhoDMatrix & rho) {
// no correlations, return flat phi
if(! dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->correlations())
return Constants::twopi*UseRandom::rnd();
// get the kinematic variables
double z = kinematics->z();
Energy2 t = z*(1.-z)*sqr(kinematics->scale());
Energy pT = kinematics->pT();
// if soft correlations
Energy2 pipj,pik;
bool canBeSoft[2] = {ids[1]->id()==ParticleID::g || ids[1]->id()==ParticleID::gamma,
ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma };
- vector<Energy2> pjk(3,ZERO);
- vector<Energy> Ek(3,ZERO);
+ array<Energy2,3> pjk = {};
+ array<Energy, 3> Ek = {};
Energy Ei,Ej;
Energy2 m12(ZERO),m22(ZERO);
InvEnergy2 aziMax(ZERO);
bool softAllowed = dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()&&
(canBeSoft[0] || canBeSoft[1]);
if(softAllowed) {
// find the partner for the soft correlations
tShowerParticlePtr partner=findCorrelationPartner(particle,true,splittingFn()->interactionType());
// remember we want the softer gluon
bool swapOrder = !canBeSoft[1] || (canBeSoft[0] && canBeSoft[1] && z < 0.5);
double zFact = !swapOrder ? (1.-z) : z;
// compute the transforms to the shower reference frame
// first the boost
Lorentz5Momentum pVect = particle.showerBasis()->pVector();
Lorentz5Momentum nVect = particle.showerBasis()->nVector();
Boost beta_bb;
if(particle.showerBasis()->frame()==ShowerBasis::BackToBack) {
beta_bb = -(pVect + nVect).boostVector();
}
else if(particle.showerBasis()->frame()==ShowerBasis::Rest) {
beta_bb = -pVect.boostVector();
}
else
assert(false);
pVect.boost(beta_bb);
nVect.boost(beta_bb);
Axis axis;
if(particle.showerBasis()->frame()==ShowerBasis::BackToBack) {
axis = pVect.vect().unit();
}
else if(particle.showerBasis()->frame()==ShowerBasis::Rest) {
axis = nVect.vect().unit();
}
else
assert(false);
// and then the rotation
LorentzRotation rot;
if(axis.perp2()>0.) {
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
}
else if(axis.z()<0.) {
rot.rotate(Constants::pi,Axis(1.,0.,0.));
}
rot.invert();
pVect *= rot;
nVect *= rot;
// shower parameters
Energy2 pn = pVect*nVect, m2 = pVect.m2();
double alpha0 = particle.showerParameters().alpha;
double beta0 = 0.5/alpha0/pn*
(sqr(particle.dataPtr()->mass())-sqr(alpha0)*m2+sqr(particle.showerParameters().pt));
Lorentz5Momentum qperp0(particle.showerParameters().ptx,
particle.showerParameters().pty,ZERO,ZERO);
assert(partner);
Lorentz5Momentum pj = partner->momentum();
pj.boost(beta_bb);
pj *= rot;
// compute the two phi independent dot products
pik = 0.5*zFact*(sqr(alpha0)*m2 - sqr(particle.showerParameters().pt) + 2.*alpha0*beta0*pn )
+0.5*sqr(pT)/zFact;
Energy2 dot1 = pj*pVect;
Energy2 dot2 = pj*nVect;
Energy2 dot3 = pj*qperp0;
pipj = alpha0*dot1+beta0*dot2+dot3;
// compute the constants for the phi dependent dot product
pjk[0] = zFact*(alpha0*dot1+dot3-0.5*dot2/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0))
+0.5*sqr(pT)*dot2/pn/zFact/alpha0;
pjk[1] = (pj.x() - dot2/alpha0/pn*qperp0.x())*pT;
pjk[2] = (pj.y() - dot2/alpha0/pn*qperp0.y())*pT;
m12 = sqr(particle.dataPtr()->mass());
m22 = sqr(partner->dataPtr()->mass());
if(swapOrder) {
pjk[1] *= -1.;
pjk[2] *= -1.;
}
Ek[0] = zFact*(alpha0*pVect.t()-0.5*nVect.t()/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0))
+0.5*sqr(pT)*nVect.t()/pn/zFact/alpha0;
Ek[1] = -nVect.t()/alpha0/pn*qperp0.x()*pT;
Ek[2] = -nVect.t()/alpha0/pn*qperp0.y()*pT;
if(swapOrder) {
Ek[1] *= -1.;
Ek[2] *= -1.;
}
Energy mag2=sqrt(sqr(Ek[1])+sqr(Ek[2]));
Ei = alpha0*pVect.t()+beta0*nVect.t();
Ej = pj.t();
double phi0 = atan2(-pjk[2],-pjk[1]);
if(phi0<0.) phi0 += Constants::twopi;
double phi1 = atan2(-Ek[2],-Ek[1]);
if(phi1<0.) phi1 += Constants::twopi;
double xi_min = pik/Ei/(Ek[0]+mag2), xi_max = pik/Ei/(Ek[0]-mag2), xi_ij = pipj/Ei/Ej;
if(xi_min>xi_max) swap(xi_min,xi_max);
if(xi_min>xi_ij) softAllowed = false;
Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2]));
if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==1) {
aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag);
}
else if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==2) {
double A = (pipj*Ek[0]- Ej*pik)/Ej/sqr(Ej);
double B = -sqrt(sqr(pipj)*(sqr(Ek[1])+sqr(Ek[2])))/Ej/sqr(Ej);
double C = pjk[0]/sqr(Ej);
double D = -sqrt(sqr(pjk[1])+sqr(pjk[2]))/sqr(Ej);
pair<double,double> minima = softPhiMin(phi0,phi1,A,B,C,D);
aziMax = 0.5/pik/(Ek[0]-mag2)*(Ei-m12*(Ek[0]-mag2)/pik + max(Ej*(A+B*cos(minima.first -phi1))/(C+D*cos(minima.first -phi0)),
Ej*(A+B*cos(minima.second-phi1))/(C+D*cos(minima.second-phi0))));
}
else
assert(false);
}
// if spin correlations
vector<pair<int,Complex> > wgts;
if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->spinCorrelations()) {
// calculate the weights
wgts = splittingFn()->generatePhiForward(z,t,ids,rho);
}
else {
- wgts = vector<pair<int,Complex> >(1,make_pair(0,1.));
+ wgts = {{ {0, 1.} }};
}
// generate the azimuthal angle
double phi,wgt;
static const Complex ii(0.,1.);
unsigned int ntry(0);
double phiMax(0.),wgtMax(0.);
do {
phi = Constants::twopi*UseRandom::rnd();
// first the spin correlations bit (gives 1 if correlations off)
Complex spinWgt = 0.;
for(unsigned int ix=0;ix<wgts.size();++ix) {
if(wgts[ix].first==0)
spinWgt += wgts[ix].second;
else
spinWgt += exp(double(wgts[ix].first)*ii*phi)*wgts[ix].second;
}
wgt = spinWgt.real();
if(wgt-1.>1e-10) {
generator()->log() << "Forward spin weight problem " << wgt << " " << wgt-1.
<< " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n";
generator()->log() << "Weights \n";
for(unsigned int ix=0;ix<wgts.size();++ix)
generator()->log() << wgts[ix].first << " " << wgts[ix].second << "\n";
}
// soft correlations bit
double aziWgt = 1.;
if(softAllowed) {
Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi);
Energy Eg = Ek[0]+Ek[1]*cos(phi)+Ek[2]*sin(phi);
if(pipj*Eg>pik*Ej) {
if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==1) {
aziWgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax;
}
else if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==2) {
aziWgt = max(ZERO,0.5/pik/Eg*(Ei-m12*Eg/pik + (pipj*Eg - Ej*pik)/dot)/aziMax);
}
if(aziWgt-1.>1e-10||aziWgt<-1e-10) {
generator()->log() << "Forward soft weight problem " << aziWgt << " " << aziWgt-1.
<< " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n";
}
}
else {
aziWgt = 0.;
}
}
wgt *= aziWgt;
if(wgt>wgtMax) {
phiMax = phi;
wgtMax = wgt;
}
++ntry;
}
while(wgt<UseRandom::rnd()&&ntry<10000);
if(ntry==10000) {
generator()->log() << "Too many tries to generate phi in forward evolution\n";
phi = phiMax;
}
// return the azimuthal angle
return phi;
}
double QTildeSudakov::generatePhiBackward(ShowerParticle & particle,
const IdList & ids,
ShoKinPtr kinematics,
const RhoDMatrix & rho) {
// no correlations, return flat phi
if(! dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->correlations())
return Constants::twopi*UseRandom::rnd();
// get the kinematic variables
double z = kinematics->z();
Energy2 t = (1.-z)*sqr(kinematics->scale())/z;
Energy pT = kinematics->pT();
// if soft correlations
bool softAllowed = dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations() &&
(ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma);
Energy2 pipj,pik,m12(ZERO),m22(ZERO);
- vector<Energy2> pjk(3,ZERO);
+ array<Energy2,3> pjk = {};
Energy Ei,Ej,Ek;
InvEnergy2 aziMax(ZERO);
if(softAllowed) {
// find the partner for the soft correlations
tShowerParticlePtr partner=findCorrelationPartner(particle,false,splittingFn()->interactionType());
double zFact = (1.-z);
// compute the transforms to the shower reference frame
// first the boost
Lorentz5Momentum pVect = particle.showerBasis()->pVector();
Lorentz5Momentum nVect = particle.showerBasis()->nVector();
assert(particle.showerBasis()->frame()==ShowerBasis::BackToBack);
Boost beta_bb = -(pVect + nVect).boostVector();
pVect.boost(beta_bb);
nVect.boost(beta_bb);
Axis axis = pVect.vect().unit();
// and then the rotation
LorentzRotation rot;
if(axis.perp2()>0.) {
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
}
else if(axis.z()<0.) {
rot.rotate(Constants::pi,Axis(1.,0.,0.));
}
rot.invert();
pVect *= rot;
nVect *= rot;
// shower parameters
Energy2 pn = pVect*nVect;
Energy2 m2 = pVect.m2();
double alpha0 = particle.x();
double beta0 = -0.5/alpha0/pn*sqr(alpha0)*m2;
Lorentz5Momentum pj = partner->momentum();
pj.boost(beta_bb);
pj *= rot;
double beta2 = 0.5*(1.-zFact)*(sqr(alpha0*zFact/(1.-zFact))*m2+sqr(pT))/alpha0/zFact/pn;
// compute the two phi independent dot products
Energy2 dot1 = pj*pVect;
Energy2 dot2 = pj*nVect;
pipj = alpha0*dot1+beta0*dot2;
pik = alpha0*(alpha0*zFact/(1.-zFact)*m2+pn*(beta2+zFact/(1.-zFact)*beta0));
// compute the constants for the phi dependent dot product
pjk[0] = alpha0*zFact/(1.-zFact)*dot1+beta2*dot2;
pjk[1] = pj.x()*pT;
pjk[2] = pj.y()*pT;
m12 = ZERO;
m22 = sqr(partner->dataPtr()->mass());
Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2]));
if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==1) {
aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag);
}
else if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==2) {
Ek = alpha0*zFact/(1.-zFact)*pVect.t()+beta2*nVect.t();
Ei = alpha0*pVect.t()+beta0*nVect.t();
Ej = pj.t();
if(pipj*Ek> Ej*pik) {
aziMax = 0.5/pik/Ek*(Ei-m12*Ek/pik + (pipj*Ek- Ej*pik)/(pjk[0]-mag));
}
else {
aziMax = 0.5/pik/Ek*(Ei-m12*Ek/pik);
}
}
else {
assert(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==0);
}
}
// if spin correlations
vector<pair<int,Complex> > wgts;
if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->spinCorrelations()) {
// get the weights
wgts = splittingFn()->generatePhiBackward(z,t,ids,rho);
}
else {
- wgts = vector<pair<int,Complex> >(1,make_pair(0,1.));
+ wgts = {{ {0, 1.} }};
}
// generate the azimuthal angle
double phi,wgt;
static const Complex ii(0.,1.);
unsigned int ntry(0);
double phiMax(0.),wgtMax(0.);
do {
phi = Constants::twopi*UseRandom::rnd();
Complex spinWgt = 0.;
for(unsigned int ix=0;ix<wgts.size();++ix) {
if(wgts[ix].first==0)
spinWgt += wgts[ix].second;
else
spinWgt += exp(double(wgts[ix].first)*ii*phi)*wgts[ix].second;
}
wgt = spinWgt.real();
if(wgt-1.>1e-10) {
generator()->log() << "Backward weight problem " << wgt << " " << wgt-1.
<< " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << z << " " << phi << "\n";
generator()->log() << "Weights \n";
for(unsigned int ix=0;ix<wgts.size();++ix)
generator()->log() << wgts[ix].first << " " << wgts[ix].second << "\n";
}
// soft correlations bit
double aziWgt = 1.;
if(softAllowed) {
Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi);
if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==1) {
aziWgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax;
}
else if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==2) {
aziWgt = max(ZERO,0.5/pik/Ek*(Ei-m12*Ek/pik + pipj*Ek/dot - Ej*pik/dot)/aziMax);
}
if(aziWgt-1.>1e-10||aziWgt<-1e-10) {
generator()->log() << "Backward soft weight problem " << aziWgt << " " << aziWgt-1.
<< " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n";
}
}
wgt *= aziWgt;
if(wgt>wgtMax) {
phiMax = phi;
wgtMax = wgt;
}
++ntry;
}
while(wgt<UseRandom::rnd()&&ntry<10000);
if(ntry==10000) {
generator()->log() << "Too many tries to generate phi in backward evolution\n";
phi = phiMax;
}
// return the azimuthal angle
return phi;
}
double QTildeSudakov::generatePhiDecay(ShowerParticle & particle,
const IdList & ids,
ShoKinPtr kinematics,
const RhoDMatrix &) {
// only soft correlations in this case
// no correlations, return flat phi
if( !(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations() &&
(ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma )))
return Constants::twopi*UseRandom::rnd();
// get the kinematic variables
double z = kinematics->z();
Energy pT = kinematics->pT();
// if soft correlations
// find the partner for the soft correlations
tShowerParticlePtr partner = findCorrelationPartner(particle,true,splittingFn()->interactionType());
double zFact(1.-z);
// compute the transforms to the shower reference frame
// first the boost
Lorentz5Momentum pVect = particle.showerBasis()->pVector();
Lorentz5Momentum nVect = particle.showerBasis()->nVector();
assert(particle.showerBasis()->frame()==ShowerBasis::Rest);
Boost beta_bb = -pVect.boostVector();
pVect.boost(beta_bb);
nVect.boost(beta_bb);
Axis axis = nVect.vect().unit();
// and then the rotation
LorentzRotation rot;
if(axis.perp2()>0.) {
double sinth(sqrt(sqr(axis.x())+sqr(axis.y())));
rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.));
}
else if(axis.z()<0.) {
rot.rotate(Constants::pi,Axis(1.,0.,0.));
}
rot.invert();
pVect *= rot;
nVect *= rot;
// shower parameters
Energy2 pn = pVect*nVect;
Energy2 m2 = pVect.m2();
double alpha0 = particle.showerParameters().alpha;
double beta0 = 0.5/alpha0/pn*
(sqr(particle.dataPtr()->mass())-sqr(alpha0)*m2+sqr(particle.showerParameters().pt));
Lorentz5Momentum qperp0(particle.showerParameters().ptx,
particle.showerParameters().pty,ZERO,ZERO);
Lorentz5Momentum pj = partner->momentum();
pj.boost(beta_bb);
pj *= rot;
// compute the two phi independent dot products
Energy2 pik = 0.5*zFact*(sqr(alpha0)*m2 - sqr(particle.showerParameters().pt) + 2.*alpha0*beta0*pn )
+0.5*sqr(pT)/zFact;
Energy2 dot1 = pj*pVect;
Energy2 dot2 = pj*nVect;
Energy2 dot3 = pj*qperp0;
Energy2 pipj = alpha0*dot1+beta0*dot2+dot3;
// compute the constants for the phi dependent dot product
- vector<Energy2> pjk(3,ZERO);
+ array<Energy2,3> pjk = {};
pjk[0] = zFact*(alpha0*dot1+dot3-0.5*dot2/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0))
+0.5*sqr(pT)*dot2/pn/zFact/alpha0;
pjk[1] = (pj.x() - dot2/alpha0/pn*qperp0.x())*pT;
pjk[2] = (pj.y() - dot2/alpha0/pn*qperp0.y())*pT;
Energy2 m12 = sqr(particle.dataPtr()->mass());
Energy2 m22 = sqr(partner->dataPtr()->mass());
Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2]));
InvEnergy2 aziMax;
- vector<Energy> Ek(3,ZERO);
+ array<Energy,3> Ek = {};
Energy Ei,Ej;
if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==1) {
aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag);
}
else if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==2) {
Ek[0] = zFact*(alpha0*pVect.t()+-0.5*nVect.t()/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0))
+0.5*sqr(pT)*nVect.t()/pn/zFact/alpha0;
Ek[1] = -nVect.t()/alpha0/pn*qperp0.x()*pT;
Ek[2] = -nVect.t()/alpha0/pn*qperp0.y()*pT;
Energy mag2=sqrt(sqr(Ek[1])+sqr(Ek[2]));
Ei = alpha0*pVect.t()+beta0*nVect.t();
Ej = pj.t();
aziMax = 0.5/pik/(Ek[0]-mag2)*(Ei-m12*(Ek[0]-mag2)/pik + pipj*(Ek[0]+mag2)/(pjk[0]-mag) - Ej*pik/(pjk[0]-mag) );
}
else
assert(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==0);
// generate the azimuthal angle
double phi,wgt(0.);
unsigned int ntry(0);
double phiMax(0.),wgtMax(0.);
do {
phi = Constants::twopi*UseRandom::rnd();
Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi);
if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==1) {
wgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax;
}
else if(dynamic_ptr_cast<tcQTildeShowerHandlerPtr>(ShowerHandler::currentHandler())->softCorrelations()==2) {
if(qperp0.m2()==ZERO) {
wgt = 1.;
}
else {
Energy Eg = Ek[0]+Ek[1]*cos(phi)+Ek[2]*sin(phi);
wgt = max(ZERO,0.5/pik/Eg*(Ei-m12*Eg/pik + (pipj*Eg - Ej*pik)/dot)/aziMax);
}
}
if(wgt-1.>1e-10||wgt<-1e-10) {
generator()->log() << "Decay soft weight problem " << wgt << " " << wgt-1.
<< " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n";
}
if(wgt>wgtMax) {
phiMax = phi;
wgtMax = wgt;
}
++ntry;
}
while(wgt<UseRandom::rnd()&&ntry<10000);
if(ntry==10000) {
phi = phiMax;
generator()->log() << "Too many tries to generate phi\n";
}
// return the azimuthal angle
return phi;
}
Energy QTildeSudakov::calculateScale(double zin, Energy pt, IdList ids,
unsigned int iopt) {
Energy2 tmin;
initialize(ids,tmin);
// final-state branching
if(iopt==0) {
Energy2 scale=(sqr(pt)+masssquared_[1]*(1.-zin)+masssquared_[2]*zin);
if(ids[0]->id()!=ParticleID::g) scale -= zin*(1.-zin)*masssquared_[0];
scale /= sqr(zin*(1-zin));
return scale<=ZERO ? sqrt(tmin) : sqrt(scale);
}
else if(iopt==1) {
Energy2 scale=(sqr(pt)+zin*masssquared_[2])/sqr(1.-zin);
return scale<=ZERO ? sqrt(tmin) : sqrt(scale);
}
else if(iopt==2) {
Energy2 scale = (sqr(pt)+zin*masssquared_[2])/sqr(1.-zin)+masssquared_[0];
return scale<=ZERO ? sqrt(tmin) : sqrt(scale);
}
else {
throw Exception() << "Unknown option in QTildeSudakov::calculateScale() "
<< "iopt = " << iopt << Exception::runerror;
}
}
ShoKinPtr QTildeSudakov::createFinalStateBranching(Energy scale,double z,
double phi, Energy pt) {
ShoKinPtr showerKin = new_ptr(FS_QTildeShowerKinematics1to2());
showerKin->scale(scale);
showerKin->z(z);
showerKin->phi(phi);
showerKin->pT(pt);
showerKin->SudakovFormFactor(this);
return showerKin;
}
ShoKinPtr QTildeSudakov::createInitialStateBranching(Energy scale,double z,
double phi, Energy pt) {
ShoKinPtr showerKin = new_ptr(IS_QTildeShowerKinematics1to2());
showerKin->scale(scale);
showerKin->z(z);
showerKin->phi(phi);
showerKin->pT(pt);
showerKin->SudakovFormFactor(this);
return showerKin;
}
ShoKinPtr QTildeSudakov::createDecayBranching(Energy scale,double z,
double phi, Energy pt) {
ShoKinPtr showerKin = new_ptr(Decay_QTildeShowerKinematics1to2());
showerKin->scale(scale);
showerKin->z(z);
showerKin->phi(phi);
showerKin->pT(pt);
showerKin->SudakovFormFactor(this);
return showerKin;
}
diff --git a/Shower/QTilde/Makefile.am b/Shower/QTilde/Makefile.am
--- a/Shower/QTilde/Makefile.am
+++ b/Shower/QTilde/Makefile.am
@@ -1,46 +1,46 @@
SUBDIRS = Matching
pkglib_LTLIBRARIES = HwShower.la
-HwShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 25:0:0
+HwShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 25:1:0
HwShower_la_SOURCES = \
Couplings/ShowerAlphaQCD.h Couplings/ShowerAlphaQCD.cc \
Couplings/ShowerAlphaQED.h Couplings/ShowerAlphaQED.cc\
QTildeShowerHandler.h QTildeShowerHandler.fh QTildeShowerHandler.cc \
SplittingFunctions/HalfHalfOneSplitFn.h SplittingFunctions/HalfHalfOneSplitFn.cc\
SplittingFunctions/HalfHalfOneEWSplitFn.h SplittingFunctions/HalfHalfOneEWSplitFn.cc\
SplittingFunctions/OneOneOneSplitFn.h SplittingFunctions/OneOneOneSplitFn.cc\
SplittingFunctions/OneOneOneMassiveSplitFn.h SplittingFunctions/OneOneOneMassiveSplitFn.cc\
SplittingFunctions/ZeroZeroOneSplitFn.h SplittingFunctions/ZeroZeroOneSplitFn.cc\
SplittingFunctions/OneHalfHalfSplitFn.h SplittingFunctions/OneHalfHalfSplitFn.cc\
SplittingFunctions/HalfOneHalfSplitFn.h SplittingFunctions/HalfOneHalfSplitFn.cc\
SplittingFunctions/CMWOneOneOneSplitFn.h SplittingFunctions/CMWOneOneOneSplitFn.cc\
SplittingFunctions/CMWHalfHalfOneSplitFn.h SplittingFunctions/CMWHalfHalfOneSplitFn.cc\
Default/QTildeSudakov.cc Default/QTildeSudakov.h\
Default/QTildeModel.cc Default/QTildeModel.h\
Default/Decay_QTildeShowerKinematics1to2.cc \
Default/Decay_QTildeShowerKinematics1to2.h \
Default/IS_QTildeShowerKinematics1to2.cc Default/IS_QTildeShowerKinematics1to2.h \
Default/FS_QTildeShowerKinematics1to2.cc Default/FS_QTildeShowerKinematics1to2.h \
Default/QTildeFinder.cc Default/QTildeFinder.h\
Default/QTildeReconstructor.cc Default/QTildeReconstructor.h Default/QTildeReconstructor.tcc \
Base/KinematicsReconstructor.cc \
Base/KinematicsReconstructor.h \
Base/KinematicsReconstructor.fh \
Base/ShowerModel.cc Base/ShowerModel.h Base/ShowerModel.fh \
Base/HardTree.cc Base/HardTree.h Base/HardTree.fh \
Base/HardBranching.h Base/HardBranching.fh Base/HardBranching.cc\
Base/PartnerFinder.h Base/PartnerFinder.fh Base/PartnerFinder.cc \
Base/ShowerVeto.h Base/ShowerVeto.fh Base/ShowerVeto.cc \
Base/FullShowerVeto.h Base/FullShowerVeto.fh Base/FullShowerVeto.cc \
SplittingFunctions/SplittingGenerator.cc SplittingFunctions/SplittingGenerator.h\
SplittingFunctions/SplittingGenerator.fh \
Base/ShowerTree.h Base/ShowerTree.fh Base/ShowerTree.cc \
ShowerConfig.h ShowerConfig.cc \
Base/Branching.h \
Base/ShowerParticle.cc Base/ShowerParticle.fh Base/ShowerParticle.h \
Base/ShowerKinematics.fh Base/ShowerKinematics.h Base/ShowerKinematics.cc \
Base/ShowerBasis.fh Base/ShowerBasis.h Base/ShowerBasis.cc \
Base/ShowerProgenitor.fh Base/ShowerProgenitor.h \
Base/SudakovFormFactor.cc Base/SudakovFormFactor.h Base/SudakovFormFactor.fh \
SplittingFunctions/SplittingFunction.h SplittingFunctions/SplittingFunction.fh \
SplittingFunctions/SplittingFunction.cc \
Base/ShowerVertex.cc Base/ShowerVertex.fh Base/ShowerVertex.h
diff --git a/Shower/QTilde/QTildeShowerHandler.cc b/Shower/QTilde/QTildeShowerHandler.cc
--- a/Shower/QTilde/QTildeShowerHandler.cc
+++ b/Shower/QTilde/QTildeShowerHandler.cc
@@ -1,3746 +1,3746 @@
// -*- C++ -*-
//
// QTildeShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
// This is the implementation of the non-inlined, non-templated member
// functions of the QTildeShowerHandler class.
//
#include "QTildeShowerHandler.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/EventRecord/Particle.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Utilities/EnumIO.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/PDF/MPIPDF.h"
#include "Herwig/PDF/MinBiasPDF.h"
#include "Herwig/Shower/QTilde/Base/ShowerTree.h"
#include "Herwig/Shower/QTilde/Base/HardTree.h"
#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h"
#include "Herwig/Shower/QTilde/Base/PartnerFinder.h"
#include "Herwig/PDF/HwRemDecayer.h"
#include "Herwig/Shower/QTilde/Base/ShowerVertex.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h"
#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h"
#include "ThePEG/PDF/PartonExtractor.h"
#include "Herwig/Shower/RealEmissionProcess.h"
using namespace Herwig;
bool QTildeShowerHandler::_hardEmissionWarn = true;
bool QTildeShowerHandler::_missingTruncWarn = true;
QTildeShowerHandler::QTildeShowerHandler() :
_maxtry(100), _meCorrMode(1), _reconOpt(0),
_hardVetoReadOption(false),
_iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(),
_limitEmissions(0), _initialenhance(1.), _finalenhance(1.),
_nReWeight(100), _reWeight(false),
interaction_(ShowerInteraction::QEDQCD),
_trunc_Mode(true), _hardEmission(1),
_spinOpt(1), _softOpt(2), _hardPOWHEG(false), muPt(ZERO),
_maxTryFSR(100000), _maxFailFSR(100), _fracFSR(0.001),
_nFSR(0), _nFailedFSR(0)
{}
QTildeShowerHandler::~QTildeShowerHandler() {}
IBPtr QTildeShowerHandler::clone() const {
return new_ptr(*this);
}
IBPtr QTildeShowerHandler::fullclone() const {
return new_ptr(*this);
}
void QTildeShowerHandler::persistentOutput(PersistentOStream & os) const {
os << _model << _splittingGenerator << _maxtry
<< _meCorrMode << _hardVetoReadOption
<< _limitEmissions << _spinOpt << _softOpt << _hardPOWHEG
<< ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV)
<< _vetoes << _fullShowerVetoes << _nReWeight << _reWeight
<< _trunc_Mode << _hardEmission << _reconOpt
<< ounit(muPt,GeV)
<< oenum(interaction_) << _maxTryFSR << _maxFailFSR << _fracFSR;
}
void QTildeShowerHandler::persistentInput(PersistentIStream & is, int) {
is >> _model >> _splittingGenerator >> _maxtry
>> _meCorrMode >> _hardVetoReadOption
>> _limitEmissions >> _spinOpt >> _softOpt >> _hardPOWHEG
>> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV)
>> _vetoes >> _fullShowerVetoes >> _nReWeight >> _reWeight
>> _trunc_Mode >> _hardEmission >> _reconOpt
>> iunit(muPt,GeV)
>> ienum(interaction_) >> _maxTryFSR >> _maxFailFSR >> _fracFSR;
}
// The following static variable is needed for the type
// description system in ThePEG.
DescribeClass<QTildeShowerHandler,ShowerHandler>
describeHerwigQTildeShowerHandler("Herwig::QTildeShowerHandler", "HwShower.so");
void QTildeShowerHandler::Init() {
static ClassDocumentation<QTildeShowerHandler> documentation
("TheQTildeShowerHandler class is the main class"
" for the angular-ordered parton shower",
"The Shower evolution was performed using an algorithm described in "
"\\cite{Marchesini:1983bm,Marchesini:1987cf,Gieseke:2003rz,Bahr:2008pv}.",
"%\\cite{Marchesini:1983bm}\n"
"\\bibitem{Marchesini:1983bm}\n"
" G.~Marchesini and B.~R.~Webber,\n"
" ``Simulation Of QCD Jets Including Soft Gluon Interference,''\n"
" Nucl.\\ Phys.\\ B {\\bf 238}, 1 (1984).\n"
" %%CITATION = NUPHA,B238,1;%%\n"
"%\\cite{Marchesini:1987cf}\n"
"\\bibitem{Marchesini:1987cf}\n"
" G.~Marchesini and B.~R.~Webber,\n"
" ``Monte Carlo Simulation of General Hard Processes with Coherent QCD\n"
" Radiation,''\n"
" Nucl.\\ Phys.\\ B {\\bf 310}, 461 (1988).\n"
" %%CITATION = NUPHA,B310,461;%%\n"
"%\\cite{Gieseke:2003rz}\n"
"\\bibitem{Gieseke:2003rz}\n"
" S.~Gieseke, P.~Stephens and B.~Webber,\n"
" ``New formalism for QCD parton showers,''\n"
" JHEP {\\bf 0312}, 045 (2003)\n"
" [arXiv:hep-ph/0310083].\n"
" %%CITATION = JHEPA,0312,045;%%\n"
);
static Reference<QTildeShowerHandler,SplittingGenerator>
interfaceSplitGen("SplittingGenerator",
"A reference to the SplittingGenerator object",
&Herwig::QTildeShowerHandler::_splittingGenerator,
false, false, true, false);
static Reference<QTildeShowerHandler,ShowerModel> interfaceShowerModel
("ShowerModel",
"The pointer to the object which defines the shower evolution model.",
&QTildeShowerHandler::_model, false, false, true, false, false);
static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxTry
("MaxTry",
"The maximum number of attempts to generate the shower from a"
" particular ShowerTree",
&QTildeShowerHandler::_maxtry, 100, 1, 100000,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler,unsigned int> interfaceNReWeight
("NReWeight",
"The number of attempts for the shower when reweighting",
&QTildeShowerHandler::_nReWeight, 100, 10, 10000,
false, false, Interface::limited);
static Switch<QTildeShowerHandler, unsigned int> ifaceMECorrMode
("MECorrMode",
"Choice of the ME Correction Mode",
&QTildeShowerHandler::_meCorrMode, 1, false, false);
static SwitchOption on
(ifaceMECorrMode,"HardPlusSoft","hard+soft on", 1);
static SwitchOption hard
(ifaceMECorrMode,"Hard","only hard on", 2);
static SwitchOption soft
(ifaceMECorrMode,"Soft","only soft on", 3);
static Switch<QTildeShowerHandler, bool> ifaceHardVetoReadOption
("HardVetoReadOption",
"Apply read-in scale veto to all collisions or just the primary one?",
&QTildeShowerHandler::_hardVetoReadOption, false, false, false);
static SwitchOption AllCollisions
(ifaceHardVetoReadOption,
"AllCollisions",
"Read-in pT veto applied to primary and secondary collisions.",
false);
static SwitchOption PrimaryCollision
(ifaceHardVetoReadOption,
"PrimaryCollision",
"Read-in pT veto applied to primary but not secondary collisions.",
true);
static Parameter<QTildeShowerHandler, Energy> ifaceiptrms
("IntrinsicPtGaussian",
"RMS of intrinsic pT of Gaussian distribution:\n"
"2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)",
&QTildeShowerHandler::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler, double> ifacebeta
("IntrinsicPtBeta",
"Proportion of inverse quadratic distribution in generating intrinsic pT.\n"
"(1-Beta) is the proportion of Gaussian distribution",
&QTildeShowerHandler::_beta, 0, 0, 1,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler, Energy> ifacegamma
("IntrinsicPtGamma",
"Parameter for inverse quadratic:\n"
"2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))",
&QTildeShowerHandler::_gamma,GeV, ZERO, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler, Energy> ifaceiptmax
("IntrinsicPtIptmax",
"Upper bound on intrinsic pT for inverse quadratic",
&QTildeShowerHandler::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static RefVector<QTildeShowerHandler,ShowerVeto> ifaceVetoes
("Vetoes",
"The vetoes to be checked during showering",
&QTildeShowerHandler::_vetoes, -1,
false,false,true,true,false);
static RefVector<QTildeShowerHandler,FullShowerVeto> interfaceFullShowerVetoes
("FullShowerVetoes",
"The vetos to be appliede on the full final state of the shower",
&QTildeShowerHandler::_fullShowerVetoes, -1, false, false, true, false, false);
static Switch<QTildeShowerHandler,unsigned int> interfaceLimitEmissions
("LimitEmissions",
"Limit the number and type of emissions for testing",
&QTildeShowerHandler::_limitEmissions, 0, false, false);
static SwitchOption interfaceLimitEmissionsNoLimit
(interfaceLimitEmissions,
"NoLimit",
"Allow an arbitrary number of emissions",
0);
static SwitchOption interfaceLimitEmissionsOneInitialStateEmission
(interfaceLimitEmissions,
"OneInitialStateEmission",
"Allow one emission in the initial state and none in the final state",
1);
static SwitchOption interfaceLimitEmissionsOneFinalStateEmission
(interfaceLimitEmissions,
"OneFinalStateEmission",
"Allow one emission in the final state and none in the initial state",
2);
static SwitchOption interfaceLimitEmissionsHardOnly
(interfaceLimitEmissions,
"HardOnly",
"Only allow radiation from the hard ME correction",
3);
static SwitchOption interfaceLimitEmissionsOneEmission
(interfaceLimitEmissions,
"OneEmission",
"Allow one emission in either the final state or initial state, but not both",
4);
static Switch<QTildeShowerHandler,bool> interfaceTruncMode
("TruncatedShower", "Include the truncated shower?",
&QTildeShowerHandler::_trunc_Mode, 1, false, false);
static SwitchOption interfaceTruncMode0
(interfaceTruncMode,"No","Truncated Shower is OFF", 0);
static SwitchOption interfaceTruncMode1
(interfaceTruncMode,"Yes","Truncated Shower is ON", 1);
static Switch<QTildeShowerHandler,int> interfaceHardEmission
("HardEmission",
"Whether to use ME corrections or POWHEG for the hardest emission",
&QTildeShowerHandler::_hardEmission, 0, false, false);
static SwitchOption interfaceHardEmissionNone
(interfaceHardEmission,
"None",
"No Corrections",
0);
static SwitchOption interfaceHardEmissionMECorrection
(interfaceHardEmission,
"MECorrection",
"Old fashioned ME correction",
1);
static SwitchOption interfaceHardEmissionPOWHEG
(interfaceHardEmission,
"POWHEG",
"Powheg style hard emission",
2);
static Switch<QTildeShowerHandler,ShowerInteraction> interfaceInteractions
("Interactions",
"The interactions to be used in the shower",
&QTildeShowerHandler::interaction_, ShowerInteraction::QEDQCD, false, false);
static SwitchOption interfaceInteractionsQCD
(interfaceInteractions,
"QCD",
"Only QCD radiation",
ShowerInteraction::QCD);
static SwitchOption interfaceInteractionsQED
(interfaceInteractions,
"QED",
"Only QEd radiation",
ShowerInteraction::QED);
static SwitchOption interfaceInteractionEWOnly
(interfaceInteractions,
"EWOnly",
"Only EW",
ShowerInteraction::EW);
static SwitchOption interfaceInteractionQEDQCD
(interfaceInteractions,
"QEDQCD",
"QED and QCD",
ShowerInteraction::QEDQCD);
static SwitchOption interfaceInteractionALL
(interfaceInteractions,
"ALL",
"QED, QCD and EW",
ShowerInteraction::ALL);
static Switch<QTildeShowerHandler,unsigned int> interfaceReconstructionOption
("ReconstructionOption",
"Treatment of the reconstruction of the transverse momentum of "
"a branching from the evolution scale.",
&QTildeShowerHandler::_reconOpt, 0, false, false);
static SwitchOption interfaceReconstructionOptionCutOff
(interfaceReconstructionOption,
"CutOff",
"Use the cut-off masses in the calculation",
0);
static SwitchOption interfaceReconstructionOptionOffShell
(interfaceReconstructionOption,
"OffShell",
"Use the off-shell masses in the calculation veto the emission of the parent,"
" no veto in generation of emissions from children",
1);
static SwitchOption interfaceReconstructionOptionOffShell2
(interfaceReconstructionOption,
"OffShell2",
"Use the off-shell masses in the calculation veto the emissions from the children."
" no veto in generation of emissions from children",
2);
static SwitchOption interfaceReconstructionOptionOffShell3
(interfaceReconstructionOption,
"OffShell3",
"Use the off-shell masses in the calculation veto the emissions from the children."
" veto in generation of emissions from children using cut-off for second parton",
3);
static SwitchOption interfaceReconstructionOptionOffShell4
(interfaceReconstructionOption,
"OffShell4",
"As OffShell3 but with a restriction on the mass of final-state"
" jets produced via backward evolution.",
4);
static SwitchOption interfaceReconstructionOptionOffShell5
(interfaceReconstructionOption,
"OffShell5",
"Try and preserve q2 but if pt negative just zero it",
5);
static Switch<QTildeShowerHandler,unsigned int> interfaceSpinCorrelations
("SpinCorrelations",
"Treatment of spin correlations in the parton shower",
&QTildeShowerHandler::_spinOpt, 1, false, false);
static SwitchOption interfaceSpinCorrelationsNo
(interfaceSpinCorrelations,
"No",
"No spin correlations",
0);
static SwitchOption interfaceSpinCorrelationsSpin
(interfaceSpinCorrelations,
"Yes",
"Include the azimuthal spin correlations only",
1);
static Switch<QTildeShowerHandler,unsigned int> interfaceSoftCorrelations
("SoftCorrelations",
"Option for the treatment of soft correlations in the parton shower",
&QTildeShowerHandler::_softOpt, 2, false, false);
static SwitchOption interfaceSoftCorrelationsNone
(interfaceSoftCorrelations,
"No",
"No soft correlations",
0);
static SwitchOption interfaceSoftCorrelationsFull
(interfaceSoftCorrelations,
"Full",
"Use the full eikonal",
1);
static SwitchOption interfaceSoftCorrelationsSingular
(interfaceSoftCorrelations,
"Singular",
"Use original Webber-Marchisini form",
2);
static Switch<QTildeShowerHandler,bool> interfaceHardPOWHEG
("HardPOWHEG",
"Treatment of powheg emissions which are too hard to have a shower interpretation",
&QTildeShowerHandler::_hardPOWHEG, false, false, false);
static SwitchOption interfaceHardPOWHEGAsShower
(interfaceHardPOWHEG,
"AsShower",
"Still interpret as shower emissions",
false);
static SwitchOption interfaceHardPOWHEGRealEmission
(interfaceHardPOWHEG,
"RealEmission",
"Generate shower from the real emmission configuration",
true);
static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxTryFSR
("MaxTryFSR",
"The maximum number of attempted FSR emissions in"
" the generation of the FSR",
&QTildeShowerHandler::_maxTryFSR, 100000, 10, 100000000,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxFailFSR
("MaxFailFSR",
"Maximum number of failures generating the FSR",
&QTildeShowerHandler::_maxFailFSR, 100, 1, 100000000,
false, false, Interface::limited);
static Parameter<QTildeShowerHandler,double> interfaceFSRFailureFraction
("FSRFailureFraction",
"Maximum fraction of events allowed to fail due to too many FSR emissions",
&QTildeShowerHandler::_fracFSR, 0.001, 1e-10, 1,
false, false, Interface::limited);
}
tPPair QTildeShowerHandler::cascade(tSubProPtr sub,
XCPtr xcomb) {
// use me for reference in tex file etc
useMe();
prepareCascade(sub);
// set things up in the base class
resetWeights();
hard_=ShowerTreePtr();
decay_.clear();
done_.clear();
// check if anything needs doing
if ( !doFSR() && ! doISR() )
return sub->incoming();
// start of the try block for the whole showering process
unsigned int countFailures=0;
while (countFailures<maxtry()) {
try {
decay_.clear();
done_.clear();
PerturbativeProcessPtr hard;
DecayProcessMap decay;
splitHardProcess(firstInteraction() ? tagged() :
tPVector(currentSubProcess()->outgoing().begin(),
currentSubProcess()->outgoing().end()),
hard,decay);
ShowerTree::constructTrees(hard_,decay_,hard,decay);
// if no hard process
if(!hard_) throw Exception() << "Shower starting with a decay"
<< "is not implemented"
<< Exception::runerror;
// perform the shower for the hard process
showerHardProcess(hard_,xcomb);
done_.push_back(hard_);
hard_->updateAfterShower(decay_);
// if no decaying particles to shower break out of the loop
if(decay_.empty()) break;
// shower the decay products
while(!decay_.empty()) {
// find particle whose production process has been showered
ShowerDecayMap::iterator dit = decay_.begin();
while(!dit->second->parent()->hasShowered() && dit!=decay_.end()) ++dit;
assert(dit!=decay_.end());
// get the particle
ShowerTreePtr decayingTree = dit->second;
// remove it from the multimap
decay_.erase(dit);
// make sure the particle has been decayed
QTildeShowerHandler::decay(decayingTree,decay_);
// now shower the decay
showerDecay(decayingTree);
done_.push_back(decayingTree);
decayingTree->updateAfterShower(decay_);
}
// suceeded break out of the loop
break;
}
catch (KinematicsReconstructionVeto) {
resetWeights();
++countFailures;
}
catch ( ... ) {
hard_=ShowerTreePtr();
decay_.clear();
done_.clear();
throw;
}
}
// if loop exited because of too many tries, throw event away
if (countFailures >= maxtry()) {
resetWeights();
hard_=ShowerTreePtr();
decay_.clear();
done_.clear();
throw Exception() << "Too many tries for main while loop "
<< "in QTildeShowerHandler::cascade()."
<< Exception::eventerror;
}
//enter the particles in the event record
fillEventRecord();
// clear storage
hard_=ShowerTreePtr();
decay_.clear();
done_.clear();
// non hadronic case return
if (!isResolvedHadron(incomingBeams().first ) &&
!isResolvedHadron(incomingBeams().second) )
return incomingBeams();
// remake the remnants (needs to be after the colours are sorted
// out in the insertion into the event record)
if ( firstInteraction() ) return remakeRemnant(sub->incoming());
//Return the new pair of incoming partons. remakeRemnant is not
//necessary here, because the secondary interactions are not yet
//connected to the remnants.
return make_pair(findFirstParton(sub->incoming().first ),
findFirstParton(sub->incoming().second));
}
void QTildeShowerHandler::fillEventRecord() {
// create a new step
StepPtr pstep = newStep();
assert(!done_.empty());
assert(done_[0]->isHard());
// insert the steps
for(unsigned int ix=0;ix<done_.size();++ix) {
done_[ix]->fillEventRecord(pstep,doISR(),doFSR());
}
}
HardTreePtr QTildeShowerHandler::generateCKKW(ShowerTreePtr ) const {
return HardTreePtr();
}
void QTildeShowerHandler::doinit() {
ShowerHandler::doinit();
// interactions may have been changed through a setup file so we
// clear it up here
// calculate max no of FSR vetos
_maxFailFSR = max(int(_maxFailFSR), int(_fracFSR*double(generator()->N())));
// check on the reweighting
for(unsigned int ix=0;ix<_fullShowerVetoes.size();++ix) {
if(_fullShowerVetoes[ix]->behaviour()==1) {
_reWeight = true;
break;
}
}
if(_reWeight && maximumTries()<_nReWeight) {
throw Exception() << "Reweight being performed in the shower but the number of attempts for the"
<< "shower is less than that for the reweighting.\n"
<< "Maximum number of attempt for the shower "
<< fullName() << ":MaxTry is " << maximumTries() << "\nand for reweighting is "
<< fullName() << ":NReWeight is " << _nReWeight << "\n"
<< "we recommend the number of attempts is 10 times the number for reweighting\n"
<< Exception::runerror;
}
ShowerTree::_vmin2 = vMin();
ShowerTree::_spaceTime = includeSpaceTime();
}
void QTildeShowerHandler::doinitrun() {
ShowerHandler::doinitrun();
ShowerTree::_vmin2 = vMin();
ShowerTree::_spaceTime = includeSpaceTime();
}
void QTildeShowerHandler::generateIntrinsicpT(vector<ShowerProgenitorPtr> particlesToShower) {
_intrinsic.clear();
if ( !ipTon() || !doISR() ) return;
// don't do anything for the moment for secondary scatters
if( !firstInteraction() ) return;
// generate intrinsic pT
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
// only consider initial-state particles
if(particlesToShower[ix]->progenitor()->isFinalState()) continue;
if(!particlesToShower[ix]->progenitor()->dataPtr()->coloured()) continue;
Energy ipt;
if(UseRandom::rnd() > _beta) {
ipt=_iptrms*sqrt(-log(UseRandom::rnd()));
}
else {
ipt=_gamma*sqrt(pow(1.+sqr(_iptmax/_gamma), UseRandom::rnd())-1.);
}
pair<Energy,double> pt = make_pair(ipt,UseRandom::rnd(Constants::twopi));
_intrinsic[particlesToShower[ix]] = pt;
}
}
void QTildeShowerHandler::setupMaximumScales(const vector<ShowerProgenitorPtr> & p,
XCPtr xcomb) {
// let POWHEG events radiate freely
if(_hardEmission==2&&hardTree()) {
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy);
return;
}
// return if no vetos
if (!restrictPhasespace()) return;
// find out if hard partonic subprocess.
bool isPartonic(false);
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit = _currenttree->incomingLines().begin();
Lorentz5Momentum pcm;
for(; cit!=currentTree()->incomingLines().end(); ++cit) {
pcm += cit->first->progenitor()->momentum();
isPartonic |= cit->first->progenitor()->coloured();
}
// find minimum pt from hard process, the maximum pt from all outgoing
// coloured lines (this is simpler and more general than
// 2stu/(s^2+t^2+u^2)). Maximum scale for scattering processes will
// be transverse mass.
Energy ptmax = generator()->maximumCMEnergy();
// general case calculate the scale
if ( !hardScaleIsMuF() || (hardVetoReadOption()&&!firstInteraction()) ) {
// scattering process
if(currentTree()->isHard()) {
assert(xcomb);
// coloured incoming particles
if (isPartonic) {
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt = currentTree()->outgoingLines().begin();
for(; cjt!=currentTree()->outgoingLines().end(); ++cjt) {
if (cjt->first->progenitor()->coloured())
ptmax = min(ptmax,cjt->first->progenitor()->momentum().mt());
}
}
if (ptmax == generator()->maximumCMEnergy() ) ptmax = pcm.m();
if(hardScaleIsMuF()&&hardVetoReadOption()&&
!firstInteraction()) {
ptmax=min(ptmax,sqrt(xcomb->lastShowerScale()));
}
}
// decay, incoming() is the decaying particle.
else {
ptmax = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
}
// hepeup.SCALUP is written into the lastXComb by the
// LesHouchesReader itself - use this by user's choice.
// Can be more general than this.
else {
if(currentTree()->isHard()) {
assert(xcomb);
ptmax = sqrt( xcomb->lastShowerScale() );
}
else {
ptmax = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
}
ptmax *= hardScaleFactor();
// set maxHardPt for all progenitors. For partonic processes this
// is now the max pt in the FS, for non-partonic processes or
// processes with no coloured FS the invariant mass of the IS
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(ptmax);
}
void QTildeShowerHandler::setupHardScales(const vector<ShowerProgenitorPtr> & p,
XCPtr xcomb) {
if ( hardScaleIsMuF() &&
(!hardVetoReadOption() || firstInteraction()) ) {
Energy hardScale = ZERO;
if(currentTree()->isHard()) {
assert(xcomb);
hardScale = sqrt( xcomb->lastShowerScale() );
}
else {
hardScale = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
hardScale *= hardScaleFactor();
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale);
muPt = hardScale;
}
}
void QTildeShowerHandler::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) {
_hardme = HwMEBasePtr();
// extract the matrix element
tStdXCombPtr lastXC = dynamic_ptr_cast<tStdXCombPtr>(xcomb);
if(lastXC) {
_hardme = dynamic_ptr_cast<HwMEBasePtr>(lastXC->matrixElement());
}
_decayme = HwDecayerBasePtr();
// set the current tree
currentTree(hard);
hardTree(HardTreePtr());
// work out the type of event
currentTree()->xcombPtr(dynamic_ptr_cast<StdXCombPtr>(xcomb));
currentTree()->identifyEventType();
checkFlags();
// generate the showering
doShowering(true,xcomb);
}
RealEmissionProcessPtr QTildeShowerHandler::hardMatrixElementCorrection(bool hard) {
// set the initial enhancement factors for the soft correction
_initialenhance = 1.;
_finalenhance = 1.;
// see if we can get the correction from the matrix element
// or decayer
RealEmissionProcessPtr real;
if(hard) {
if(_hardme&&_hardme->hasMECorrection()) {
_hardme->initializeMECorrection(_currenttree->perturbativeProcess(),
_initialenhance,_finalenhance);
if(hardMEC())
real =
_hardme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess());
}
}
else {
if(_decayme&&_decayme->hasMECorrection()) {
_decayme->initializeMECorrection(_currenttree->perturbativeProcess(),
_initialenhance,_finalenhance);
if(hardMEC())
real = _decayme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess());
}
}
return real;
}
ShowerParticleVector QTildeShowerHandler::createTimeLikeChildren(tShowerParticlePtr, IdList ids) {
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
ShowerParticleVector children;
for(unsigned int ix=0;ix<2;++ix) {
children.push_back(new_ptr(ShowerParticle(ids[ix+1],true)));
- if(children[ix]->id()==_progenitor->id()&&!ids[ix+1]->stable())
+ if(children[ix]->id()==_progenitor->id()&&!ids[ix+1]->stable()&&abs(ids[ix+1]->id())!=ParticleID::tauminus)
children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass()));
else
children[ix]->set5Momentum(Lorentz5Momentum(ids[ix+1]->mass()));
}
return children;
}
bool QTildeShowerHandler::timeLikeShower(tShowerParticlePtr particle,
ShowerInteraction type,
Branching fb, bool first) {
// don't do anything if not needed
if(_limitEmissions == 1 || hardOnly() ||
( _limitEmissions == 2 && _nfs != 0) ||
( _limitEmissions == 4 && _nfs + _nis != 0) ) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
// too many tries
if(_nFSR>=_maxTryFSR) {
++_nFailedFSR;
// too many failed events
if(_nFailedFSR>=_maxFailFSR)
throw Exception() << "Too many events have failed due to too many shower emissions, in\n"
<< "QTildeShowerHandler::timeLikeShower(). Terminating run\n"
<< Exception::runerror;
throw Exception() << "Too many attempted emissions in QTildeShowerHandler::timeLikeShower()\n"
<< Exception::eventerror;
}
// generate the emission
ShowerParticleVector children;
int ntry=0;
// generate the emission
if(!fb.kinematics)
fb = selectTimeLikeBranching(particle,type,HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
fc[0] = Branching();
fc[1] = Branching();
++ntry;
assert(fb.kinematics);
// has emitted
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
particle->showerKinematics(fb.kinematics);
// check highest pT
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the children
children = createTimeLikeChildren(particle,fb.ids);
// update the children
particle->showerKinematics()->
updateChildren(particle, children,fb.type,_reconOpt==3 || _reconOpt==4);
// update number of emissions
++_nfs;
if(_limitEmissions!=0) {
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
setupChildren = false;
}
// select branchings for children
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
// old default
if(_reconOpt==0||_reconOpt==5) {
break;
}
// all other options
else {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics) {
const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids);
Energy2 q2 =
fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale());
if(fc[ix].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]);
masses[ix+1] = sqrt(q2);
}
else {
masses[ix+1] = virtualMasses[ix+1];
}
}
masses[0] = fb.ids[0]->id()!=ParticleID::g ? virtualMasses[0] : ZERO;
double z = fb.kinematics->z();
Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0]))
- sqr(masses[1])*(1.-z) - sqr(masses[2])*z;
if(pt2>=ZERO) break;
// clean up the vetoed emission
if(_reconOpt==1) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectTimeLikeBranching(particle,type,HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
setupChildren = true;
continue;
}
// clean up vetoed children
else if(_reconOpt>=2) {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
children[ix]->virtualMass(ZERO);
}
}
}
};
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
if(_reconOpt>=1)
particle->showerKinematics()->updateParent(particle, children,fb.type);
// branching has happened
if(first&&!children.empty())
particle->showerKinematics()->resetChildren(particle,children);
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
bool
QTildeShowerHandler::spaceLikeShower(tShowerParticlePtr particle, PPtr beam,
ShowerInteraction type) {
//using the pdf's associated with the ShowerHandler assures, that
//modified pdf's are used for the secondary interactions via
//CascadeHandler::resetPDFs(...)
tcPDFPtr pdf;
if(firstPDF().particle() == _beam)
pdf = firstPDF().pdf();
if(secondPDF().particle() == _beam)
pdf = secondPDF().pdf();
Energy freeze = pdfFreezingScale();
// don't do anything if not needed
if(_limitEmissions == 2 || hardOnly() ||
( _limitEmissions == 1 && _nis != 0 ) ||
( _limitEmissions == 4 && _nis + _nfs != 0 ) ) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
Branching bb;
// generate branching
while (true) {
bb=_splittingGenerator->chooseBackwardBranching(*particle,beam,
_initialenhance,
_beam,type,
pdf,freeze);
// return if no emission
if(!bb.kinematics) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
// if not vetoed break
if(!spaceLikeVetoed(bb,particle)) break;
// otherwise reset scale and continue
particle->vetoEmission(bb.type,bb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
}
// assign the splitting function and shower kinematics
particle->showerKinematics(bb.kinematics);
if(bb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(bb.kinematics->pT());
// For the time being we are considering only 1->2 branching
// particles as in Sudakov form factor
tcPDPtr part[2]={bb.ids[0],bb.ids[2]};
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent = new_ptr(ShowerParticle(part[0],false));
ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true));
ShowerParticleVector theChildren;
theChildren.push_back(particle);
theChildren.push_back(otherChild);
//this updates the evolution scale
particle->showerKinematics()->
updateParent(newParent, theChildren,bb.type);
// update the history if needed
_currenttree->updateInitialStateShowerProduct(_progenitor,newParent);
_currenttree->addInitialStateBranching(particle,newParent,otherChild);
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
++_nis;
bool emitted = _limitEmissions==0 ?
spaceLikeShower(newParent,beam,type) : false;
if(newParent->spinInfo()) newParent->spinInfo()->develop();
// now reconstruct the momentum
if(!emitted) {
if(_intrinsic.find(_progenitor)==_intrinsic.end()) {
bb.kinematics->updateLast(newParent,ZERO,ZERO);
}
else {
pair<Energy,double> kt=_intrinsic[_progenitor];
bb.kinematics->updateLast(newParent,
kt.first*cos(kt.second),
kt.first*sin(kt.second));
}
}
particle->showerKinematics()->
updateChildren(newParent, theChildren,bb.type,_reconOpt>=4);
if(_limitEmissions!=0) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
// perform the shower of the final-state particle
timeLikeShower(otherChild,type,Branching(),true);
updateHistory(otherChild);
if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop();
// return the emitted
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
void QTildeShowerHandler::showerDecay(ShowerTreePtr decay) {
// work out the type of event
currentTree()->xcombPtr(StdXCombPtr());
currentTree()->identifyEventType();
_decayme = HwDecayerBasePtr();
_hardme = HwMEBasePtr();
// find the decayer
// try the normal way if possible
tDMPtr dm = decay->incomingLines().begin()->first->original() ->decayMode();
if(!dm) dm = decay->incomingLines().begin()->first->copy() ->decayMode();
if(!dm) dm = decay->incomingLines().begin()->first->progenitor()->decayMode();
// otherwise make a string and look it up
if(!dm) {
string tag = decay->incomingLines().begin()->first->original()->dataPtr()->name()
+ "->";
OrderedParticles outgoing;
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
it=decay->outgoingLines().begin();it!=decay->outgoingLines().end();++it) {
if(abs(decay->incomingLines().begin()->first->original()->id()) == ParticleID::t &&
abs(it->first->original()->id())==ParticleID::Wplus &&
decay->treelinks().size() == 1) {
ShowerTreePtr Wtree = decay->treelinks().begin()->first;
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
it2=Wtree->outgoingLines().begin();it2!=Wtree->outgoingLines().end();++it2) {
outgoing.insert(it2->first->original()->dataPtr());
}
}
else {
outgoing.insert(it->first->original()->dataPtr());
}
}
for(OrderedParticles::const_iterator it=outgoing.begin(); it!=outgoing.end();++it) {
if(it!=outgoing.begin()) tag += ",";
tag +=(**it).name();
}
tag += ";";
dm = findDecayMode(tag);
}
if(dm) _decayme = dynamic_ptr_cast<HwDecayerBasePtr>(dm->decayer());
// set the ShowerTree to be showered
currentTree(decay);
decay->applyTransforms();
hardTree(HardTreePtr());
// generate the showering
doShowering(false,XCPtr());
// if no vetos
// force calculation of spin correlations
SpinPtr spInfo = decay->incomingLines().begin()->first->progenitor()->spinInfo();
if(spInfo) {
if(!spInfo->developed()) spInfo->needsUpdate();
spInfo->develop();
}
}
bool QTildeShowerHandler::spaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass,ShowerInteraction type,
Branching fb) {
// don't do anything if not needed
if(_limitEmissions == 1 || hardOnly() ||
( _limitEmissions == 3 && _nis != 0) ||
( _limitEmissions == 4 && _nfs + _nis != 0) ) {
return false;
}
// too many tries
if(_nFSR>=_maxTryFSR) {
++_nFailedFSR;
// too many failed events
if(_nFailedFSR>=_maxFailFSR)
throw Exception() << "Too many events have failed due to too many shower emissions, in\n"
<< "QTildeShowerHandler::timeLikeShower(). Terminating run\n"
<< Exception::runerror;
throw Exception() << "Too many attempted emissions in QTildeShowerHandler::timeLikeShower()\n"
<< Exception::eventerror;
}
// generate the emission
ShowerParticleVector children;
int ntry=0;
// generate the emission
if(!fb.kinematics)
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,
HardBranchingPtr());
// no emission, return
if(!fb.kinematics) return false;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(particle->virtualMass()==ZERO)
particle->virtualMass(_progenitor->progenitor()->mass());
fc[0] = Branching();
fc[1] = Branching();
++ntry;
assert(fb.kinematics);
// has emitted
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the ShowerParticle objects for the two children
children = createTimeLikeChildren(particle,fb.ids);
// updateChildren the children
particle->showerKinematics()->
updateChildren(particle, children, fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,
type,HardBranchingPtr());
fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr());
// old default
if(_reconOpt==0) {
++_nis;
// shower the first particle
_currenttree->updateInitialStateShowerProduct(_progenitor,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
break;
}
// Herwig default
else if(_reconOpt==1) {
// shower the first particle
_currenttree->updateInitialStateShowerProduct(_progenitor,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,
HardBranchingPtr());
// no emission, return
if(!fb.kinematics) {
return false;
}
setupChildren = true;
continue;
}
else {
++_nis;
break;
}
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
// space-like children
masses[1] = children[0]->virtualMass();
// time-like child
if(fc[1].kinematics) {
const vector<Energy> & vm = fc[1].sudakov->virtualMasses(fc[1].ids);
Energy2 q2 =
fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale());
if(fc[1].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]);
masses[2] = sqrt(q2);
}
else {
masses[2] = virtualMasses[2];
}
masses[0]=particle->virtualMass();
double z = fb.kinematics->z();
Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2]));
if(pt2>=ZERO) {
++_nis;
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else {
if(ix==0)
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy);
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
}
}
children[0]->virtualMass(_progenitor->progenitor()->mass());
children[1]->virtualMass(ZERO);
}
}
};
if(_reconOpt>=2) {
// In the case of splittings which involves coloured particles,
// set properly the colour flow of the branching.
// update the history if needed
_currenttree->updateInitialStateShowerProduct(_progenitor,children[0]);
_currenttree->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching());
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true);
updateHistory(children[1]);
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
}
// branching has happened
return true;
}
vector<ShowerProgenitorPtr> QTildeShowerHandler::setupShower(bool hard) {
RealEmissionProcessPtr real;
// generate hard me if needed
if(_hardEmission==1) {
real = hardMatrixElementCorrection(hard);
if(real&&!real->outgoing().empty()) setupMECorrection(real);
}
// generate POWHEG hard emission if needed
else if(_hardEmission==2)
hardestEmission(hard);
// set the initial colour partners
setEvolutionPartners(hard,interaction_,false);
// get the particles to be showered
vector<ShowerProgenitorPtr> particlesToShower =
currentTree()->extractProgenitors();
// return the answer
return particlesToShower;
}
void QTildeShowerHandler::setEvolutionPartners(bool hard,ShowerInteraction type,
bool clear) {
// match the particles in the ShowerTree and hardTree
if(hardTree() && !hardTree()->connect(currentTree()))
throw Exception() << "Can't match trees in "
<< "QTildeShowerHandler::setEvolutionPartners()"
<< Exception::eventerror;
// extract the progenitors
vector<ShowerParticlePtr> particles =
currentTree()->extractProgenitorParticles();
// clear the partners if needed
if(clear) {
for(unsigned int ix=0;ix<particles.size();++ix) {
particles[ix]->partner(ShowerParticlePtr());
particles[ix]->clearPartners();
}
}
// sort out the colour partners
if(hardTree()) {
// find the partner
for(unsigned int ix=0;ix<particles.size();++ix) {
tShowerParticlePtr partner = hardTree()->particles()[particles[ix]]->branchingParticle()->partner();
if(!partner) continue;
for(map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
it=hardTree()->particles().begin();
it!=hardTree()->particles().end();++it) {
if(it->second->branchingParticle()==partner) {
particles[ix]->partner(it->first);
break;
}
}
if(!particles[ix]->partner())
throw Exception() << "Can't match partners in "
<< "QTildeShowerHandler::setEvolutionPartners()"
<< Exception::eventerror;
}
}
// Set the initial evolution scales
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,interaction_,!_hardtree);
if(hardTree() && _hardPOWHEG) {
bool tooHard=false;
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end();
for(unsigned int ix=0;ix<particles.size();++ix) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(particles[ix]);
Energy hardScale(ZERO);
ShowerPartnerType type(ShowerPartnerType::Undefined);
// final-state
if(particles[ix]->isFinalState()) {
if(mit!= eit && !mit->second->children().empty()) {
hardScale = mit->second->scale();
type = mit->second->type();
}
}
// initial-state
else {
if(mit!= eit && mit->second->parent()) {
hardScale = mit->second->parent()->scale();
type = mit->second->parent()->type();
}
}
if(type!=ShowerPartnerType::Undefined) {
if(type==ShowerPartnerType::QED) {
tooHard |= particles[ix]->scales().QED_noAO<hardScale;
}
else if(type==ShowerPartnerType::QCDColourLine) {
tooHard |= particles[ix]->scales().QCD_c_noAO<hardScale;
}
else if(type==ShowerPartnerType::QCDAntiColourLine) {
tooHard |= particles[ix]->scales().QCD_ac_noAO<hardScale;
}
else if(type==ShowerPartnerType::EW) {
tooHard |= particles[ix]->scales().EW<hardScale;
}
}
}
if(tooHard) convertHardTree(hard,type);
}
}
void QTildeShowerHandler::updateHistory(tShowerParticlePtr particle) {
if(!particle->children().empty()) {
ShowerParticleVector theChildren;
for(unsigned int ix=0;ix<particle->children().size();++ix) {
ShowerParticlePtr part = dynamic_ptr_cast<ShowerParticlePtr>
(particle->children()[ix]);
theChildren.push_back(part);
}
// update the history if needed
if(particle==_currenttree->getFinalStateShowerProduct(_progenitor))
_currenttree->updateFinalStateShowerProduct(_progenitor,
particle,theChildren);
_currenttree->addFinalStateBranching(particle,theChildren);
for(unsigned int ix=0;ix<theChildren.size();++ix)
updateHistory(theChildren[ix]);
}
}
bool QTildeShowerHandler::startTimeLikeShower(ShowerInteraction type) {
_nFSR = 0;
// initialize basis vectors etc
if(!progenitor()->progenitor()->partner()) return false;
progenitor()->progenitor()->initializeFinalState();
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && !mit->second->children().empty() ) {
bool output=truncatedTimeLikeShower(progenitor()->progenitor(),
mit->second ,type,Branching(),true);
if(output) updateHistory(progenitor()->progenitor());
return output;
}
}
// do the shower
bool output = hardOnly() ? false :
timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ;
if(output) updateHistory(progenitor()->progenitor());
return output;
}
bool QTildeShowerHandler::startSpaceLikeShower(PPtr parent, ShowerInteraction type) {
// initialise the basis vectors
if(!progenitor()->progenitor()->partner()) return false;
progenitor()->progenitor()->initializeInitialState(parent);
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit =hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && mit->second->parent() ) {
return truncatedSpaceLikeShower( progenitor()->progenitor(),
parent, mit->second->parent(), type );
}
}
// perform the shower
return hardOnly() ? false :
spaceLikeShower(progenitor()->progenitor(),parent,type);
}
bool QTildeShowerHandler::
startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass,ShowerInteraction type) {
_nFSR = 0;
// set up the particle basis vectors
if(!progenitor()->progenitor()->partner()) return false;
progenitor()->progenitor()->initializeDecay();
if(hardTree()) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit =hardTree()->particles().end(),
mit = hardTree()->particles().find(progenitor()->progenitor());
if( mit != eit && mit->second->parent() ) {
HardBranchingPtr branch=mit->second;
while(branch->parent()) branch=branch->parent();
return truncatedSpaceLikeDecayShower(progenitor()->progenitor(),maxScales,
minimumMass, branch ,type, Branching());
}
}
// perform the shower
return hardOnly() ? false :
spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type,Branching());
}
bool QTildeShowerHandler::timeLikeVetoed(const Branching & fb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction type = convertInteraction(fb.type);
// check whether emission was harder than largest pt of hard subprocess
if ( restrictPhasespace() && fb.kinematics->pT() > _progenitor->maxHardPt() )
return true;
// soft matrix element correction veto
if( softMEC()) {
if(_hardme && _hardme->hasMECorrection()) {
if(_hardme->softMatrixElementVeto(particle,
_progenitor->progenitor(),
particle->isFinalState(),
_progenitor->highestpT(),
fb.ids, fb.kinematics->z(),
fb.kinematics->scale(),
fb.kinematics->pT()))
return true;
}
else if(_decayme && _decayme->hasMECorrection()) {
if(_decayme->softMatrixElementVeto(particle,
_progenitor->progenitor(),
particle->isFinalState(),
_progenitor->highestpT(),
fb.ids, fb.kinematics->z(),
fb.kinematics->scale(),
fb.kinematics->pT()))
return true;
}
}
// veto on maximum pt
if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true;
// general vetos
if (fb.kinematics && !_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoTimeLike(_progenitor,particle,fb,currentTree());
switch((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
}
if(vetoed) return true;
}
if ( firstInteraction() &&
profileScales() ) {
double weight =
profileScales()->
hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT());
if ( UseRandom::rnd() > weight )
return true;
}
return false;
}
bool QTildeShowerHandler::spaceLikeVetoed(const Branching & bb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction type = convertInteraction(bb.type);
// check whether emission was harder than largest pt of hard subprocess
if (restrictPhasespace() && bb.kinematics->pT() > _progenitor->maxHardPt())
return true;
// apply the soft correction
if( softMEC() && _hardme && _hardme->hasMECorrection() ) {
if(_hardme->softMatrixElementVeto(particle,
_progenitor->progenitor(),
particle->isFinalState(),
_progenitor->highestpT(),
bb.ids, bb.kinematics->z(),
bb.kinematics->scale(),
bb.kinematics->pT()))
return true;
}
// the more general vetos
// check vs max pt for the shower
if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true;
if (!_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoSpaceLike(_progenitor,particle,bb,currentTree());
switch ((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
}
if (vetoed) return true;
}
if ( firstInteraction() &&
profileScales() ) {
double weight =
profileScales()->
hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT());
if ( UseRandom::rnd() > weight )
return true;
}
return false;
}
bool QTildeShowerHandler::spaceLikeDecayVetoed( const Branching & fb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction type = convertInteraction(fb.type);
// apply the soft correction
if( softMEC() && _decayme && _decayme->hasMECorrection() ) {
if(_decayme->softMatrixElementVeto(particle,
_progenitor->progenitor(),
particle->isFinalState(),
_progenitor->highestpT(),
fb.ids, fb.kinematics->z(),
fb.kinematics->scale(),
fb.kinematics->pT()))
return true;
}
// veto on hardest pt in the shower
if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true;
// general vetos
if (!_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoSpaceLike(_progenitor,particle,fb,currentTree());
switch((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
if (vetoed) return true;
}
}
return false;
}
void QTildeShowerHandler::hardestEmission(bool hard) {
HardTreePtr ISRTree;
// internal POWHEG in production or decay
if( (( _hardme && _hardme->hasPOWHEGCorrection()!=0 ) ||
( _decayme && _decayme->hasPOWHEGCorrection()!=0 ) ) ) {
RealEmissionProcessPtr real;
unsigned int type(0);
// production
if(_hardme) {
assert(hard);
real = _hardme->generateHardest( currentTree()->perturbativeProcess(),
interaction_);
type = _hardme->hasPOWHEGCorrection();
}
// decay
else {
assert(!hard);
real = _decayme->generateHardest( currentTree()->perturbativeProcess() );
type = _decayme->hasPOWHEGCorrection();
}
if(real) {
// set up ther hard tree
if(!real->outgoing().empty()) _hardtree = new_ptr(HardTree(real));
// set up the vetos
currentTree()->setVetoes(real->pT(),type);
}
// store initial state POWHEG radiation
if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1)
ISRTree = _hardtree;
}
else if (hard) {
// Get minimum pT cutoff used in shower approximation
Energy maxpt = 1.*GeV;
if ( currentTree()->showerApproximation() ) {
int colouredIn = 0;
int colouredOut = 0;
for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it
= currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if( it->second->coloured() ) ++colouredOut;
}
for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it
= currentTree()->incomingLines().begin();
it != currentTree()->incomingLines().end(); ++it ) {
if( it->second->coloured() ) ++colouredIn;
}
if ( currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->fiPtCut() &&
currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->iiPtCut() )
maxpt = currentTree()->showerApproximation()->ffPtCut();
else if ( colouredIn == 2 && colouredOut == 0 )
maxpt = currentTree()->showerApproximation()->iiPtCut();
else if ( colouredIn == 0 && colouredOut > 1 )
maxpt = currentTree()->showerApproximation()->ffPtCut();
else if ( colouredIn == 2 && colouredOut == 1 )
maxpt = min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut());
else if ( colouredIn == 1 && colouredOut > 1 )
maxpt = min(currentTree()->showerApproximation()->ffPtCut(), currentTree()->showerApproximation()->fiPtCut());
else
maxpt = min(min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()),
currentTree()->showerApproximation()->ffPtCut());
}
// Generate hardtree from born and real emission subprocesses
_hardtree = generateCKKW(currentTree());
// Find transverse momentum of hardest emission
if (_hardtree){
for(set<HardBranchingPtr>::iterator it=_hardtree->branchings().begin();
it!=_hardtree->branchings().end();++it) {
if ((*it)->parent() && (*it)->status()==HardBranching::Incoming)
maxpt=(*it)->branchingParticle()->momentum().perp();
if ((*it)->children().size()==2 && (*it)->status()==HardBranching::Outgoing){
if ((*it)->branchingParticle()->id()!=21 &&
abs((*it)->branchingParticle()->id())>5 ){
if ((*it)->children()[0]->branchingParticle()->id()==21 ||
abs((*it)->children()[0]->branchingParticle()->id())<6)
maxpt=(*it)->children()[0]->branchingParticle()->momentum().perp();
else if ((*it)->children()[1]->branchingParticle()->id()==21 ||
abs((*it)->children()[1]->branchingParticle()->id())<6)
maxpt=(*it)->children()[1]->branchingParticle()->momentum().perp();
}
else {
if ( abs((*it)->branchingParticle()->id())<6){
if (abs((*it)->children()[0]->branchingParticle()->id())<6)
maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp();
else
maxpt = (*it)->children()[0]->branchingParticle()->momentum().perp();
}
else maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp();
}
}
}
}
// Hardest (pt) emission should be the first powheg emission.
maxpt=min(sqrt(lastXCombPtr()->lastShowerScale()),maxpt);
// set maximum pT for subsequent emissions from S events
if ( currentTree()->isPowhegSEvent() ) {
for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it
= currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if( ! it->second->coloured() ) continue;
it->first->maximumpT(maxpt, ShowerInteraction::QCD );
}
for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it
= currentTree()->incomingLines().begin();
it != currentTree()->incomingLines().end(); ++it ) {
if( ! it->second->coloured() ) continue;
it->first->maximumpT(maxpt, ShowerInteraction::QCD );
}
}
}
else
_hardtree = generateCKKW(currentTree());
// if hard me doesn't have a FSR powheg
// correction use decay powheg correction
if (_hardme && _hardme->hasPOWHEGCorrection()<2) {
addFSRUsingDecayPOWHEG(ISRTree);
}
// connect the trees
if(_hardtree) {
connectTrees(currentTree(),_hardtree,hard);
}
}
void QTildeShowerHandler::addFSRUsingDecayPOWHEG(HardTreePtr ISRTree) {
// check for intermediate colour singlet resonance
const ParticleVector inter = _hardme->subProcess()->intermediates();
if (inter.size()!=1 || inter[0]->momentum().m2()/GeV2 < 0 ||
inter[0]->dataPtr()->iColour()!=PDT::Colour0) {
return;
}
// ignore cases where outgoing particles are not coloured
map<ShowerProgenitorPtr, tShowerParticlePtr > out = currentTree()->outgoingLines();
if (out.size() != 2 ||
out. begin()->second->dataPtr()->iColour()==PDT::Colour0 ||
out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) {
return;
}
// look up decay mode
tDMPtr dm;
string tag;
string inParticle = inter[0]->dataPtr()->name() + "->";
vector<string> outParticles;
outParticles.push_back(out.begin ()->first->progenitor()->dataPtr()->name());
outParticles.push_back(out.rbegin()->first->progenitor()->dataPtr()->name());
for (int it=0; it<2; ++it){
tag = inParticle + outParticles[it] + "," + outParticles[(it+1)%2] + ";";
dm = generator()->findDecayMode(tag);
if(dm) break;
}
// get the decayer
HwDecayerBasePtr decayer;
if(dm) decayer = dynamic_ptr_cast<HwDecayerBasePtr>(dm->decayer());
// check if decayer has a FSR POWHEG correction
if (!decayer || decayer->hasPOWHEGCorrection()<2) {
return;
}
// generate the hardest emission
// create RealEmissionProcess
PPtr in = new_ptr(*inter[0]);
RealEmissionProcessPtr newProcess(new_ptr(RealEmissionProcess()));
newProcess->bornIncoming().push_back(in);
newProcess->bornOutgoing().push_back(out.begin ()->first->progenitor());
newProcess->bornOutgoing().push_back(out.rbegin()->first->progenitor());
// generate the FSR
newProcess = decayer->generateHardest(newProcess);
HardTreePtr FSRTree;
if(newProcess) {
// set up ther hard tree
if(!newProcess->outgoing().empty()) FSRTree = new_ptr(HardTree(newProcess));
// set up the vetos
currentTree()->setVetoes(newProcess->pT(),2);
}
if(!FSRTree) return;
// if there is no ISRTree make _hardtree from FSRTree
if (!ISRTree){
vector<HardBranchingPtr> inBranch,hardBranch;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit =currentTree()->incomingLines().begin();
cit!=currentTree()->incomingLines().end();++cit ) {
inBranch.push_back(new_ptr(HardBranching(cit->second,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
inBranch.back()->beam(cit->first->original()->parents()[0]);
hardBranch.push_back(inBranch.back());
}
if(inBranch[0]->branchingParticle()->dataPtr()->coloured()) {
inBranch[0]->colourPartner(inBranch[1]);
inBranch[1]->colourPartner(inBranch[0]);
}
for(set<HardBranchingPtr>::iterator it=FSRTree->branchings().begin();
it!=FSRTree->branchings().end();++it) {
if((**it).branchingParticle()->id()!=in->id())
hardBranch.push_back(*it);
}
hardBranch[2]->colourPartner(hardBranch[3]);
hardBranch[3]->colourPartner(hardBranch[2]);
HardTreePtr newTree = new_ptr(HardTree(hardBranch,inBranch,
ShowerInteraction::QCD));
_hardtree = newTree;
}
// Otherwise modify the ISRTree to include the emission in FSRTree
else {
vector<tShowerParticlePtr> FSROut, ISROut;
set<HardBranchingPtr>::iterator itFSR, itISR;
// get outgoing particles
for(itFSR =FSRTree->branchings().begin();
itFSR!=FSRTree->branchings().end();++itFSR){
if ((**itFSR).status()==HardBranching::Outgoing)
FSROut.push_back((*itFSR)->branchingParticle());
}
for(itISR =ISRTree->branchings().begin();
itISR!=ISRTree->branchings().end();++itISR){
if ((**itISR).status()==HardBranching::Outgoing)
ISROut.push_back((*itISR)->branchingParticle());
}
// find COM frame formed by outgoing particles
LorentzRotation eventFrameFSR, eventFrameISR;
eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM());
eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM());
// find rotation between ISR and FSR frames
int j=0;
if (ISROut[0]->id()!=FSROut[0]->id()) j=1;
eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()-
(eventFrameISR*ISROut[j]->momentum()).phi() );
eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()-
(eventFrameISR*ISROut[j]->momentum()).theta() );
eventFrameISR.invert();
for (itFSR=FSRTree->branchings().begin();
itFSR!=FSRTree->branchings().end();++itFSR){
if ((**itFSR).branchingParticle()->id()==in->id()) continue;
for (itISR =ISRTree->branchings().begin();
itISR!=ISRTree->branchings().end();++itISR){
if ((**itISR).status()==HardBranching::Incoming) continue;
if ((**itFSR).branchingParticle()->id()==
(**itISR).branchingParticle()->id()){
// rotate FSRTree particle to ISRTree event frame
(**itISR).branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).branchingParticle()->momentum());
(**itISR).branchingParticle()->rescaleMass();
// add the children of the FSRTree particles to the ISRTree
if(!(**itFSR).children().empty()){
(**itISR).addChild((**itFSR).children()[0]);
(**itISR).addChild((**itFSR).children()[1]);
// rotate momenta to ISRTree event frame
(**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).children()[0]->branchingParticle()->momentum());
(**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).children()[1]->branchingParticle()->momentum());
}
}
}
}
_hardtree = ISRTree;
}
}
bool QTildeShowerHandler::truncatedTimeLikeShower(tShowerParticlePtr particle,
HardBranchingPtr branch,
ShowerInteraction type,
Branching fb, bool first) {
// select a branching if we don't have one
if(!fb.kinematics)
fb = selectTimeLikeBranching(particle,type,branch);
// must be an emission, the forced one it not a truncated one
assert(fb.kinematics);
ShowerParticleVector children;
int ntry=0;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(!fc[0].hard) fc[0] = Branching();
if(!fc[1].hard) fc[1] = Branching();
++ntry;
// Assign the shower kinematics to the emitting particle.
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the children
children = createTimeLikeChildren(particle,fb.ids);
// update the children
particle->showerKinematics()->
updateChildren(particle, children,fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
if(!fc[0].kinematics) {
// select branching for first particle
if(!fb.hard && fb.iout ==1 )
fc[0] = selectTimeLikeBranching(children[0],type,branch);
else if(fb.hard && !branch->children()[0]->children().empty() )
fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]);
else
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
}
// select branching for the second particle
if(!fc[1].kinematics) {
// select branching for first particle
if(!fb.hard && fb.iout ==2 )
fc[1] = selectTimeLikeBranching(children[1],type,branch);
else if(fb.hard && !branch->children()[1]->children().empty() )
fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]);
else
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
}
// old default
if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[1]->children().empty() )
truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
break;
}
// H7 default
else if(_reconOpt==1) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectTimeLikeBranching(particle,type,branch);
// must be at least hard emission
assert(fb.kinematics);
setupChildren = true;
continue;
}
else
break;
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics) {
const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids);
Energy2 q2 =
fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale());
if(fc[ix].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]);
masses[ix+1] = sqrt(q2);
}
else {
masses[ix+1] = virtualMasses[ix+1];
}
}
masses[0] = fb.ids[0]->id()!=ParticleID::g ? virtualMasses[0] : ZERO;
double z = fb.kinematics->z();
Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0]))
- sqr(masses[1])*(1.-z) - sqr(masses[2])*z;
if(pt2>=ZERO) {
break;
}
// if only the hard emission have to accept it
else if ((fc[0].hard && !fc[1].kinematics) ||
(fc[1].hard && !fc[0].kinematics) ) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].hard) continue;
if(fc[ix].kinematics && ! fc[ix].hard )
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
children[ix]->virtualMass(ZERO);
}
}
}
};
if(_reconOpt>=2) {
// shower the first particle
if(fc[0].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 1)
truncatedTimeLikeShower(children[0],branch,type,fc[0],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) {
// the parent has truncated emission and following line
if(!fb.hard && fb.iout == 2)
truncatedTimeLikeShower(children[1],branch,type,fc[1],false);
// hard emission and subsquent hard emissions
else if(fb.hard && !branch->children()[1]->children().empty() )
truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false);
else
timeLikeShower(children[1],type,fc[1],false);
}
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
particle->showerKinematics()->updateParent(particle, children,fb.type);
}
if(first&&!children.empty())
particle->showerKinematics()->resetChildren(particle,children);
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
bool QTildeShowerHandler::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam,
HardBranchingPtr branch,
ShowerInteraction type) {
tcPDFPtr pdf;
if(firstPDF().particle() == beamParticle())
pdf = firstPDF().pdf();
if(secondPDF().particle() == beamParticle())
pdf = secondPDF().pdf();
Energy freeze = pdfFreezingScale();
Branching bb;
// parameters of the force branching
double z(0.);
HardBranchingPtr timelike;
for( unsigned int ix = 0; ix < branch->children().size(); ++ix ) {
if( branch->children()[ix]->status() ==HardBranching::Outgoing) {
timelike = branch->children()[ix];
}
if( branch->children()[ix]->status() ==HardBranching::Incoming )
z = branch->children()[ix]->z();
}
// generate truncated branching
tcPDPtr part[2];
if(z>=0.&&z<=1.) {
while (true) {
if( !isTruncatedShowerON() || hardOnly() ) break;
bb = splittingGenerator()->chooseBackwardBranching( *particle,
beam, 1., beamParticle(),
type , pdf,freeze);
if( !bb.kinematics || bb.kinematics->scale() < branch->scale() ) {
bb = Branching();
break;
}
// particles as in Sudakov form factor
part[0] = bb.ids[0];
part[1] = bb.ids[2];
double zsplit = bb.kinematics->z();
// apply the vetos for the truncated shower
// if doesn't carry most of momentum
ShowerInteraction type2 = convertInteraction(bb.type);
if(type2==branch->sudakov()->interactionType() &&
zsplit < 0.5) {
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
// others
if( part[0]->id() != particle->id() || // if particle changes type
bb.kinematics->pT() > progenitor()->maximumpT(type2) || // pt veto
bb.kinematics->scale() < branch->scale()) { // angular ordering veto
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
// and those from the base class
if(spaceLikeVetoed(bb,particle)) {
particle->vetoEmission(bb.type,bb.kinematics->scale());
continue;
}
break;
}
}
if( !bb.kinematics ) {
//do the hard emission
ShoKinPtr kinematics =
branch->sudakov()->createInitialStateBranching( branch->scale(), z, branch->phi(),
branch->children()[0]->pT() );
// assign the splitting function and shower kinematics
particle->showerKinematics( kinematics );
if(kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(kinematics->pT());
// For the time being we are considering only 1->2 branching
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent =
new_ptr( ShowerParticle( branch->branchingParticle()->dataPtr(), false ) );
ShowerParticlePtr otherChild =
new_ptr( ShowerParticle( timelike->branchingParticle()->dataPtr(),
true, true ) );
ShowerParticleVector theChildren;
theChildren.push_back( particle );
theChildren.push_back( otherChild );
particle->showerKinematics()->
updateParent( newParent, theChildren, branch->type());
// update the history if needed
currentTree()->updateInitialStateShowerProduct( progenitor(), newParent );
currentTree()->addInitialStateBranching( particle, newParent, otherChild );
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
bool emitted=false;
if(!hardOnly()) {
if( branch->parent() ) {
emitted = truncatedSpaceLikeShower( newParent, beam, branch->parent() , type);
}
else {
emitted = spaceLikeShower( newParent, beam , type);
}
}
if( !emitted ) {
if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) {
kinematics->updateLast( newParent, ZERO, ZERO );
}
else {
pair<Energy,double> kt = intrinsicpT()[progenitor()];
kinematics->updateLast( newParent,
kt.first*cos( kt.second ),
kt.first*sin( kt.second ) );
}
}
particle->showerKinematics()->
updateChildren( newParent, theChildren,bb.type,false);
if(hardOnly()) return true;
// perform the shower of the final-state particle
if( timelike->children().empty() ) {
timeLikeShower( otherChild , type,Branching(),true);
}
else {
truncatedTimeLikeShower( otherChild, timelike , type,Branching(), true);
}
updateHistory(otherChild);
// return the emitted
return true;
}
// assign the splitting function and shower kinematics
particle->showerKinematics( bb.kinematics );
if(bb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(bb.kinematics->pT());
// For the time being we are considering only 1->2 branching
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent = new_ptr( ShowerParticle( part[0], false ) );
ShowerParticlePtr otherChild = new_ptr( ShowerParticle( part[1], true, true ) );
ShowerParticleVector theChildren;
theChildren.push_back( particle );
theChildren.push_back( otherChild );
particle->showerKinematics()->
updateParent( newParent, theChildren, bb.type);
// update the history if needed
currentTree()->updateInitialStateShowerProduct( progenitor(), newParent );
currentTree()->addInitialStateBranching( particle, newParent, otherChild );
// for the reconstruction of kinematics, parent/child
// relationships are according to the branching process:
// now continue the shower
bool emitted = truncatedSpaceLikeShower( newParent, beam, branch,type);
// now reconstruct the momentum
if( !emitted ) {
if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) {
bb.kinematics->updateLast( newParent, ZERO, ZERO );
}
else {
pair<Energy,double> kt = intrinsicpT()[ progenitor() ];
bb.kinematics->updateLast( newParent,
kt.first*cos( kt.second ),
kt.first*sin( kt.second ) );
}
}
particle->showerKinematics()->
updateChildren( newParent, theChildren, bb.type,false);
// perform the shower of the final-state particle
timeLikeShower( otherChild , type,Branching(),true);
updateHistory(otherChild);
// return the emitted
return true;
}
bool QTildeShowerHandler::
truncatedSpaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass, HardBranchingPtr branch,
ShowerInteraction type, Branching fb) {
// select a branching if we don't have one
if(!fb.kinematics)
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch);
// must be an emission, the forced one it not a truncated one
assert(fb.kinematics);
ShowerParticleVector children;
int ntry=0;
Branching fc[2];
bool setupChildren = true;
while (ntry<50) {
if(!fc[0].hard) fc[0] = Branching();
if(!fc[1].hard) fc[1] = Branching();
++ntry;
if(setupChildren) {
++_nFSR;
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// create the ShowerParticle objects for the two children
children = createTimeLikeChildren(particle,fb.ids);
// updateChildren the children
particle->showerKinematics()->
updateChildren(particle, children, fb.type,_reconOpt>=3);
setupChildren = false;
}
// select branchings for children
if(!fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
// select branching for first particle
if(!fb.hard)
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch);
else if(fb.hard && ! branch->children()[0]->children().empty() )
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,
branch->children()[0]);
else
fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,
HardBranchingPtr());
}
else {
// select branching for first particle
if(fb.hard && !branch->children()[0]->children().empty() )
fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]);
else
fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr());
}
}
// select branching for the second particle
if(!fc[1].kinematics) {
if(children[1]->id()==particle->id()) {
// select branching for first particle
if(!fb.hard)
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,branch);
else if(fb.hard && ! branch->children()[1]->children().empty() )
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,
branch->children()[1]);
else
fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,
HardBranchingPtr());
}
else {
if(fb.hard && !branch->children()[1]->children().empty() )
fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]);
else
fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr());
}
}
// old default
if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
updateHistory(children[1]);
// branching has happened
break;
}
// H7 default
else if(_reconOpt==1) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<children.size();++ix)
particle->abandonChild(children[ix]);
children.clear();
particle->vetoEmission(fb.type,fb.kinematics->scale());
// generate the new emission
fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch);
// must be at least hard emission
assert(fb.kinematics);
setupChildren = true;
continue;
}
else {
updateHistory(children[1]);
break;
}
}
else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
// space-like children
masses[1] = children[0]->virtualMass();
// time-like child
if(fc[1].kinematics) {
const vector<Energy> & vm = fc[1].sudakov->virtualMasses(fc[1].ids);
Energy2 q2 =
fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale());
if(fc[1].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]);
masses[2] = sqrt(q2);
}
else {
masses[2] = virtualMasses[2];
}
masses[0]=particle->virtualMass();
double z = fb.kinematics->z();
Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2]));
if(pt2>=ZERO) {
break;
}
else {
// reset the scales for the children
for(unsigned int ix=0;ix<2;++ix) {
if(fc[ix].kinematics)
children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale());
else {
if(ix==0)
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy);
else
children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO);
}
}
children[0]->virtualMass(_progenitor->progenitor()->mass());
children[1]->virtualMass(ZERO);
}
}
};
if(_reconOpt>=2) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]);
currentTree()->addInitialStateBranching(particle,children[0],children[1]);
// shower the first particle
if(fc[0].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[0]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[0]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false);
// normal shower
else
timeLikeShower(children[0],type,fc[0],false);
}
}
// shower the second particle
if(fc[1].kinematics) {
if(children[0]->id()==particle->id()) {
if(!fb.hard)
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch,type,fc[1]);
else if(fb.hard && ! branch->children()[0]->children().empty() )
truncatedSpaceLikeDecayShower( children[0],maxScales,minmass,
branch->children()[0],type,fc[1]);
else
spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]);
}
else {
if(fb.hard && !branch->children()[0]->children().empty() )
truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false);
// normal shower
else
timeLikeShower(children[0],type,fc[1],false);
}
}
updateHistory(children[1]);
}
return true;
}
void QTildeShowerHandler::connectTrees(ShowerTreePtr showerTree,
HardTreePtr hardTree, bool hard ) {
ShowerParticleVector particles;
// find the Sudakovs
for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin();
cit!=hardTree->branchings().end();++cit) {
// Sudakovs for ISR
if((**cit).parent()&&(**cit).status()==HardBranching::Incoming) {
++_nis;
- vector<long> br(3);
+ array<long,3> br;
br[0] = (**cit).parent()->branchingParticle()->id();
br[1] = (**cit). branchingParticle()->id();
br[2] = (**cit).parent()->children()[0]==*cit ?
(**cit).parent()->children()[1]->branchingParticle()->id() :
(**cit).parent()->children()[0]->branchingParticle()->id();
BranchingList branchings = splittingGenerator()->initialStateBranchings();
if(br[1]<0&&br[0]==br[1]) {
br[0] = abs(br[0]);
br[1] = abs(br[1]);
}
else if(br[1]<0) {
br[1] = -br[1];
br[2] = -br[2];
}
long index = abs(br[1]);
SudakovPtr sudakov;
for(BranchingList::const_iterator cjt = branchings.lower_bound(index);
cjt != branchings.upper_bound(index); ++cjt ) {
IdList ids = cjt->second.particles;
if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) {
sudakov=cjt->second.sudakov;
break;
}
}
if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in "
<< "QTildeShowerHandler::connectTrees() for ISR"
<< Exception::runerror;
(**cit).parent()->sudakov(sudakov);
}
// Sudakovs for FSR
else if(!(**cit).children().empty()) {
++_nfs;
- vector<long> br(3);
+ array<long,3> br;
br[0] = (**cit) .branchingParticle()->id();
br[1] = (**cit).children()[0]->branchingParticle()->id();
br[2] = (**cit).children()[1]->branchingParticle()->id();
BranchingList branchings = splittingGenerator()->finalStateBranchings();
if(br[0]<0) {
br[0] = abs(br[0]);
br[1] = abs(br[1]);
br[2] = abs(br[2]);
}
long index = br[0];
SudakovPtr sudakov;
for(BranchingList::const_iterator cjt = branchings.lower_bound(index);
cjt != branchings.upper_bound(index); ++cjt ) {
IdList ids = cjt->second.particles;
if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) {
sudakov=cjt->second.sudakov;
break;
}
}
if(!sudakov) {
throw Exception() << "Can't find Sudakov for the hard emission in "
<< "QTildeShowerHandler::connectTrees()"
<< Exception::runerror;
}
(**cit).sudakov(sudakov);
}
}
// calculate the evolution scale
for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin();
cit!=hardTree->branchings().end();++cit) {
particles.push_back((*cit)->branchingParticle());
}
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,interaction_,true);
hardTree->partnersSet(true);
// inverse reconstruction
if(hard) {
showerModel()->kinematicsReconstructor()->
deconstructHardJets(hardTree,interaction_);
}
else
showerModel()->kinematicsReconstructor()->
deconstructDecayJets(hardTree,interaction_);
// now reset the momenta of the showering particles
vector<ShowerProgenitorPtr> particlesToShower=showerTree->extractProgenitors();
// match them
map<ShowerProgenitorPtr,HardBranchingPtr> partners;
for(set<HardBranchingPtr>::const_iterator bit=hardTree->branchings().begin();
bit!=hardTree->branchings().end();++bit) {
Energy2 dmin( 1e30*GeV2 );
ShowerProgenitorPtr partner;
for(vector<ShowerProgenitorPtr>::const_iterator pit=particlesToShower.begin();
pit!=particlesToShower.end();++pit) {
if(partners.find(*pit)!=partners.end()) continue;
if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue;
if( (**bit).branchingParticle()->isFinalState() !=
(**pit).progenitor()->isFinalState() ) continue;
if( (**pit).progenitor()->isFinalState() ) {
Energy2 dtest =
sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) +
sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) +
sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) +
sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() );
// add mass difference for identical particles (e.g. Z0 Z0 production)
dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m());
if( dtest < dmin ) {
partner = *pit;
dmin = dtest;
}
}
else {
// ensure directions are right
if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) {
partner = *pit;
break;
}
}
}
if(!partner) throw Exception() << "Failed to match shower and hard trees in QTildeShowerHandler::hardestEmission"
<< Exception::eventerror;
partners[partner] = *bit;
}
for(vector<ShowerProgenitorPtr>::const_iterator pit=particlesToShower.begin();
pit!=particlesToShower.end();++pit) {
HardBranchingPtr partner = partners[*pit];
if((**pit).progenitor()->dataPtr()->stable()) {
(**pit).progenitor()->set5Momentum(partner->showerMomentum());
(**pit).copy()->set5Momentum(partner->showerMomentum());
}
else {
Lorentz5Momentum oldMomentum = (**pit).progenitor()->momentum();
Lorentz5Momentum newMomentum = partner->showerMomentum();
LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
(**pit).progenitor()->transform(boost);
(**pit).copy() ->transform(boost);
boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass());
(**pit).progenitor()->transform(boost);
(**pit).copy() ->transform(boost);
}
}
// correction boosts for daughter trees
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit = showerTree->treelinks().begin();
tit != showerTree->treelinks().end();++tit) {
ShowerTreePtr decayTree = tit->first;
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit = decayTree->incomingLines().begin();
// reset the momentum of the decay particle
Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum();
Lorentz5Momentum newMomentum = tit->second.second->momentum();
LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
decayTree->transform(boost,true);
boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass());
decayTree->transform(boost,true);
}
}
void QTildeShowerHandler::doShowering(bool hard,XCPtr xcomb) {
// zero number of emissions
_nis = _nfs = 0;
// if MC@NLO H event and limited emissions
// indicate both final and initial state emission
if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) {
_nis = _nfs = 1;
}
// extract particles to shower
vector<ShowerProgenitorPtr> particlesToShower(setupShower(hard));
// check if we should shower
bool colCharge = false;
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(particlesToShower[ix]->progenitor()->dataPtr()->coloured() ||
particlesToShower[ix]->progenitor()->dataPtr()->charged()) {
colCharge = true;
break;
}
}
if(!colCharge) {
_currenttree->hasShowered(true);
return;
}
// setup the maximum scales for the shower
if (restrictPhasespace()) setupMaximumScales(particlesToShower,xcomb);
// set the hard scales for the profiles
setupHardScales(particlesToShower,xcomb);
// specific stuff for hard processes and decays
Energy minmass(ZERO), mIn(ZERO);
// hard process generate the intrinsic p_T once and for all
if(hard) {
generateIntrinsicpT(particlesToShower);
}
// decay compute the minimum mass of the final-state
else {
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(particlesToShower[ix]->progenitor()->isFinalState()) {
if(particlesToShower[ix]->progenitor()->dataPtr()->stable())
minmass += particlesToShower[ix]->progenitor()->dataPtr()->constituentMass();
else
minmass += particlesToShower[ix]->progenitor()->mass();
}
else {
mIn = particlesToShower[ix]->progenitor()->mass();
}
}
// throw exception if decay can't happen
if ( minmass > mIn ) {
throw Exception() << "QTildeShowerHandler.cc: Mass of decaying particle is "
<< "below constituent masses of decay products."
<< Exception::eventerror;
}
}
// setup for reweighted
bool reWeighting = _reWeight && hard && ShowerHandler::currentHandler()->firstInteraction();
double eventWeight=0.;
unsigned int nTryReWeight(0);
// create random particle vector (only need to do once)
vector<ShowerProgenitorPtr> tmp;
unsigned int nColouredIncoming = 0;
while(particlesToShower.size()>0){
unsigned int xx=UseRandom::irnd(particlesToShower.size());
tmp.push_back(particlesToShower[xx]);
particlesToShower.erase(particlesToShower.begin()+xx);
}
particlesToShower=tmp;
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(!particlesToShower[ix]->progenitor()->isFinalState() &&
particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming;
}
bool switchRecon = hard && nColouredIncoming !=1;
// main shower loop
unsigned int ntry(0);
bool reconstructed = false;
do {
// clear results of last attempt if needed
if(ntry!=0) {
currentTree()->clear();
setEvolutionPartners(hard,interaction_,true);
_nis = _nfs = 0;
// if MC@NLO H event and limited emissions
// indicate both final and initial state emission
if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) {
_nis = _nfs = 1;
}
for(unsigned int ix=0; ix<particlesToShower.size();++ix) {
SpinPtr spin = particlesToShower[ix]->progenitor()->spinInfo();
if(spin && spin->decayVertex() &&
dynamic_ptr_cast<tcSVertexPtr>(spin->decayVertex())) {
spin->decayVertex(VertexPtr());
}
}
}
// loop over particles
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
// extract the progenitor
progenitor(particlesToShower[ix]);
// final-state radiation
if(progenitor()->progenitor()->isFinalState()) {
if(!doFSR()) continue;
// perform shower
progenitor()->hasEmitted(startTimeLikeShower(interaction_));
}
// initial-state radiation
else {
if(!doISR()) continue;
// hard process
if(hard) {
// get the PDF
setBeamParticle(_progenitor->beam());
if(!beamParticle()) {
throw Exception() << "Incorrect type of beam particle in "
<< "QTildeShowerHandler::doShowering(). "
<< "This should not happen for conventional choices but may happen if you have used a"
<< " non-default choice and have not changed the create ParticleData line in the input files"
<< " for this particle to create BeamParticleData."
<< Exception::runerror;
}
// perform the shower
// set the beam particle
tPPtr beamparticle=progenitor()->original();
if(!beamparticle->parents().empty())
beamparticle=beamparticle->parents()[0];
// generate the shower
progenitor()->hasEmitted(startSpaceLikeShower(beamparticle,
interaction_));
}
// decay
else {
// skip colour and electrically neutral particles
if(!progenitor()->progenitor()->dataPtr()->coloured() &&
!progenitor()->progenitor()->dataPtr()->charged()) {
progenitor()->hasEmitted(false);
continue;
}
// perform shower
// set the scales correctly. The current scale is the maximum scale for
// emission not the starting scale
ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales());
progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales();
if(progenitor()->progenitor()->dataPtr()->charged()) {
progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass();
progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass();
}
if(progenitor()->progenitor()->hasColour()) {
progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass();
progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass();
}
if(progenitor()->progenitor()->hasAntiColour()) {
progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass();
progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass();
}
// perform the shower
progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass,
interaction_));
}
}
}
// do the kinematic reconstruction, checking if it worked
reconstructed = hard ?
showerModel()->kinematicsReconstructor()->
reconstructHardJets (currentTree(),intrinsicpT(),interaction_,
switchRecon && ntry>maximumTries()/2) :
showerModel()->kinematicsReconstructor()->
reconstructDecayJets(currentTree(),interaction_);
if(!reconstructed) continue;
// apply vetos on the full shower
for(vector<FullShowerVetoPtr>::const_iterator it=_fullShowerVetoes.begin();
it!=_fullShowerVetoes.end();++it) {
int veto = (**it).applyVeto(currentTree());
if(veto<0) continue;
// veto the shower
if(veto==0) {
reconstructed = false;
break;
}
// veto the shower and reweight
else if(veto==1) {
reconstructed = false;
break;
}
// veto the event
else if(veto==2) {
throw Veto();
}
}
if(reWeighting) {
if(reconstructed) eventWeight += 1.;
reconstructed=false;
++nTryReWeight;
if(nTryReWeight==_nReWeight) {
reWeighting = false;
if(eventWeight==0.) throw Veto();
}
}
}
while(!reconstructed&&maximumTries()>++ntry);
// check if failed to generate the shower
if(ntry==maximumTries()) {
if(hard)
throw ShowerHandler::ShowerTriesVeto(ntry);
else
throw Exception() << "Failed to generate the shower after "
<< ntry << " attempts in QTildeShowerHandler::showerDecay()"
<< Exception::eventerror;
}
// handle the weights and apply any reweighting required
if(nTryReWeight>0) {
tStdEHPtr seh = dynamic_ptr_cast<tStdEHPtr>(generator()->currentEventHandler());
static bool first = true;
if(seh) {
seh->reweight(eventWeight/double(nTryReWeight));
}
else if(first) {
generator()->log() << "Reweighting the shower only works with internal Herwig7 processes"
<< "Presumably you are showering Les Houches Events. These will not be"
<< "reweighted\n";
first = false;
}
}
// tree has now showered
_currenttree->hasShowered(true);
hardTree(HardTreePtr());
}
void QTildeShowerHandler:: convertHardTree(bool hard,ShowerInteraction type) {
map<ColinePtr,ColinePtr> cmap;
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(cit->first->progenitor());
// put the colour lines in the map
ShowerParticlePtr oldParticle = cit->first->progenitor();
ShowerParticlePtr newParticle = mit->second->branchingParticle();
ColinePtr cLine = oldParticle-> colourLine();
ColinePtr aLine = oldParticle->antiColourLine();
if(newParticle->colourLine() &&
cmap.find(newParticle-> colourLine())==cmap.end())
cmap[newParticle-> colourLine()] = cLine;
if(newParticle->antiColourLine() &&
cmap.find(newParticle->antiColourLine())==cmap.end())
cmap[newParticle->antiColourLine()] = aLine;
// check whether or not particle emits
bool emission = mit->second->parent();
if(emission) {
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
}
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
}
newParticle = mit->second->parent()->branchingParticle();
}
// get the new colour lines
ColinePtr newCLine,newALine;
// sort out colour lines
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newCLine = cmap[ctemp];
}
else {
newCLine = new_ptr(ColourLine());
cmap[ctemp] = newCLine;
}
}
// and anticolour lines
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newALine = cmap[ctemp];
}
else {
newALine = new_ptr(ColourLine());
cmap[ctemp] = newALine;
}
}
// remove colour lines from old particle
if(aLine) {
aLine->removeAntiColoured(cit->first->copy());
aLine->removeAntiColoured(cit->first->progenitor());
}
if(cLine) {
cLine->removeColoured(cit->first->copy());
cLine->removeColoured(cit->first->progenitor());
}
// add particle to colour lines
if(newCLine) newCLine->addColoured (newParticle);
if(newALine) newALine->addAntiColoured(newParticle);
// insert new particles
cit->first->copy(newParticle);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,false)));
cit->first->progenitor(sp);
currentTree()->incomingLines()[cit->first]=sp;
cit->first->perturbative(!emission);
// and the emitted particle if needed
if(emission) {
ShowerParticlePtr newOut = mit->second->parent()->children()[1]->branchingParticle();
if(newOut->colourLine()) {
ColinePtr ctemp = newOut-> colourLine();
ctemp->removeColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addColoured (newOut);
}
if(newOut->antiColourLine()) {
ColinePtr ctemp = newOut->antiColourLine();
ctemp->removeAntiColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addAntiColoured(newOut);
}
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout));
out->perturbative(false);
currentTree()->outgoingLines().insert(make_pair(out,sout));
}
if(hard) {
// sort out the value of x
if(mit->second->beam()->momentum().z()>ZERO) {
sp->x(newParticle->momentum(). plus()/mit->second->beam()->momentum(). plus());
}
else {
sp->x(newParticle->momentum().minus()/mit->second->beam()->momentum().minus());
}
}
}
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) {
map<tShowerTreePtr,pair<tShowerProgenitorPtr,
tShowerParticlePtr> >::const_iterator tit;
for(tit = currentTree()->treelinks().begin();
tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==cit->first->progenitor())
break;
}
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(cit->first->progenitor());
if(mit==hardTree()->particles().end()) continue;
// put the colour lines in the map
ShowerParticlePtr oldParticle = cit->first->progenitor();
ShowerParticlePtr newParticle = mit->second->branchingParticle();
ShowerParticlePtr newOut;
ColinePtr cLine = oldParticle-> colourLine();
ColinePtr aLine = oldParticle->antiColourLine();
if(newParticle->colourLine() &&
cmap.find(newParticle-> colourLine())==cmap.end())
cmap[newParticle-> colourLine()] = cLine;
if(newParticle->antiColourLine() &&
cmap.find(newParticle->antiColourLine())==cmap.end())
cmap[newParticle->antiColourLine()] = aLine;
// check whether or not particle emits
bool emission = !mit->second->children().empty();
if(emission) {
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
}
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
}
newParticle = mit->second->children()[0]->branchingParticle();
newOut = mit->second->children()[1]->branchingParticle();
if(newParticle->id()!=oldParticle->id()&&newParticle->id()==newOut->id())
swap(newParticle,newOut);
}
// get the new colour lines
ColinePtr newCLine,newALine;
// sort out colour lines
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newCLine = cmap[ctemp];
}
else {
newCLine = new_ptr(ColourLine());
cmap[ctemp] = newCLine;
}
}
// and anticolour lines
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newALine = cmap[ctemp];
}
else {
newALine = new_ptr(ColourLine());
cmap[ctemp] = newALine;
}
}
// remove colour lines from old particle
if(aLine) {
aLine->removeAntiColoured(cit->first->copy());
aLine->removeAntiColoured(cit->first->progenitor());
}
if(cLine) {
cLine->removeColoured(cit->first->copy());
cLine->removeColoured(cit->first->progenitor());
}
// special for unstable particles
if(newParticle->id()==oldParticle->id() &&
(tit!=currentTree()->treelinks().end()||!oldParticle->dataPtr()->stable())) {
Lorentz5Momentum oldMomentum = oldParticle->momentum();
Lorentz5Momentum newMomentum = newParticle->momentum();
LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false);
oldParticle->transform(boost);
boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass());
oldParticle->transform(boost);
if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false);
newParticle=oldParticle;
}
// add particle to colour lines
if(newCLine) newCLine->addColoured (newParticle);
if(newALine) newALine->addAntiColoured(newParticle);
// insert new particles
cit->first->copy(newParticle);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,true)));
cit->first->progenitor(sp);
currentTree()->outgoingLines()[cit->first]=sp;
cit->first->perturbative(!emission);
// and the emitted particle if needed
if(emission) {
if(newOut->colourLine()) {
ColinePtr ctemp = newOut-> colourLine();
ctemp->removeColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addColoured (newOut);
}
if(newOut->antiColourLine()) {
ColinePtr ctemp = newOut->antiColourLine();
ctemp->removeAntiColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addAntiColoured(newOut);
}
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout));
out->perturbative(false);
currentTree()->outgoingLines().insert(make_pair(out,sout));
}
// update any decay products
if(tit!=currentTree()->treelinks().end())
currentTree()->updateLink(tit->first,make_pair(cit->first,sp));
}
// reset the tree
currentTree()->resetShowerProducts();
// reextract the particles and set the colour partners
vector<ShowerParticlePtr> particles =
currentTree()->extractProgenitorParticles();
// clear the partners
for(unsigned int ix=0;ix<particles.size();++ix) {
particles[ix]->partner(ShowerParticlePtr());
particles[ix]->clearPartners();
}
// clear the tree
hardTree(HardTreePtr());
// Set the initial evolution scales
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,type,!_hardtree);
}
Branching QTildeShowerHandler::selectTimeLikeBranching(tShowerParticlePtr particle,
ShowerInteraction type,
HardBranchingPtr branch) {
Branching fb;
unsigned int iout=0;
while (true) {
// break if doing truncated shower and no truncated shower needed
if(branch && (!isTruncatedShowerON()||hardOnly())) break;
fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type);
// no emission break
if(!fb.kinematics) break;
// special for truncated shower
if(branch) {
// check haven't evolved too far
if(fb.kinematics->scale() < branch->scale()) {
fb=Branching();
break;
}
// find the truncated line
iout=0;
if(fb.ids[1]->id()!=fb.ids[2]->id()) {
if(fb.ids[1]->id()==particle->id()) iout=1;
else if (fb.ids[2]->id()==particle->id()) iout=2;
}
else if(fb.ids[1]->id()==particle->id()) {
if(fb.kinematics->z()>0.5) iout=1;
else iout=2;
}
// apply the vetos for the truncated shower
// no flavour changing branchings
if(iout==0) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z();
// only if same interaction for forced branching
ShowerInteraction type2 = convertInteraction(fb.type);
// and evolution
if(type2==branch->sudakov()->interactionType()) {
if(zsplit < 0.5 || // hardest line veto
fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// pt veto
if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// standard vetos for all emissions
if(timeLikeVetoed(fb,particle)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
continue;
}
// special for already decayed particles
// don't allow flavour changing branchings
bool vetoDecay = false;
for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,
tShowerParticlePtr> >::const_iterator tit = currentTree()->treelinks().begin();
tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first == progenitor()) {
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
it = currentTree()->outgoingLines().find(progenitor());
if(it!=currentTree()->outgoingLines().end() && particle == it->second &&
fb.ids[0]!=fb.ids[1] && fb.ids[1]!=fb.ids[2]) {
vetoDecay = true;
break;
}
}
}
if(vetoDecay) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
continue;
}
break;
}
// normal case
if(!branch) {
if(fb.kinematics) fb.hard = false;
return fb;
}
// truncated emission
if(fb.kinematics) {
fb.hard = false;
fb.iout = iout;
return fb;
}
// otherwise need to return the hard emission
// construct the kinematics for the hard emission
ShoKinPtr showerKin=
branch->sudakov()->createFinalStateBranching(branch->scale(),
branch->children()[0]->z(),
branch->phi(),
branch->children()[0]->pT());
IdList idlist(3);
idlist[0] = particle->dataPtr();
idlist[1] = branch->children()[0]->branchingParticle()->dataPtr();
idlist[2] = branch->children()[1]->branchingParticle()->dataPtr();
fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() );
fb.hard = true;
fb.iout=0;
// return it
return fb;
}
Branching QTildeShowerHandler::selectSpaceLikeDecayBranching(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass,ShowerInteraction type,
HardBranchingPtr branch) {
Branching fb;
unsigned int iout=0;
while (true) {
// break if doing truncated shower and no truncated shower needed
if(branch && (!isTruncatedShowerON()||hardOnly())) break;
// select branching
fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass,
_initialenhance,type);
// return if no radiation
if(!fb.kinematics) break;
// special for truncated shower
if(branch) {
// check haven't evolved too far
if(fb.kinematics->scale() < branch->scale()) {
fb=Branching();
break;
}
// find the truncated line
iout=0;
if(fb.ids[1]->id()!=fb.ids[2]->id()) {
if(fb.ids[1]->id()==particle->id()) iout=1;
else if (fb.ids[2]->id()==particle->id()) iout=2;
}
else if(fb.ids[1]->id()==particle->id()) {
if(fb.kinematics->z()>0.5) iout=1;
else iout=2;
}
// apply the vetos for the truncated shower
// no flavour changing branchings
if(iout==0) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
ShowerInteraction type2 = convertInteraction(fb.type);
double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z();
if(type2==branch->sudakov()->interactionType()) {
if(zsplit < 0.5 || // hardest line veto
fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// pt veto
if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
}
// if not vetoed break
if(spaceLikeDecayVetoed(fb,particle)) {
// otherwise reset scale and continue
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
break;
}
// normal case
if(!branch) {
if(fb.kinematics) fb.hard = false;
return fb;
}
// truncated emission
if(fb.kinematics) {
fb.hard = false;
fb.iout = iout;
return fb;
}
// otherwise need to return the hard emission
// construct the kinematics for the hard emission
ShoKinPtr showerKin=
branch->sudakov()->createDecayBranching(branch->scale(),
branch->children()[0]->z(),
branch->phi(),
branch->children()[0]->pT());
IdList idlist(3);
idlist[0] = particle->dataPtr();
idlist[1] = branch->children()[0]->branchingParticle()->dataPtr();
idlist[2] = branch->children()[1]->branchingParticle()->dataPtr();
// create the branching
fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine );
fb.hard=true;
fb.iout=0;
// return it
return fb;
}
void QTildeShowerHandler::checkFlags() {
string error = "Inconsistent hard emission set-up in QTildeShowerHandler::showerHardProcess(). ";
if ( ( currentTree()->isMCatNLOSEvent() || currentTree()->isMCatNLOHEvent() ) ) {
if (_hardEmission ==2 )
throw Exception() << error
<< "Cannot generate POWHEG matching with MC@NLO shower "
<< "approximation. Add 'set QTildeShowerHandler:HardEmission 0' to input file."
<< Exception::runerror;
if ( canHandleMatchboxTrunc() )
throw Exception() << error
<< "Cannot use truncated qtilde shower with MC@NLO shower "
<< "approximation. Set LHCGenerator:EventHandler"
<< ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or "
<< "'/Herwig/Shower/Dipole/DipoleShowerHandler'."
<< Exception::runerror;
}
else if ( ((currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) ) &&
_hardEmission != 2){
if ( canHandleMatchboxTrunc())
throw Exception() << error
<< "Unmatched events requested for POWHEG shower "
<< "approximation. Set QTildeShowerHandler:HardEmission to "
<< "'POWHEG'."
<< Exception::runerror;
else if (_hardEmissionWarn) {
_hardEmissionWarn = false;
_hardEmission=2;
throw Exception() << error
<< "Unmatched events requested for POWHEG shower "
<< "approximation. Changing QTildeShowerHandler:HardEmission from "
<< _hardEmission << " to 2"
<< Exception::warning;
}
}
if ( currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) {
if (currentTree()->showerApproximation()->needsTruncatedShower() &&
!canHandleMatchboxTrunc() )
throw Exception() << error
<< "Current shower handler cannot generate truncated shower. "
<< "Set Generator:EventHandler:CascadeHandler to "
<< "'/Herwig/Shower/PowhegShowerHandler'."
<< Exception::runerror;
}
else if ( currentTree()->truncatedShower() && _missingTruncWarn) {
_missingTruncWarn=false;
throw Exception() << "Warning: POWHEG shower approximation used without "
<< "truncated shower. Set Generator:EventHandler:"
<< "CascadeHandler to '/Herwig/Shower/PowhegShowerHandler' and "
<< "'MEMatching:TruncatedShower Yes'."
<< Exception::warning;
}
// else if ( !dipme && _hardEmissionMode > 1 &&
// firstInteraction())
// throw Exception() << error
// << "POWHEG matching requested for LO events. Include "
// << "'set Factory:ShowerApproximation MEMatching' in input file."
// << Exception::runerror;
}
tPPair QTildeShowerHandler::remakeRemnant(tPPair oldp){
// get the parton extractor
PartonExtractor & pex = *lastExtractor();
// get the new partons
tPPair newp = make_pair(findFirstParton(oldp.first ),
findFirstParton(oldp.second));
// if the same do nothing
if(newp == oldp) return oldp;
// Creates the new remnants and returns the new PartonBinInstances
// ATTENTION Broken here for very strange configuration
PBIPair newbins = pex.newRemnants(oldp, newp, newStep());
newStep()->addIntermediate(newp.first);
newStep()->addIntermediate(newp.second);
// return the new partons
return newp;
}
PPtr QTildeShowerHandler::findFirstParton(tPPtr seed) const{
if(seed->parents().empty()) return seed;
tPPtr parent = seed->parents()[0];
//if no parent there this is a loose end which will
//be connected to the remnant soon.
if(!parent || parent == incomingBeams().first ||
parent == incomingBeams().second ) return seed;
else return findFirstParton(parent);
}
void QTildeShowerHandler::decay(ShowerTreePtr tree, ShowerDecayMap & decay) {
// must be one incoming particle
assert(tree->incomingLines().size()==1);
// apply any transforms
tree->applyTransforms();
// if already decayed return
if(!tree->outgoingLines().empty()) return;
// now we need to replace the particle with a new copy after the shower
// find particle after the shower
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator
tit = tree->parent()->treelinks().find(tree);
assert(tit!=tree->parent()->treelinks().end());
ShowerParticlePtr newparent=tit->second.second;
PerturbativeProcessPtr newProcess = new_ptr(PerturbativeProcess());
newProcess->incoming().push_back(make_pair(newparent,PerturbativeProcessPtr()));
DecayProcessMap decayMap;
ShowerHandler::decay(newProcess,decayMap);
ShowerTree::constructTrees(tree,decay,newProcess,decayMap);
}
namespace {
ShowerProgenitorPtr
findFinalStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) {
map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator partner;
Energy2 dmin(1e30*GeV2);
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator
cit =tree->outgoingLines().begin(); cit!=tree->outgoingLines().end(); ++cit) {
if(cit->second->id()!=id) continue;
Energy2 test =
sqr(cit->second->momentum().x()-momentum.x())+
sqr(cit->second->momentum().y()-momentum.y())+
sqr(cit->second->momentum().z()-momentum.z())+
sqr(cit->second->momentum().t()-momentum.t());
if(test<dmin) {
dmin = test;
partner = cit;
}
}
return partner->first;
}
ShowerProgenitorPtr
findInitialStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) {
map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator partner;
Energy2 dmin(1e30*GeV2);
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator
cit =tree->incomingLines().begin(); cit!=tree->incomingLines().end(); ++cit) {
if(cit->second->id()!=id) continue;
Energy2 test =
sqr(cit->second->momentum().x()-momentum.x())+
sqr(cit->second->momentum().y()-momentum.y())+
sqr(cit->second->momentum().z()-momentum.z())+
sqr(cit->second->momentum().t()-momentum.t());
if(test<dmin) {
dmin = test;
partner = cit;
}
}
return partner->first;
}
void fixSpectatorColours(PPtr newSpect,ShowerProgenitorPtr oldSpect,
ColinePair & cline,ColinePair & aline, bool reconnect) {
cline.first = oldSpect->progenitor()->colourLine();
cline.second = newSpect->colourLine();
aline.first = oldSpect->progenitor()->antiColourLine();
aline.second = newSpect->antiColourLine();
if(!reconnect) return;
if(cline.first) {
cline.first ->removeColoured(oldSpect->copy());
cline.first ->removeColoured(oldSpect->progenitor());
cline.second->removeColoured(newSpect);
cline.first ->addColoured(newSpect);
}
if(aline.first) {
aline.first ->removeAntiColoured(oldSpect->copy());
aline.first ->removeAntiColoured(oldSpect->progenitor());
aline.second->removeAntiColoured(newSpect);
aline.first ->addAntiColoured(newSpect);
}
}
void fixInitialStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter,
ColinePair cline,ColinePair aline,double x) {
// sort out the colours
if(emitted->dataPtr()->iColour()==PDT::Colour8) {
// emitter
if(cline.first && cline.first == emitter->progenitor()->antiColourLine() &&
cline.second !=newEmit->antiColourLine()) {
// sort out not radiating line
ColinePtr col = emitter->progenitor()->colourLine();
if(col) {
col->removeColoured(emitter->copy());
col->removeColoured(emitter->progenitor());
newEmit->colourLine()->removeColoured(newEmit);
col->addColoured(newEmit);
}
}
else if(aline.first && aline.first == emitter->progenitor()->colourLine() &&
aline.second !=newEmit->colourLine()) {
// sort out not radiating line
ColinePtr anti = emitter->progenitor()->antiColourLine();
if(anti) {
anti->removeAntiColoured(emitter->copy());
anti->removeAntiColoured(emitter->progenitor());
newEmit->colourLine()->removeAntiColoured(newEmit);
anti->addAntiColoured(newEmit);
}
}
else
assert(false);
// emitted
if(cline.first && cline.second==emitted->colourLine()) {
cline.second->removeColoured(emitted);
cline.first->addColoured(emitted);
}
else if(aline.first && aline.second==emitted->antiColourLine()) {
aline.second->removeAntiColoured(emitted);
aline.first->addAntiColoured(emitted);
}
else
assert(false);
}
else {
if(emitter->progenitor()->antiColourLine() ) {
ColinePtr col = emitter->progenitor()->antiColourLine();
col->removeAntiColoured(emitter->copy());
col->removeAntiColoured(emitter->progenitor());
if(newEmit->antiColourLine()) {
newEmit->antiColourLine()->removeAntiColoured(newEmit);
col->addAntiColoured(newEmit);
}
else if (emitted->colourLine()) {
emitted->colourLine()->removeColoured(emitted);
col->addColoured(emitted);
}
else
assert(false);
}
if(emitter->progenitor()->colourLine() ) {
ColinePtr col = emitter->progenitor()->colourLine();
col->removeColoured(emitter->copy());
col->removeColoured(emitter->progenitor());
if(newEmit->colourLine()) {
newEmit->colourLine()->removeColoured(newEmit);
col->addColoured(newEmit);
}
else if (emitted->antiColourLine()) {
emitted->antiColourLine()->removeAntiColoured(emitted);
col->addAntiColoured(emitted);
}
else
assert(false);
}
}
// update the emitter
emitter->copy(newEmit);
ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,false));
sp->x(x);
emitter->progenitor(sp);
tree->incomingLines()[emitter]=sp;
emitter->perturbative(false);
// add emitted
sp=new_ptr(ShowerParticle(*emitted,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(),emitted,sp));
gluon->perturbative(false);
tree->outgoingLines().insert(make_pair(gluon,sp));
}
void fixFinalStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter,
ColinePair cline,ColinePair aline) {
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit;
// special case if decayed
for(tit = tree->treelinks().begin(); tit != tree->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==emitter->progenitor())
break;
}
// sort out the colour lines
if(cline.first && cline.first == emitter->progenitor()->antiColourLine() &&
cline.second !=newEmit->antiColourLine()) {
// sort out not radiating line
ColinePtr col = emitter->progenitor()->colourLine();
if(col) {
col->removeColoured(emitter->copy());
col->removeColoured(emitter->progenitor());
newEmit->colourLine()->removeColoured(newEmit);
col->addColoured(newEmit);
}
}
else if(aline.first && aline.first == emitter->progenitor()->colourLine() &&
aline.second !=newEmit->colourLine()) {
// sort out not radiating line
ColinePtr anti = emitter->progenitor()->antiColourLine();
if(anti) {
anti->removeAntiColoured(emitter->copy());
anti->removeAntiColoured(emitter->progenitor());
newEmit->colourLine()->removeAntiColoured(newEmit);
anti->addAntiColoured(newEmit);
}
}
else
assert(false);
// update the emitter
emitter->copy(newEmit);
ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,true));
emitter->progenitor(sp);
tree->outgoingLines()[emitter]=sp;
emitter->perturbative(false);
// update for decaying particles
if(tit!=tree->treelinks().end())
tree->updateLink(tit->first,make_pair(emitter,sp));
// add the emitted particle
// sort out the colour
if(cline.first && cline.second==emitted->antiColourLine()) {
cline.second->removeAntiColoured(emitted);
cline.first->addAntiColoured(emitted);
}
else if(aline.first && aline.second==emitted->colourLine()) {
aline.second->removeColoured(emitted);
aline.first->addColoured(emitted);
}
else
assert(false);
sp=new_ptr(ShowerParticle(*emitted,1,true));
ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(),
emitted,sp));
gluon->perturbative(false);
tree->outgoingLines().insert(make_pair(gluon,sp));
}
}
void QTildeShowerHandler::setupMECorrection(RealEmissionProcessPtr real) {
assert(real);
currentTree()->hardMatrixElementCorrection(true);
// II emission
if(real->emitter() < real->incoming().size() &&
real->spectator() < real->incoming().size()) {
// recoiling system
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= currentTree()->outgoingLines().begin();
cjt != currentTree()->outgoingLines().end();++cjt ) {
cjt->first->progenitor()->transform(real->transformation());
cjt->first->copy()->transform(real->transformation());
}
// the the radiating system
ShowerProgenitorPtr emitter,spectator;
unsigned int iemit = real->emitter();
unsigned int ispect = real->spectator();
int ig = int(real->emitted())-int(real->incoming().size());
emitter = findInitialStateLine(currentTree(),
real->bornIncoming()[iemit]->id(),
real->bornIncoming()[iemit]->momentum());
spectator = findInitialStateLine(currentTree(),
real->bornIncoming()[ispect]->id(),
real->bornIncoming()[ispect]->momentum());
// sort out the colours
ColinePair cline,aline;
fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true);
// update the spectator
spectator->copy(real->incoming()[ispect]);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false)));
sp->x(ispect ==0 ? real->x().first :real->x().second);
spectator->progenitor(sp);
currentTree()->incomingLines()[spectator]=sp;
spectator->perturbative(true);
// now for the emitter
fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig],
emitter,cline,aline,iemit ==0 ? real->x().first :real->x().second);
}
// FF emission
else if(real->emitter() >= real->incoming().size() &&
real->spectator() >= real->incoming().size()) {
assert(real->outgoing()[real->emitted()-real->incoming().size()]->id()==ParticleID::g);
// find the emitter and spectator in the shower tree
ShowerProgenitorPtr emitter,spectator;
int iemit = int(real->emitter())-int(real->incoming().size());
emitter = findFinalStateLine(currentTree(),
real->bornOutgoing()[iemit]->id(),
real->bornOutgoing()[iemit]->momentum());
int ispect = int(real->spectator())-int(real->incoming().size());
spectator = findFinalStateLine(currentTree(),
real->bornOutgoing()[ispect]->id(),
real->bornOutgoing()[ispect]->momentum());
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit;
// first the spectator
// special case if decayed
for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==spectator->progenitor())
break;
}
// sort out the colours
ColinePair cline,aline;
fixSpectatorColours(real->outgoing()[ispect],spectator,cline,aline,true);
// update the spectator
spectator->copy(real->outgoing()[ispect]);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect],1,true)));
spectator->progenitor(sp);
currentTree()->outgoingLines()[spectator]=sp;
spectator->perturbative(true);
// update for decaying particles
if(tit!=currentTree()->treelinks().end())
currentTree()->updateLink(tit->first,make_pair(spectator,sp));
// now the emitting particle
int ig = int(real->emitted())-int(real->incoming().size());
fixFinalStateEmitter(currentTree(),real->outgoing()[iemit],
real->outgoing()[ig],
emitter,cline,aline);
}
// IF emission
else {
// scattering process
if(real->incoming().size()==2) {
ShowerProgenitorPtr emitter,spectator;
unsigned int iemit = real->emitter();
unsigned int ispect = real->spectator();
int ig = int(real->emitted())-int(real->incoming().size());
ColinePair cline,aline;
// incoming spectator
if(ispect<2) {
spectator = findInitialStateLine(currentTree(),
real->bornIncoming()[ispect]->id(),
real->bornIncoming()[ispect]->momentum());
fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true);
// update the spectator
spectator->copy(real->incoming()[ispect]);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false)));
sp->x(ispect ==0 ? real->x().first :real->x().second);
spectator->progenitor(sp);
currentTree()->incomingLines()[spectator]=sp;
spectator->perturbative(true);
}
// outgoing spectator
else {
spectator = findFinalStateLine(currentTree(),
real->bornOutgoing()[ispect-real->incoming().size()]->id(),
real->bornOutgoing()[ispect-real->incoming().size()]->momentum());
// special case if decayed
map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit;
for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==spectator->progenitor())
break;
}
fixSpectatorColours(real->outgoing()[ispect-real->incoming().size()],spectator,cline,aline,true);
// update the spectator
spectator->copy(real->outgoing()[ispect-real->incoming().size()]);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect-real->incoming().size()],1,true)));
spectator->progenitor(sp);
currentTree()->outgoingLines()[spectator]=sp;
spectator->perturbative(true);
// update for decaying particles
if(tit!=currentTree()->treelinks().end())
currentTree()->updateLink(tit->first,make_pair(spectator,sp));
}
// incoming emitter
if(iemit<2) {
emitter = findInitialStateLine(currentTree(),
real->bornIncoming()[iemit]->id(),
real->bornIncoming()[iemit]->momentum());
fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig],
emitter,aline,cline,iemit ==0 ? real->x().first :real->x().second);
}
// outgoing emitter
else {
emitter = findFinalStateLine(currentTree(),
real->bornOutgoing()[iemit-real->incoming().size()]->id(),
real->bornOutgoing()[iemit-real->incoming().size()]->momentum());
fixFinalStateEmitter(currentTree(),real->outgoing()[iemit-real->incoming().size()],
real->outgoing()[ig],emitter,aline,cline);
}
}
// decay process
else {
assert(real->spectator()==0);
unsigned int iemit = real->emitter()-real->incoming().size();
int ig = int(real->emitted())-int(real->incoming().size());
ColinePair cline,aline;
// incoming spectator
ShowerProgenitorPtr spectator = findInitialStateLine(currentTree(),
real->bornIncoming()[0]->id(),
real->bornIncoming()[0]->momentum());
fixSpectatorColours(real->incoming()[0],spectator,cline,aline,false);
// find the emitter
ShowerProgenitorPtr emitter =
findFinalStateLine(currentTree(),
real->bornOutgoing()[iemit]->id(),
real->bornOutgoing()[iemit]->momentum());
// recoiling system
for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cjt= currentTree()->outgoingLines().begin();
cjt != currentTree()->outgoingLines().end();++cjt ) {
if(cjt->first==emitter) continue;
cjt->first->progenitor()->transform(real->transformation());
cjt->first->copy()->transform(real->transformation());
}
// sort out the emitter
fixFinalStateEmitter(currentTree(),real->outgoing()[iemit],
real->outgoing()[ig],emitter,aline,cline);
}
}
// clean up the shower tree
_currenttree->resetShowerProducts();
}
diff --git a/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.cc b/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.cc
--- a/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.cc
+++ b/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.cc
@@ -1,134 +1,134 @@
// -*- C++ -*-
//
// HalfHalfOneSplitFn.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the HalfHalfOneSplitFn class.
//
#include "HalfHalfOneSplitFn.h"
#include "ThePEG/PDT/ParticleData.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Decay/TwoBodyDecayMatrixElement.h"
using namespace Herwig;
DescribeNoPIOClass<HalfHalfOneSplitFn,Herwig::SplittingFunction>
describeHalfHalfOneSplitFn ("Herwig::HalfHalfOneSplitFn","HwShower.so");
void HalfHalfOneSplitFn::Init() {
static ClassDocumentation<HalfHalfOneSplitFn> documentation
("The HalfHalfOneSplitFn class implements the q -> qg splitting function");
}
double HalfHalfOneSplitFn::P(const double z, const Energy2 t,
const IdList &ids, const bool mass, const RhoDMatrix &) const {
double val = (1. + sqr(z))/(1.-z);
if(mass) {
Energy m = ids[0]->mass();
val -= 2.*sqr(m)/t;
}
return colourFactor(ids)*val;
}
double HalfHalfOneSplitFn::overestimateP(const double z,
const IdList & ids) const {
return 2.*colourFactor(ids)/(1.-z);
}
double HalfHalfOneSplitFn::ratioP(const double z, const Energy2 t,
const IdList & ids, const bool mass, const RhoDMatrix &) const {
double val = 1. + sqr(z);
if(mass) {
Energy m = ids[0]->mass();
val -= 2.*sqr(m)*(1.-z)/t;
}
return 0.5*val;
}
double HalfHalfOneSplitFn::integOverP(const double z,
const IdList & ids,
unsigned int PDFfactor) const {
switch (PDFfactor) {
case 0:
return -2.*colourFactor(ids)*Math::log1m(z);
case 1:
return 2.*colourFactor(ids)*log(z/(1.-z));
case 2:
return 2.*colourFactor(ids)/(1.-z);
case 3:
default:
throw Exception() << "HalfHalfOneSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
double HalfHalfOneSplitFn::invIntegOverP(const double r, const IdList & ids,
unsigned int PDFfactor) const {
switch (PDFfactor) {
case 0:
return 1. - exp(- 0.5*r/colourFactor(ids));
case 1:
return 1./(1.-exp(-0.5*r/colourFactor(ids)));
case 2:
return 1.-2.*colourFactor(ids)/r;
case 3:
default:
throw Exception() << "HalfHalfOneSplitFn::invIntegOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
bool HalfHalfOneSplitFn::accept(const IdList &ids) const {
// 3 particles and in and out fermion same
if(ids.size()!=3 || ids[0]!=ids[1]) return false;
if(ids[0]->iSpin()!=PDT::Spin1Half ||
ids[2]->iSpin()!=PDT::Spin1) return false;
return checkColours(ids);
}
vector<pair<int, Complex> >
HalfHalfOneSplitFn::generatePhiForward(const double, const Energy2, const IdList & ,
const RhoDMatrix &) {
// no dependence on the spin density matrix, dependence on off-diagonal terms cancels
// and rest = splitting function for Tr(rho)=1 as required by defn
- return vector<pair<int, Complex> >(1,make_pair(0,1.));
+ return {{ {0, 1.} }};
}
vector<pair<int, Complex> >
HalfHalfOneSplitFn::generatePhiBackward(const double, const Energy2, const IdList & ,
const RhoDMatrix &) {
// no dependence on the spin density matrix, dependence on off-diagonal terms cancels
// and rest = splitting function for Tr(rho)=1 as required by defn
- return vector<pair<int, Complex> >(1,make_pair(0,1.));
+ return {{ {0, 1.} }};
}
DecayMEPtr HalfHalfOneSplitFn::matrixElement(const double z, const Energy2 t,
const IdList & ids, const double phi,
bool timeLike) {
// calculate the kernal
DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin1)));
Energy m = !timeLike ? ZERO : ids[0]->mass();
double mt = m/sqrt(t);
double root = sqrt(1.-(1.-z)*sqr(m)/z/t);
double romz = sqrt(1.-z);
double rz = sqrt(z);
Complex phase = exp(Complex(0.,1.)*phi);
(*kernal)(0,0,0) = -root/romz*phase;
(*kernal)(1,1,2) = -conj((*kernal)(0,0,0));
(*kernal)(0,0,2) = root/romz*z/phase;
(*kernal)(1,1,0) = -conj((*kernal)(0,0,2));
(*kernal)(1,0,2) = mt*(1.-z)/rz;
(*kernal)(0,1,0) = conj((*kernal)(1,0,2));
(*kernal)(0,1,2) = 0.;
(*kernal)(1,0,0) = 0.;
return kernal;
}
diff --git a/Shower/QTilde/SplittingFunctions/HalfOneHalfSplitFn.cc b/Shower/QTilde/SplittingFunctions/HalfOneHalfSplitFn.cc
--- a/Shower/QTilde/SplittingFunctions/HalfOneHalfSplitFn.cc
+++ b/Shower/QTilde/SplittingFunctions/HalfOneHalfSplitFn.cc
@@ -1,143 +1,143 @@
// -*- C++ -*-
//
// HalfOneHalfSplitFn.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the HalfOneHalfSplitFn class.
//
#include "HalfOneHalfSplitFn.h"
#include "ThePEG/PDT/ParticleData.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Decay/TwoBodyDecayMatrixElement.h"
using namespace Herwig;
DescribeNoPIOClass<HalfOneHalfSplitFn,Herwig::SplittingFunction>
describeHalfOneHalfSplitFn ("Herwig::HalfOneHalfSplitFn","HwShower.so");
void HalfOneHalfSplitFn::Init() {
static ClassDocumentation<HalfOneHalfSplitFn> documentation
("The HalfOneHalfSplitFn class implements the splitting "
"function for q -> g q");
}
double HalfOneHalfSplitFn::P(const double z, const Energy2 t,
const IdList &ids, const bool mass, const RhoDMatrix & ) const {
double val=(2.*(1.-z)+sqr(z))/z;
if(mass) {
Energy m = ids[0]->mass();
val-=2.*sqr(m)/t;
}
return colourFactor(ids)*val;
}
double HalfOneHalfSplitFn::overestimateP(const double z,
const IdList &ids) const {
return 2.*colourFactor(ids)/z;
}
double HalfOneHalfSplitFn::ratioP(const double z, const Energy2 t,
const IdList &ids,const bool mass, const RhoDMatrix & ) const {
double val=2.*(1.-z)+sqr(z);
if(mass) {
Energy m=ids[0]->mass();
val -=2.*sqr(m)*z/t;
}
return 0.5*val;
}
double HalfOneHalfSplitFn::integOverP(const double z, const IdList & ids,
unsigned int PDFfactor) const {
switch(PDFfactor) {
case 0:
return 2.*colourFactor(ids)*log(z);
case 1:
return -2.*colourFactor(ids)/z;
case 2:
return 2.*colourFactor(ids)*log(z/(1.-z));
case 3:
default:
throw Exception() << "HalfOneHalfSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
double HalfOneHalfSplitFn::invIntegOverP(const double r,
const IdList & ids,
unsigned int PDFfactor) const {
switch(PDFfactor) {
case 0:
return exp(0.5*r/colourFactor(ids));
case 1:
return -2.*colourFactor(ids)/r;
case 2:
return 1./(1.+exp(-0.5*r/colourFactor(ids)));
case 3:
default:
throw Exception() << "HalfOneHalfSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
bool HalfOneHalfSplitFn::accept(const IdList &ids) const {
// 3 particles and in and out fermion same
if(ids.size()!=3 || ids[0]!=ids[2]) return false;
if(ids[0]->iSpin()!=PDT::Spin1Half ||
ids[1]->iSpin()!=PDT::Spin1) return false;
return checkColours(ids);
}
vector<pair<int, Complex> >
HalfOneHalfSplitFn::generatePhiForward(const double, const Energy2, const IdList & ,
const RhoDMatrix &) {
// no dependence on the spin density matrix, dependence on off-diagonal terms cancels
// and rest = splitting function for Tr(rho)=1 as required by defn
- return vector<pair<int, Complex> >(1,make_pair(0,1.));
+ return {{ {0, 1.} }};
}
vector<pair<int, Complex> >
HalfOneHalfSplitFn::generatePhiBackward(const double z, const Energy2 t, const IdList & ids,
const RhoDMatrix & rho) {
assert(rho.iSpin()==PDT::Spin1);
double mt = sqr(ids[0]->mass())/t;
double diag = (1.+sqr(1.-z))/z - 2.*mt;
double off = 2.*(1.-z)/z*(1.-mt*z/(1.-z));
double max = diag+2.*abs(rho(0,2))*off;
vector<pair<int, Complex> > output;
output.push_back(make_pair( 0, (rho(0,0)+rho(2,2))*diag/max));
output.push_back(make_pair( 2, -rho(0,2) * off/max));
output.push_back(make_pair(-2, -rho(2,0) * off/max));
return output;
}
DecayMEPtr HalfOneHalfSplitFn::matrixElement(const double z, const Energy2 t,
const IdList & ids, const double phi,
bool timeLike) {
// calculate the kernal
DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1Half,PDT::Spin1,PDT::Spin1Half)));
Energy m = !timeLike ? ZERO : ids[0]->mass();
double mt = m/sqrt(t);
double root = sqrt(1.-z*sqr(m)/(1.-z)/t);
double romz = sqrt(1.-z);
double rz = sqrt(z);
Complex phase = exp(-Complex(0.,1.)*phi);
(*kernal)(0,0,0) = -root/rz/phase;
(*kernal)(1,2,1) = -conj((*kernal)(0,0,0));
(*kernal)(0,2,0) = root/rz*(1.-z)*phase;
(*kernal)(1,0,1) = -conj((*kernal)(0,2,0));
(*kernal)(1,2,0) = mt*z/romz;
(*kernal)(0,0,1) = conj((*kernal)(1,2,0));
(*kernal)(0,2,1) = 0.;
(*kernal)(1,0,0) = 0.;
return kernal;
}
diff --git a/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.cc b/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.cc
--- a/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.cc
+++ b/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.cc
@@ -1,150 +1,150 @@
// -*- C++ -*-
//
// OneHalfHalfSplitFn.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the OneHalfHalfSplitFn class.
//
#include "OneHalfHalfSplitFn.h"
#include "ThePEG/PDT/ParticleData.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Decay/TwoBodyDecayMatrixElement.h"
using namespace Herwig;
DescribeNoPIOClass<OneHalfHalfSplitFn,Herwig::SplittingFunction>
describeOneHalfHalfSplitFn ("Herwig::OneHalfHalfSplitFn","HwShower.so");
void OneHalfHalfSplitFn::Init() {
static ClassDocumentation<OneHalfHalfSplitFn> documentation
("The OneHalfHalfSplitFn class implements the splitting function for g->q qbar");
}
double OneHalfHalfSplitFn::P(const double z, const Energy2 t,
const IdList &ids, const bool mass, const RhoDMatrix &) const {
double zz = z*(1.-z);
double val=1.-2.*zz;
if(mass) {
Energy m = ids[1]->mass();
val +=2.*sqr(m)/t;
}
return colourFactor(ids)*val;
}
double OneHalfHalfSplitFn::overestimateP(const double,
const IdList &ids) const {
return colourFactor(ids);
}
double OneHalfHalfSplitFn::ratioP(const double z, const Energy2 t,
const IdList &ids, const bool mass, const RhoDMatrix &) const {
double zz = z*(1.-z);
double val = 1.-2.*zz;
if(mass) {
Energy m = ids[1]->mass();
val+= 2.*sqr(m)/t;
}
return val;
}
double OneHalfHalfSplitFn::integOverP(const double z, const IdList & ids,
unsigned int PDFfactor) const {
switch(PDFfactor) {
case 0:
return colourFactor(ids)*z;
case 1:
return colourFactor(ids)*log(z);
case 2:
return -colourFactor(ids)*log(1.-z);
case 3:
return colourFactor(ids)*log(z/(1.-z));
case 4:
return colourFactor(ids)*2.*sqrt(z);
case 5:
return colourFactor(ids)*(2./3.)*z*sqrt(z);
default:
throw Exception() << "OneHalfHalfSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
double OneHalfHalfSplitFn::invIntegOverP(const double r,
const IdList & ids,
unsigned int PDFfactor) const {
switch(PDFfactor) {
case 0:
return r/colourFactor(ids);
case 1:
return exp(r/colourFactor(ids));
case 2:
return 1.-exp(-r/colourFactor(ids));
case 3:
return 1./(1.+exp(-r/colourFactor(ids)));
case 4:
return 0.25*sqr(r/colourFactor(ids));
case 5:
return pow(1.5*r/colourFactor(ids),2./3.);
default:
throw Exception() << "OneHalfHalfSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
bool OneHalfHalfSplitFn::accept(const IdList &ids) const {
if(ids.size()!=3) return false;
if(ids[1]!=ids[2]->CC()) return false;
if(ids[1]->iSpin()!=PDT::Spin1Half) return false;
if(ids[0]->iSpin()!=PDT::Spin1) return false;
return checkColours(ids);
}
vector<pair<int, Complex> >
OneHalfHalfSplitFn::generatePhiForward(const double z, const Energy2 t, const IdList & ids,
const RhoDMatrix & rho) {
assert(rho.iSpin()==PDT::Spin1);
double modRho = abs(rho(0,2));
Energy mq = ids[1]->mass();
Energy2 mq2 = sqr(mq);
double fact = z*(1.-z)-mq2/t;
double max = 1.+2.*fact*(-1.+2.*modRho);
vector<pair<int, Complex> > output;
output.push_back(make_pair( 0,(rho(0,0)+rho(2,2))*(1.-2.*fact)/max));
output.push_back(make_pair(-2,2.*fact*rho(0,2)/max));
output.push_back(make_pair( 2,2.*fact*rho(2,0)/max));
return output;
}
vector<pair<int, Complex> >
OneHalfHalfSplitFn::generatePhiBackward(const double, const Energy2, const IdList &,
const RhoDMatrix & ) {
// no dependance
- return vector<pair<int, Complex> >(1,make_pair(0,1.));
+ return {{ {0, 1.} }};
}
DecayMEPtr OneHalfHalfSplitFn::matrixElement(const double z, const Energy2 t,
const IdList & ids, const double phi,
bool timeLike) {
static const Complex ii(0.,1.);
// calculate the kernal
DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half)));
double mt = !timeLike ? ZERO : ids[1]->mass()/sqrt(t);
double root =sqrt(1.-sqr(mt)/z/(1.-z));
(*kernal)(0,0,0) = mt/sqrt(z*(1.-z));
(*kernal)(2,1,1) = (*kernal)(0,0,0);
(*kernal)(0,0,1) = -z*root*exp(-ii*phi);
(*kernal)(2,1,0) = -conj((*kernal)(0,0,1));
(*kernal)(0,1,0) = (1.-z)*exp(-ii*phi)*root;
(*kernal)(2,0,1) = -conj((*kernal)(0,1,0));
(*kernal)(0,1,1) = 0.;
(*kernal)(2,0,0) = 0.;
return kernal;
}
diff --git a/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc b/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc
--- a/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc
+++ b/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc
@@ -1,642 +1,648 @@
// -*- C++ -*-
//
// SplittingGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the SplittingGenerator class.
//
#include "SplittingGenerator.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Command.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Utilities/StringUtils.h"
#include "ThePEG/Repository/Repository.h"
#include "Herwig/Shower/QTilde/Base/ShowerParticle.h"
#include "Herwig/Shower/ShowerHandler.h"
#include "ThePEG/Utilities/Rebinder.h"
#include <cassert>
#include "ThePEG/Utilities/DescribeClass.h"
using namespace Herwig;
namespace {
bool checkInteraction(ShowerInteraction allowed,
ShowerInteraction splitting) {
if(allowed==ShowerInteraction::ALL)
return true;
else if(allowed==ShowerInteraction::QEDQCD &&
(splitting==ShowerInteraction::QED ||
splitting==ShowerInteraction::QCD ))
return true;
else if(allowed == splitting)
return true;
else
return false;
}
}
DescribeClass<SplittingGenerator,Interfaced>
describeSplittingGenerator ("Herwig::SplittingGenerator","");
IBPtr SplittingGenerator::clone() const {
return new_ptr(*this);
}
IBPtr SplittingGenerator::fullclone() const {
return new_ptr(*this);
}
void SplittingGenerator::persistentOutput(PersistentOStream & os) const {
os << _bbranchings << _fbranchings << _deTuning;
}
void SplittingGenerator::persistentInput(PersistentIStream & is, int) {
is >> _bbranchings >> _fbranchings >> _deTuning;
}
void SplittingGenerator::Init() {
static ClassDocumentation<SplittingGenerator> documentation
("There class is responsible for initializing the Sudakov form factors ",
"and generating splittings.");
static Command<SplittingGenerator> interfaceAddSplitting
("AddFinalSplitting",
"Adds another splitting to the list of splittings considered "
"in the shower. Command is a->b,c; Sudakov",
&SplittingGenerator::addFinalSplitting);
static Command<SplittingGenerator> interfaceAddInitialSplitting
("AddInitialSplitting",
"Adds another splitting to the list of initial splittings to consider "
"in the shower. Command is a->b,c; Sudakov. Here the particle a is the "
"particle that is PRODUCED by the splitting. b is the initial state "
"particle that is splitting in the shower.",
&SplittingGenerator::addInitialSplitting);
static Command<SplittingGenerator> interfaceDeleteSplitting
("DeleteFinalSplitting",
"Deletes a splitting from the list of splittings considered "
"in the shower. Command is a->b,c; Sudakov",
&SplittingGenerator::deleteFinalSplitting);
static Command<SplittingGenerator> interfaceDeleteInitialSplitting
("DeleteInitialSplitting",
"Deletes a splitting from the list of initial splittings to consider "
"in the shower. Command is a->b,c; Sudakov. Here the particle a is the "
"particle that is PRODUCED by the splitting. b is the initial state "
"particle that is splitting in the shower.",
&SplittingGenerator::deleteInitialSplitting);
static Parameter<SplittingGenerator,double> interfaceDetuning
("Detuning",
"The Detuning parameter to make the veto algorithm less efficient to improve the weight variations",
&SplittingGenerator::_deTuning, 1.0, 1.0, 10.0,
false, false, Interface::limited);
}
string SplittingGenerator::addSplitting(string arg, bool final) {
string partons = StringUtils::car(arg);
string sudakov = StringUtils::cdr(arg);
vector<tPDPtr> products;
string::size_type next = partons.find("->");
if(next == string::npos)
return "Error: Invalid string for splitting " + arg;
if(partons.find(';') == string::npos)
return "Error: Invalid string for splitting " + arg;
tPDPtr parent = Repository::findParticle(partons.substr(0,next));
partons = partons.substr(next+2);
do {
next = min(partons.find(','), partons.find(';'));
tPDPtr pdp = Repository::findParticle(partons.substr(0,next));
partons = partons.substr(next+1);
if(pdp) products.push_back(pdp);
else return "Error: Could not create splitting from " + arg;
} while(partons[0] != ';' && partons.size());
SudakovPtr s;
s = dynamic_ptr_cast<SudakovPtr>(Repository::TraceObject(sudakov));
if(!s) return "Error: Could not load Sudakov " + sudakov + '\n';
IdList ids;
ids.push_back(parent);
for(vector<tPDPtr>::iterator it = products.begin(); it!=products.end(); ++it)
ids.push_back(*it);
// check splitting can handle this
if(!s->splittingFn()->accept(ids))
return "Error: Sudakov " + sudakov + " SplittingFunction can't handle particles\n";
// add to map
addToMap(ids,s,final);
return "";
}
string SplittingGenerator::deleteSplitting(string arg, bool final) {
string partons = StringUtils::car(arg);
string sudakov = StringUtils::cdr(arg);
vector<tPDPtr> products;
string::size_type next = partons.find("->");
if(next == string::npos)
return "Error: Invalid string for splitting " + arg;
if(partons.find(';') == string::npos)
return "Error: Invalid string for splitting " + arg;
tPDPtr parent = Repository::findParticle(partons.substr(0,next));
partons = partons.substr(next+2);
do {
next = min(partons.find(','), partons.find(';'));
tPDPtr pdp = Repository::findParticle(partons.substr(0,next));
partons = partons.substr(next+1);
if(pdp) products.push_back(pdp);
else return "Error: Could not create splitting from " + arg;
} while(partons[0] != ';' && partons.size());
SudakovPtr s;
s = dynamic_ptr_cast<SudakovPtr>(Repository::TraceObject(sudakov));
if(!s) return "Error: Could not load Sudakov " + sudakov + '\n';
IdList ids;
ids.push_back(parent);
for(vector<tPDPtr>::iterator it = products.begin(); it!=products.end(); ++it)
ids.push_back(*it);
// check splitting can handle this
if(!s->splittingFn()->accept(ids))
return "Error: Sudakov " + sudakov + " SplittingFunction can't handle particles\n";
// delete from map
deleteFromMap(ids,s,final);
return "";
}
void SplittingGenerator::addToMap(const IdList &ids, const SudakovPtr &s, bool final) {
if(!final) {
// search if the branching was already included.
auto binsert =BranchingInsert(abs(ids[1]->id()),BranchingElement(s,ids));
// get the range of already inserted splittings.
auto eqrange=_bbranchings.equal_range(binsert.first);
for(auto it = eqrange.first; it != eqrange.second; ++it){
if((*it).second == binsert.second)
throw Exception()<<"SplittingGenerator: Trying to insert existing splitting.\n"
<< Exception::setuperror;
}
_bbranchings.insert(binsert);
s->addSplitting(ids);
}
else {
// search if the branching was already included.
auto binsert =BranchingInsert(abs(ids[0]->id()),BranchingElement(s,ids));
// get the range of already inserted splittings.
auto eqrange=_fbranchings.equal_range(binsert.first);
for(auto it = eqrange.first; it != eqrange.second; ++it){
if((*it).second ==binsert.second)
throw Exception()<<"SplittingGenerator: Trying to insert existing splitting.\n"
<< Exception::setuperror;
}
_fbranchings.insert(binsert);
s->addSplitting(ids);
}
}
void SplittingGenerator::deleteFromMap(const IdList &ids,
const SudakovPtr &s, bool final) {
bool didRemove=false;
if(!final) {
pair<BranchingList::iterator,BranchingList::iterator>
range = _bbranchings.equal_range(abs(ids[1]->id()));
for(BranchingList::iterator it=range.first;
it!=range.second&&it!=_bbranchings.end();++it) {
if(it->second.sudakov==s&&it->second.particles==ids) {
BranchingList::iterator it2=it;
--it;
_bbranchings.erase(it2);
didRemove=true;
}
}
s->removeSplitting(ids);
}
else {
pair<BranchingList::iterator,BranchingList::iterator>
range = _fbranchings.equal_range(abs(ids[0]->id()));
for(BranchingList::iterator it=range.first;
it!=range.second&&it!=_fbranchings.end();++it) {
if(it->second.sudakov==s&&it->second.particles==ids) {
BranchingList::iterator it2 = it;
--it;
_fbranchings.erase(it2);
didRemove=true;
}
}
s->removeSplitting(ids);
}
if (!didRemove)
throw Exception()<<"SplittingGenerator: Try to remove non existing splitting.\n"
<< Exception::setuperror;
}
Branching SplittingGenerator::chooseForwardBranching(ShowerParticle &particle,
double enhance,
ShowerInteraction type) const {
RhoDMatrix rho;
bool rhoCalc(false);
Energy newQ = ZERO;
ShoKinPtr kinematics = ShoKinPtr();
ShowerPartnerType partnerType(ShowerPartnerType::Undefined);
SudakovPtr sudakov = SudakovPtr();
IdList ids;
// First, find the eventual branching, corresponding to the highest scale.
long index = abs(particle.data().id());
// if no branchings return empty branching struct
if( _fbranchings.find(index) == _fbranchings.end() )
return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined);
// otherwise select branching
for(BranchingList::const_iterator cit = _fbranchings.lower_bound(index);
cit != _fbranchings.upper_bound(index); ++cit) {
// check either right interaction or doing both
if(!checkInteraction(type,cit->second.sudakov->interactionType())) continue;
if(!rhoCalc) {
rho = particle.extractRhoMatrix(true);
rhoCalc = true;
}
// whether or not this interaction should be angular ordered
bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered();
ShoKinPtr newKin;
ShowerPartnerType type;
IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles;
// work out which starting scale we need
if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) {
type = ShowerPartnerType::QED;
Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO;
newKin = cit->second.sudakov->
generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning,
particle.scales().Max_Q2);
}
else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) {
// special for octets
if(particle.dataPtr()->iColour()==PDT::Colour8) {
// octet -> octet octet
if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) {
type = ShowerPartnerType::QCDColourLine;
Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO;
newKin= cit->second.sudakov->
generateNextTimeBranching(startingScale,particles,rho,0.5*enhance,_deTuning,
particle.scales().Max_Q2);
startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO;
ShoKinPtr newKin2 = cit->second.sudakov->
generateNextTimeBranching(startingScale,particles,rho,0.5*enhance,_deTuning,
particle.scales().Max_Q2);
// pick the one with the highest scale
if( ( newKin && newKin2 && newKin2->scale() > newKin->scale()) ||
(!newKin && newKin2) ) {
newKin = newKin2;
type = ShowerPartnerType::QCDAntiColourLine;
}
}
// other g -> q qbar
else {
Energy startingScale = angularOrdered ?
max(particle.scales().QCD_c , particle.scales().QCD_ac ) :
max(particle.scales().QCD_c_noAO, particle.scales().QCD_ac_noAO);
newKin= cit->second.sudakov->
generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning,
particle.scales().Max_Q2);
type = UseRandom::rndbool() ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine;
}
}
// everything else q-> qg etc
else {
Energy startingScale;
if(particle.hasColour()) {
type = ShowerPartnerType::QCDColourLine;
startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO;
}
else {
type = ShowerPartnerType::QCDAntiColourLine;
startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO;
}
newKin= cit->second.sudakov->
generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning,
particle.scales().Max_Q2);
}
}
else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) {
type = ShowerPartnerType::EW;
Energy startingScale = particle.scales().EW;
newKin = cit->second.sudakov->
generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning,
particle.scales().Max_Q2);
}
// shouldn't be anything else
else
assert(false);
// if no kinematics contine
if(!newKin) continue;
// select highest scale
if( newKin->scale() > newQ ) {
kinematics = newKin;
newQ = newKin->scale();
ids = particles;
sudakov = cit->second.sudakov;
partnerType = type;
}
}
// return empty branching if nothing happened
- if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),
- ShowerPartnerType::Undefined);
+ if(!kinematics) {
+ particle.spinInfo()->undecay();
+ return Branching(ShoKinPtr(), IdList(),SudakovPtr(),
+ ShowerPartnerType::Undefined);
+ }
// if not hard generate phi
kinematics->phi(sudakov->generatePhiForward(particle,ids,kinematics,rho));
// and return it
return Branching(kinematics, ids,sudakov,partnerType);
}
Branching SplittingGenerator::
chooseDecayBranching(ShowerParticle &particle,
const ShowerParticle::EvolutionScales & stoppingScales,
Energy minmass, double enhance,
ShowerInteraction interaction) const {
RhoDMatrix rho(particle.dataPtr()->iSpin());
Energy newQ = Constants::MaxEnergy;
ShoKinPtr kinematics;
SudakovPtr sudakov;
ShowerPartnerType partnerType(ShowerPartnerType::Undefined);
IdList ids;
// First, find the eventual branching, corresponding to the lowest scale.
long index = abs(particle.data().id());
// if no branchings return empty branching struct
if(_fbranchings.find(index) == _fbranchings.end())
return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined);
// otherwise select branching
for(BranchingList::const_iterator cit = _fbranchings.lower_bound(index);
cit != _fbranchings.upper_bound(index); ++cit) {
// check interaction doesn't change flavour
if(cit->second.particles[1]->id()!=index&&cit->second.particles[2]->id()!=index) continue;
// check either right interaction or doing both
if(!checkInteraction(interaction,cit->second.sudakov->interactionType())) continue;
// whether or not this interaction should be angular ordered
bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered();
ShoKinPtr newKin;
IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles;
ShowerPartnerType type;
// work out which starting scale we need
if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) {
type = ShowerPartnerType::QED;
Energy stoppingScale = angularOrdered ? stoppingScales.QED : stoppingScales.QED_noAO;
Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO;
if(startingScale < stoppingScale ) {
newKin = cit->second.sudakov->
generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho,
enhance,_deTuning);
}
}
else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) {
// special for octets
if(particle.dataPtr()->iColour()==PDT::Colour8) {
// octet -> octet octet
if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) {
Energy stoppingColour = angularOrdered ? stoppingScales.QCD_c : stoppingScales.QCD_c_noAO;
Energy stoppingAnti = angularOrdered ? stoppingScales.QCD_ac : stoppingScales.QCD_ac_noAO;
Energy startingColour = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO;
Energy startingAnti = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO;
type = ShowerPartnerType::QCDColourLine;
if(startingColour<stoppingColour) {
newKin= cit->second.sudakov->
generateNextDecayBranching(startingColour,stoppingColour,minmass,
particles,rho,0.5*enhance,_deTuning);
}
ShoKinPtr newKin2;
if(startingAnti<stoppingAnti) {
newKin2 = cit->second.sudakov->
generateNextDecayBranching(startingAnti,stoppingAnti,minmass,
particles,rho,0.5*enhance,_deTuning);
}
// pick the one with the lowest scale
if( (newKin&&newKin2&&newKin2->scale()<newKin->scale()) ||
(!newKin&&newKin2) ) {
newKin = newKin2;
type = ShowerPartnerType::QCDAntiColourLine;
}
}
// other
else {
assert(false);
}
}
// everything else
else {
Energy startingScale,stoppingScale;
if(particle.hasColour()) {
type = ShowerPartnerType::QCDColourLine;
stoppingScale = angularOrdered ? stoppingScales.QCD_c : stoppingScales.QCD_c_noAO;
startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO;
}
else {
type = ShowerPartnerType::QCDAntiColourLine;
stoppingScale = angularOrdered ? stoppingScales.QCD_ac : stoppingScales.QCD_ac_noAO;
startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO;
}
if(startingScale < stoppingScale ) {
newKin = cit->second.sudakov->
generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho,
enhance,_deTuning);
}
}
}
else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) {
type = ShowerPartnerType::EW;
Energy stoppingScale = stoppingScales.EW;
Energy startingScale = particle.scales().EW;
if(startingScale < stoppingScale ) {
newKin = cit->second.sudakov->
generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho,enhance,_deTuning);
}
}
// shouldn't be anything else
else
assert(false);
if(!newKin) continue;
// select highest scale
if(newKin->scale() < newQ ) {
newQ = newKin->scale();
ids = particles;
kinematics=newKin;
sudakov=cit->second.sudakov;
partnerType = type;
}
}
// return empty branching if nothing happened
if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),
ShowerPartnerType::Undefined);
// and generate phi
kinematics->phi(sudakov->generatePhiDecay(particle,ids,kinematics,rho));
// and return it
return Branching(kinematics, ids,sudakov,partnerType);
}
Branching SplittingGenerator::
chooseBackwardBranching(ShowerParticle &particle,PPtr,
double enhance,
Ptr<BeamParticleData>::transient_const_pointer beam,
ShowerInteraction type,
tcPDFPtr pdf, Energy freeze) const {
RhoDMatrix rho;
bool rhoCalc(false);
Energy newQ=ZERO;
ShoKinPtr kinematics=ShoKinPtr();
ShowerPartnerType partnerType(ShowerPartnerType::Undefined);
SudakovPtr sudakov;
IdList ids;
// First, find the eventual branching, corresponding to the highest scale.
long index = abs(particle.id());
// if no possible branching return
if(_bbranchings.find(index) == _bbranchings.end())
return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined);
// otherwise select branching
for(BranchingList::const_iterator cit = _bbranchings.lower_bound(index);
cit != _bbranchings.upper_bound(index); ++cit ) {
// check either right interaction or doing both
if(!checkInteraction(type,cit->second.sudakov->interactionType())) continue;
// setup the PDF
cit->second.sudakov->setPDF(pdf,freeze);
//calc rho as needed
if(!rhoCalc) {
rho = particle.extractRhoMatrix(false);
rhoCalc = true;
}
// whether or not this interaction should be angular ordered
bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered();
ShoKinPtr newKin;
IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles;
ShowerPartnerType type;
if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) {
type = ShowerPartnerType::QED;
Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO;
newKin=cit->second.sudakov->
generateNextSpaceBranching(startingScale,particles, particle.x(),rho,enhance,
beam,_deTuning);
}
else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) {
// special for octets
if(particle.dataPtr()->iColour()==PDT::Colour8) {
// octet -> octet octet
if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) {
type = ShowerPartnerType::QCDColourLine;
Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO;
newKin = cit->second.sudakov->
generateNextSpaceBranching(startingScale,particles, particle.x(),rho,0.5*enhance,
beam,_deTuning);
startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO;
ShoKinPtr newKin2 = cit->second.sudakov->
generateNextSpaceBranching(startingScale,particles, particle.x(),rho,
0.5*enhance,beam,_deTuning);
// pick the one with the highest scale
if( (newKin&&newKin2&&newKin2->scale()>newKin->scale()) ||
(!newKin&&newKin2) ) {
newKin = newKin2;
type = ShowerPartnerType::QCDAntiColourLine;
}
}
else {
Energy startingScale = angularOrdered ?
max(particle.scales().QCD_c , particle.scales().QCD_ac ) :
max(particle.scales().QCD_c_noAO, particle.scales().QCD_ac_noAO);
type = UseRandom::rndbool() ?
ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine;
newKin=cit->second.sudakov->
generateNextSpaceBranching(startingScale,particles, particle.x(),rho,enhance,beam,_deTuning);
}
}
// everything else
else {
Energy startingScale;
if(particle.hasColour()) {
type = ShowerPartnerType::QCDColourLine;
startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO;
}
else {
type = ShowerPartnerType::QCDAntiColourLine;
startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO;
}
newKin=cit->second.sudakov->
generateNextSpaceBranching(startingScale,particles,particle.x(),rho,enhance,beam,_deTuning);
}
}
else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) {
type = ShowerPartnerType::EW;
Energy startingScale = particle.scales().EW;
newKin=cit->second.sudakov->
generateNextSpaceBranching(startingScale,particles,particle.x(),rho,enhance,beam,_deTuning);
}
// shouldn't be anything else
else
assert(false);
// if no kinematics contine
if(!newKin) continue;
// select highest scale
if(newKin->scale() > newQ) {
newQ = newKin->scale();
kinematics=newKin;
ids = particles;
sudakov=cit->second.sudakov;
partnerType = type;
}
}
// return empty branching if nothing happened
- if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),
- ShowerPartnerType::Undefined);
+ if(!kinematics) {
+ particle.spinInfo()->undecay();
+ return Branching(ShoKinPtr(), IdList(),SudakovPtr(),
+ ShowerPartnerType::Undefined);
+ }
// initialize the ShowerKinematics
// and generate phi
kinematics->phi(sudakov->generatePhiBackward(particle,ids,kinematics,rho));
// return the answer
return Branching(kinematics, ids,sudakov,partnerType);
}
void SplittingGenerator::rebind(const TranslationMap & trans) {
BranchingList::iterator cit;
for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) {
(cit->second).sudakov=trans.translate((cit->second).sudakov);
for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) {
(cit->second).particles[ix]=trans.translate((cit->second).particles[ix]);
}
for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) {
(cit->second).conjugateParticles[ix]=trans.translate((cit->second).conjugateParticles[ix]);
}
}
for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) {
(cit->second).sudakov=trans.translate((cit->second).sudakov);
for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) {
(cit->second).particles[ix]=trans.translate((cit->second).particles[ix]);
}
for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) {
(cit->second).conjugateParticles[ix]=trans.translate((cit->second).conjugateParticles[ix]);
}
}
Interfaced::rebind(trans);
}
IVector SplittingGenerator::getReferences() {
IVector ret = Interfaced::getReferences();
BranchingList::iterator cit;
for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) {
ret.push_back((cit->second).sudakov);
for(unsigned int ix=0;ix<(cit->second).particles.size();++ix)
ret.push_back(const_ptr_cast<tPDPtr>((cit->second).particles[ix]));
for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix)
ret.push_back(const_ptr_cast<tPDPtr>((cit->second).conjugateParticles[ix]));
}
for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) {
ret.push_back((cit->second).sudakov);
for(unsigned int ix=0;ix<(cit->second).particles.size();++ix)
ret.push_back(const_ptr_cast<tPDPtr>((cit->second).particles[ix]));
for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix)
ret.push_back(const_ptr_cast<tPDPtr>((cit->second).conjugateParticles[ix]));
}
return ret;
}
diff --git a/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.cc b/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.cc
--- a/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.cc
+++ b/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.cc
@@ -1,118 +1,118 @@
// -*- C++ -*-
//
// PhitoPhiGSplitFn.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2017 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ZeroZeroOneSplitFn class.
//
#include "ZeroZeroOneSplitFn.h"
#include "ThePEG/PDT/ParticleData.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Decay/TwoBodyDecayMatrixElement.h"
using namespace Herwig;
DescribeNoPIOClass<ZeroZeroOneSplitFn,Herwig::SplittingFunction>
describeZeroZeroOneSplitFn ("Herwig::ZeroZeroOneSplitFn","HwShower.so");
void ZeroZeroOneSplitFn::Init() {
static ClassDocumentation<ZeroZeroOneSplitFn> documentation
("The ZeroZeroOneSplitFn class implements the splitting function for the "
"radiation of a gluon by a scalar coloured particle");
}
double ZeroZeroOneSplitFn::P(const double z, const Energy2 t,
const IdList &ids, const bool mass, const RhoDMatrix &) const {
double val = z/(1.-z);
if(mass) {
Energy m = ids[0]->mass();
val-= sqr(m)/t;
}
return 2.*colourFactor(ids)*val;
}
double ZeroZeroOneSplitFn::overestimateP(const double z,
const IdList &ids) const {
return 2.*colourFactor(ids)/(1.-z);
}
double ZeroZeroOneSplitFn::ratioP(const double z, const Energy2 t,
const IdList &ids,const bool mass, const RhoDMatrix &) const {
double val = z;
if(mass) {
Energy m = ids[0]->mass();
val-=sqr(m)*(1.-z)/t;
}
return val;
}
double ZeroZeroOneSplitFn::integOverP(const double z, const IdList & ids,
unsigned int PDFfactor) const {
switch(PDFfactor) {
case 0:
return -2.*colourFactor(ids)*log(1.-z);
case 1:
case 2:
case 3:
default:
throw Exception() << "ZeroZeroOneSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
double ZeroZeroOneSplitFn::invIntegOverP(const double r, const IdList & ids,
unsigned int PDFfactor) const {
switch(PDFfactor) {
case 0:
return 1. - exp(- 0.5*r/colourFactor(ids));
case 1:
case 2:
case 3:
default:
throw Exception() << "ZeroZeroOneSplitFn::integOverP() invalid PDFfactor = "
<< PDFfactor << Exception::runerror;
}
}
bool ZeroZeroOneSplitFn::accept(const IdList &ids) const {
if(ids.size()!=3) return false;
if(ids[0]!=ids[1]) return false;
if(ids[0]->iSpin()!=PDT::Spin0 ||
ids[2]->iSpin()!=PDT::Spin1) return false;
return checkColours(ids);
}
vector<pair<int, Complex> >
ZeroZeroOneSplitFn::generatePhiForward(const double, const Energy2, const IdList &,
const RhoDMatrix &) {
// scalar so no dependence
- return vector<pair<int, Complex> >(1,make_pair(0,1.));
+ return {{ {0, 1.} }};
}
vector<pair<int, Complex> >
ZeroZeroOneSplitFn::generatePhiBackward(const double, const Energy2, const IdList &,
const RhoDMatrix &) {
// scalar so no dependence
assert(false);
- return vector<pair<int, Complex> >(1,make_pair(0,1.));
+ return {{ {0, 1.} }};
}
DecayMEPtr ZeroZeroOneSplitFn::matrixElement(const double z, const Energy2 t,
const IdList & ids, const double phi,
bool timeLike) {
// calculate the kernal
DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin1)));
Energy m = timeLike ? ids[0]->mass() : ZERO;
(*kernal)(0,0,0) = -exp(Complex(0.,1.)*phi)*sqrt(1.-(1.-z)*sqr(m)/z/t)*sqrt(z/(1.-z));
(*kernal)(0,0,2) = -conj((*kernal)(0,0,0));
return kernal;
}
diff --git a/Shower/ShowerHandler.h b/Shower/ShowerHandler.h
--- a/Shower/ShowerHandler.h
+++ b/Shower/ShowerHandler.h
@@ -1,839 +1,847 @@
// -*- C++ -*-
//
// ShowerHandler.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_ShowerHandler_H
#define HERWIG_ShowerHandler_H
//
// This is the declaration of the ShowerHandler class.
//
#include "ThePEG/Handlers/EventHandler.h"
#include "ThePEG/Handlers/CascadeHandler.h"
#include "ShowerVariation.h"
#include "Herwig/PDF/HwRemDecayer.fh"
#include "ThePEG/EventRecord/RemnantParticle.fh"
#include "UEBase.h"
#include "PerturbativeProcess.h"
#include "Herwig/MatrixElement/Matchbox/Matching/HardScaleProfile.h"
#include "ShowerHandler.fh"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
*
* This class is the main driver of the shower: it is responsible for
* the proper handling of all other specific collaborating classes
* and for the storing of the produced particles in the event record.
*
* @see \ref ShowerHandlerInterfaces "The interfaces"
*
* @see ThePEG::CascadeHandler
* @see MPIHandler
* @see HwRemDecayer
*/
class ShowerHandler: public CascadeHandler {
public:
/**
* Typedef for a pair of ThePEG::RemnantParticle pointers.
*/
typedef pair<tRemPPtr, tRemPPtr> RemPair;
public:
/**
* Default constructor
*/
ShowerHandler();
/**
* Destructor
*/
virtual ~ShowerHandler();
public:
/**
* The main method which manages the multiple interactions and starts
* the shower by calling cascade(sub, lastXC).
*/
virtual void cascade();
/**
* pointer to "this", the current ShowerHandler.
*/
static const tShowerHandlerPtr currentHandler() {
assert(currentHandler_);
return currentHandler_;
}
public:
/**
* Hook to allow vetoing of event after showering hard sub-process
* as in e.g. MLM merging.
*/
virtual bool showerHardProcessVeto() const { return false; }
/**
* Return true, if this cascade handler will perform reshuffling from hard
* process masses.
*/
virtual bool isReshuffling() const { return true; }
/**
* Return true, if the shower handler can generate a truncated
* shower for POWHEG style events generated using Matchbox
*/
virtual bool canHandleMatchboxTrunc() const { return false; }
/**
* Get the PDF freezing scale
*/
Energy pdfFreezingScale() const { return pdfFreezingScale_; }
/**
* Get the local PDFs.
*/
PDFPtr getPDFA() const {return PDFA_;}
/**
* Get the local PDFs.
*/
PDFPtr getPDFB() const {return PDFB_;}
/**
* Return true if currently the primary subprocess is showered.
*/
bool firstInteraction() const {
if (!eventHandler()->currentCollision())return true;
return ( subProcess_ ==
eventHandler()->currentCollision()->primarySubProcess() );
}
/**
* Return the remnant decayer.
*/
tHwRemDecPtr remnantDecayer() const { return remDec_; }
/**
* Split the hard process into production and decays
* @param tagged The tagged particles from the StepHandler
* @param hard The hard perturbative process
* @param decay The decay particles
*/
void splitHardProcess(tPVector tagged, PerturbativeProcessPtr & hard,
DecayProcessMap & decay) const;
/**
* Information if the Showerhandler splits the hard process.
*/
bool doesSplitHardProcess()const {return splitHardProcess_;}
/**
* Decay a particle.
* radPhotons switches the generation of photon
* radiation on/off.
* Required for Dipole Shower but not QTilde Shower.
*/
tDMPtr decay(PerturbativeProcessPtr,
DecayProcessMap & decay,
bool radPhotons = false) const;
/**
* Cached lookup of decay modes.
* Generator::findDecayMode() is not efficient.
*/
tDMPtr findDecayMode(const string & tag) const;
/**
* A struct to order the particles in the same way as in the DecayMode's
*/
struct ParticleOrdering {
bool operator() (tcPDPtr p1, tcPDPtr p2);
};
/**
* A container for ordered particles required
* for constructing tags for decay mode lookup.
*/
typedef multiset<tcPDPtr,ParticleOrdering> OrderedParticles;
public:
/**
* @name Switches for initial- and final-state radiation
*/
//@{
/**
* Switch for any radiation
*/
bool doRadiation() const {return doFSR_ || doISR_;}
/**
* Switch on or off final state radiation.
*/
bool doFSR() const { return doFSR_;}
/**
* Switch on or off initial state radiation.
*/
bool doISR() const { return doISR_;}
//@}
public:
/**
* @name Switches for scales
*/
//@{
/**
* Return true if maximum pt should be deduced from the factorization scale
*/
bool hardScaleIsMuF() const { return maxPtIsMuF_; }
/**
* The factorization scale factor.
*/
double factorizationScaleFactor() const {
return factorizationScaleFactor_;
}
/**
* The renormalization scale factor.
*/
double renFac() const {
return renormalizationScaleFactor_;
}
/**
* The factorization scale factor.
*/
double facFac() const {
return factorizationScaleFactor_;
}
/**
* The renormalization scale factor.
*/
double renormalizationScaleFactor() const {
return renormalizationScaleFactor_;
}
/**
* The scale factor for the hard scale
*/
double hardScaleFactor() const {
return hardScaleFactor_;
}
/**
* Return true, if the phase space restrictions of the dipole shower should
* be applied.
*/
bool restrictPhasespace() const { return restrictPhasespace_; }
/**
* Return profile scales
*/
Ptr<HardScaleProfile>::tptr profileScales() const { return hardScaleProfile_; }
/**
* Return the relevant hard scale to be used in the profile scales
*/
virtual Energy hardScale() const;
+
+ /**
+ * Return information about shower phase space choices
+ */
+ virtual int showerPhaseSpaceOption() const {
+ assert(false && "not implemented in general");
+ return -1;
+ }
//@}
public:
/**
* Access the shower variations
*/
map<string,ShowerVariation>& showerVariations() {
return showerVariations_;
}
/**
* Return the shower variations
*/
const map<string,ShowerVariation>& showerVariations() const {
return showerVariations_;
}
/**
* Access the current Weights
*/
map<string,double>& currentWeights() {
return currentWeights_;
}
/**
* Return the current Weights
*/
const map<string,double>& currentWeights() const {
return currentWeights_;
}
/**
* Change the current reweighting factor
*/
void reweight(double w) {
reweight_ = w;
}
/**
* Return the current reweighting factor
*/
double reweight() const {
return reweight_;
}
public:
/**
* struct that is used to catch exceptions which are thrown
* due to energy conservation issues of additional scatters
*/
struct ExtraScatterVeto {};
/**
* struct that is used to catch exceptions which are thrown
* due to fact that the Shower has been invoked more than
* a defined threshold on a certain configuration
*/
struct ShowerTriesVeto {
/** variable to store the number of attempts */
const int tries;
/** constructor */
ShowerTriesVeto(int t) : tries(t) {}
};
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 Functions to perform the cascade
*/
//@{
/**
* The main method which manages the showering of a subprocess.
*/
virtual tPPair cascade(tSubProPtr sub, XCPtr xcomb);
/**
* Set up for the cascade
*/
void prepareCascade(tSubProPtr sub) {
current_ = currentStep();
subProcess_ = sub;
}
/**
* Boost all the particles in the collision so that the collision always occurs
* in the rest frame with the incoming particles along the z axis
*/
void boostCollision(bool boost);
//@}
protected:
/**
* Set/unset the current shower handler
*/
//@{
/**
* Set the current handler
*/
void setCurrentHandler() {
currentHandler_ = tShowerHandlerPtr(this);
}
/**
* Unset the current handler
*/
void unSetCurrentHandler() {
currentHandler_ = tShowerHandlerPtr();
}
//@}
protected:
/**
* @name Members relating to the underlying event and MPI
*/
//@{
/**
* Return true if multiple parton interactions are switched on
* and can be used for this beam setup.
*/
bool isMPIOn() const {
return MPIHandler_ && MPIHandler_->beamOK();
}
/**
* Access function for the MPIHandler, it should only be called after
* checking with isMPIOn.
*/
tUEBasePtr getMPIHandler() const {
assert(MPIHandler_);
return MPIHandler_;
}
/**
* Is a beam particle where hadronic structure is resolved
*/
bool isResolvedHadron(tPPtr);
/**
* Get the remnants from the ThePEG::PartonBinInstance es and
* do some checks.
*/
RemPair getRemnants(PBIPair incbins);
/**
* Reset the PDF's after the hard collision has been showered
*/
void setMPIPDFs();
//@}
public:
/**
* Check if a particle decays in the shower
* @param id The PDG code for the particle
*/
bool decaysInShower(long id) const {
return ( particlesDecayInShower_.find( abs(id) ) !=
particlesDecayInShower_.end() );
}
protected:
/**
* Members to handle splitting up of hard process and decays
*/
//@{
/**
* Find decay products from the hard process and create decay processes
* @param parent The parent particle
* @param hard The hard process
* @param decay The decay processes
*/
void findDecayProducts(PPtr parent, PerturbativeProcessPtr hard, DecayProcessMap & decay) const;
/**
* Find decay products from the hard process and create decay processes
* @param parent The parent particle
* @param hard The parent hard process
* @param decay The decay processes
*/
void createDecayProcess(PPtr parent,PerturbativeProcessPtr hard, DecayProcessMap & decay) const;
//@}
/**
* @name Functions to return information relevant to the process being showered
*/
//@{
/**
* Return the currently used SubProcess.
*/
tSubProPtr currentSubProcess() const {
assert(subProcess_);
return subProcess_;
}
/**
* Access to the incoming beam particles
*/
tPPair incomingBeams() const {
return incoming_;
}
//@}
protected:
/**
* Weight handling for shower variations
*/
//@
/**
* Combine the variation weights which have been encountered
*/
void combineWeights();
/**
* Initialise the weights in currentEvent()
*/
void initializeWeights();
/**
* Reset the current weights
*/
void resetWeights();
//@}
protected:
/**
* Return the maximum number of attempts for showering
* a given subprocess.
*/
unsigned int maxtry() const { return maxtry_; }
protected:
/**
* Parameters for the space-time model
*/
//@{
/**
* Whether or not to include spa-cetime distances in the shower
*/
bool includeSpaceTime() const {return includeSpaceTime_;}
/**
* The minimum virtuality for the space-time model
*/
Energy2 vMin() const {return vMin_;}
//@}
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();
/**
* Initialize this object. Called in the run phase just before
* a run begins.
*/
virtual void doinitrun();
/**
* Finalize this object. Called in the run phase just after a
* run has ended. Used eg. to write out statistics.
*/
virtual void dofinish();
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
ShowerHandler & operator=(const ShowerHandler &);
private:
/**
* pointer to "this", the current ShowerHandler.
*/
static tShowerHandlerPtr currentHandler_;
/**
* a MPIHandler to administer the creation of several (semihard)
* partonic interactions.
*/
UEBasePtr MPIHandler_;
/**
* Pointer to the HwRemDecayer
*/
HwRemDecPtr remDec_;
private:
/**
* Maximum tries for various stages of the showering process
*/
//@{
/**
* Maximum number of attempts for the
* main showering loop
*/
unsigned int maxtry_;
/**
* Maximum number of attempts for the regeneration of an additional
* scattering, before the number of scatters is reduced.
*/
unsigned int maxtryMPI_;
/**
* Maximum number of attempts for the regeneration of an additional
* hard scattering, before this event is vetoed.
*/
unsigned int maxtryDP_;
/**
* Maximum number of attempts to generate a decay
*/
unsigned int maxtryDecay_;
//@}
private:
/**
* Factors for the various scales
*/
//@{
/**
* The factorization scale factor.
*/
double factorizationScaleFactor_;
/**
* The renormalization scale factor.
*/
double renormalizationScaleFactor_;
/**
* The scale factor for the hard scale
*/
double hardScaleFactor_;
/**
* True, if the phase space restrictions of the dipole shower should
* be applied.
*/
bool restrictPhasespace_;
/**
* True if maximum pt should be deduced from the factorization scale
*/
bool maxPtIsMuF_;
/**
* The profile scales
*/
Ptr<HardScaleProfile>::ptr hardScaleProfile_;
//@}
private:
/**
* Storage of information about the current event
*/
//@{
/**
* The incoming beam particles for the current collision
*/
tPPair incoming_;
/**
* Boost to get back to the lab
*/
LorentzRotation boost_;
/**
* Const pointer to the currently handeled ThePEG::SubProcess
*/
tSubProPtr subProcess_;
/**
* Const pointer to the current step
*/
tcStepPtr current_;
//@}
private:
/**
* PDFs to be used for the various stages and related parameters
*/
//@{
/**
* The PDF freezing scale
*/
Energy pdfFreezingScale_;
/**
* PDFs to be used for the various stages and related parameters
*/
//@{
/**
* The PDF for beam particle A. Overrides the particle's own PDF setting.
*/
PDFPtr PDFA_;
/**
* The PDF for beam particle B. Overrides the particle's own PDF setting.
*/
PDFPtr PDFB_;
/**
* The PDF for beam particle A for remnant splitting. Overrides the particle's own PDF setting.
*/
PDFPtr PDFARemnant_;
/**
* The PDF for beam particle B for remnant splitting. Overrides the particle's own PDF setting.
*/
PDFPtr PDFBRemnant_;
/**
* The MPI PDF's to be used for secondary scatters.
*/
pair <PDFPtr, PDFPtr> mpipdfs_;
/**
* The MPI PDF's to be used for secondary scatters.
*/
pair <PDFPtr, PDFPtr> rempdfs_;
/**
* The MPI PDF's to be used for secondary scatters.
*/
pair <PDFPtr, PDFPtr> remmpipdfs_;
//@}
private:
/**
* @name Parameters for initial- and final-state radiation
*/
//@{
/**
* Switch on or off final state radiation.
*/
bool doFSR_;
/**
* Switch on or off initial state radiation.
*/
bool doISR_;
//@}
private:
/**
* @name Parameters for particle decays
*/
//@{
/**
* Whether or not to split into hard and decay trees
*/
bool splitHardProcess_;
/**
* PDG codes of the particles which decay during showering
* this is fast storage for use during running
*/
set<long> particlesDecayInShower_;
/**
* PDG codes of the particles which decay during showering
* this is a vector that is interfaced so they can be changed
*/
vector<long> inputparticlesDecayInShower_;
//@}
private:
/**
* Parameters for the space-time model
*/
//@{
/**
* Whether or not to include spa-cetime distances in the shower
*/
bool includeSpaceTime_;
/**
* The minimum virtuality for the space-time model
*/
Energy2 vMin_;
//@}
private:
/**
* Parameters relevant for reweight and variations
*/
//@{
/**
* The shower variations
*/
map<string,ShowerVariation> showerVariations_;
/**
* Command to add a shower variation
*/
string doAddVariation(string);
/**
* A reweighting factor applied by the showering
*/
double reweight_;
/**
* The shower variation weights
*/
map<string,double> currentWeights_;
//@}
};
}
#endif /* HERWIG_ShowerHandler_H */
diff --git a/Tests/Makefile.am b/Tests/Makefile.am
--- a/Tests/Makefile.am
+++ b/Tests/Makefile.am
@@ -1,400 +1,398 @@
AM_LDFLAGS += -module -avoid-version -rpath /dummy/path/not/used
EXTRA_DIST = Inputs python Rivet
EXTRA_LTLIBRARIES = LeptonTest.la GammaTest.la HadronTest.la DISTest.la
if WANT_LIBFASTJET
EXTRA_LTLIBRARIES += HadronJetTest.la LeptonJetTest.la
HadronJetTest_la_SOURCES = \
Hadron/VHTest.h Hadron/VHTest.cc\
Hadron/VTest.h Hadron/VTest.cc\
Hadron/HTest.h Hadron/HTest.cc
HadronJetTest_la_CPPFLAGS = $(AM_CPPFLAGS) $(FASTJETINCLUDE) \
-I$(FASTJETPATH)
HadronJetTest_la_LIBADD = $(FASTJETLIBS)
LeptonJetTest_la_SOURCES = \
Lepton/TopDecay.h Lepton/TopDecay.cc
LeptonJetTest_la_CPPFLAGS = $(AM_CPPFLAGS) $(FASTJETINCLUDE) \
-I$(FASTJETPATH)
LeptonJetTest_la_LIBADD = $(FASTJETLIBS)
endif
LeptonTest_la_SOURCES = \
Lepton/VVTest.h Lepton/VVTest.cc \
Lepton/VBFTest.h Lepton/VBFTest.cc \
Lepton/VHTest.h Lepton/VHTest.cc \
Lepton/FermionTest.h Lepton/FermionTest.cc
GammaTest_la_SOURCES = \
Gamma/GammaMETest.h Gamma/GammaMETest.cc \
Gamma/GammaPMETest.h Gamma/GammaPMETest.cc
DISTest_la_SOURCES = \
DIS/DISTest.h DIS/DISTest.cc
HadronTest_la_SOURCES = \
Hadron/HadronVVTest.h Hadron/HadronVVTest.cc\
Hadron/HadronVBFTest.h Hadron/HadronVBFTest.cc\
Hadron/WHTest.h Hadron/WHTest.cc\
Hadron/ZHTest.h Hadron/ZHTest.cc\
Hadron/VGammaTest.h Hadron/VGammaTest.cc\
Hadron/ZJetTest.h Hadron/ZJetTest.cc\
Hadron/WJetTest.h Hadron/WJetTest.cc\
Hadron/QQHTest.h Hadron/QQHTest.cc
REPO = $(top_builddir)/src/HerwigDefaults.rpo
HERWIG = $(top_builddir)/src/Herwig
HWREAD = $(HERWIG) read --repo $(REPO) -L $(builddir)/.libs -i $(top_builddir)/src
HWBUILD = $(HERWIG) build --repo $(REPO) -L $(builddir)/.libs -i $(top_builddir)/src
HWINTEGRATE = $(HERWIG) integrate
HWRUN = $(HERWIG) run -N $${NUMEVENTS:-10000}
tests : tests-LEP tests-DIS tests-LHC tests-Gamma
LEPDEPS = \
test-LEP-VV \
test-LEP-VH \
test-LEP-VBF \
test-LEP-BB \
test-LEP-Quarks \
test-LEP-Leptons
if WANT_LIBFASTJET
LEPDEPS += test-LEP-TopDecay
endif
tests-LEP : $(LEPDEPS)
tests-DIS : test-DIS-Charged test-DIS-Neutral
LHCDEPS = \
test-LHC-WW test-LHC-WZ test-LHC-ZZ \
test-LHC-ZGamma test-LHC-WGamma \
test-LHC-ZH test-LHC-WH \
test-LHC-ZJet test-LHC-WJet \
test-LHC-Z test-LHC-W \
test-LHC-ZZVBF test-LHC-VBF \
test-LHC-WWVBF \
test-LHC-bbH test-LHC-ttH \
test-LHC-GammaGamma test-LHC-GammaJet \
test-LHC-Higgs test-LHC-HiggsJet \
test-LHC-QCDFast test-LHC-QCD \
test-LHC-Top
if WANT_LIBFASTJET
LHCDEPS += \
test-LHC-Bottom \
test-LHC-WHJet test-LHC-ZHJet test-LHC-HJet \
test-LHC-ZShower test-LHC-WShower \
test-LHC-WHJet-Powheg test-LHC-ZHJet-Powheg test-LHC-HJet-Powheg \
test-LHC-ZShower-Powheg test-LHC-WShower-Powheg
endif
tests-LHC : $(LHCDEPS)
tests-Gamma : test-Gamma-FF test-Gamma-WW test-Gamma-P
LEPLIBS = LeptonTest.la
HADLIBS = HadronTest.la
if WANT_LIBFASTJET
LEPLIBS += LeptonJetTest.la
HADLIBS += HadronJetTest.la
endif
test-LEP-% : Inputs/LEP-%.in $(LEPLIBS)
$(HWREAD) $<
$(HWRUN) $(notdir $(subst .in,.run,$<))
test-Gamma-% : Inputs/Gamma-%.in GammaTest.la
$(HWREAD) $<
$(HWRUN) $(notdir $(subst .in,.run,$<))
test-DIS-% : Inputs/DIS-%.in DISTest.la
$(HWREAD) $<
$(HWRUN) $(notdir $(subst .in,.run,$<))
test-LHC-% : Inputs/LHC-%.in GammaTest.la $(HADLIBS)
$(HWREAD) $<
$(HWRUN) $(notdir $(subst .in,.run,$<))
tests-Rivet : Rivet-LEP Rivet-BFactory Rivet-DIS Rivet-Star Rivet-SppS \
Rivet-TVT-WZ Rivet-TVT-Photon Rivet-TVT-Jets \
Rivet-LHC-Jets Rivet-LHC-EW Rivet-LHC-Photon Rivet-LHC-Higgs
Rivet-%.run : Rivet/%.in
$(HWBUILD) -c .cache/$(subst .run,,$@) $<
Rivet-Matchbox-%.yoda : Rivet-Matchbox-%.run
$(HWINTEGRATE) -c .cache/$(subst .run,,$<) $<
$(HWRUN) -c .cache/$(subst .run,,$<) $<
Rivet-%.yoda : Rivet-%.run
$(HWRUN) $<
Rivet/%.in :
python/make_input_files.py $(notdir $(subst .in,,$@))
Rivet-inputfiles: $(shell echo Rivet/LEP{,-Powheg,-Matchbox,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox-Powheg,-Merging}-{9.4,12,13,17,27.6,29,30.2,30.7,30.75,30,31.3,34.8,43.6,50,52,55,56,57,60.8,60,61.4,10,12.8,22,26.8,35,44,48.0,91,93.0,130,133,136,161,172,177,183,189,192,196,197,200,202,206,91-nopi}.in) \
$(shell echo Rivet/LEP{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Powheg,-Matchbox-Powheg}-14.in) \
$(shell echo Rivet/LEP{,-Dipole}-{10.5,11.96,12.8,13.96,16.86,21.84,26.8,28.48,35.44,48.0,97.0}-gg.in) \
$(shell echo Rivet/BFactory{,-Powheg,-Matchbox,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox-Powheg}-{10.52,10.52-sym,10.54,10.45}.in) \
$(shell echo Rivet/BFactory{,-Dipole}-{Upsilon,Upsilon2,Upsilon4,Tau,10.58-res}.in) \
$(shell echo Rivet/DIS{,-NoME,-Powheg,-Matchbox,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox-Powheg,-Merging}-{e--LowQ2,e+-LowQ2,e+-HighQ2}.in) \
$(shell echo Rivet/TVT{,-Powheg,-Matchbox,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox-Powheg,-Merging}-{Run-I-Z,Run-I-W,Run-I-WZ,Run-II-Z-e,Run-II-Z-{,LowMass-,HighMass-}mu,Run-II-W}.in) \
$(shell echo Rivet/TVT{,-Dipole}-Run-II-{DiPhoton-GammaGamma,DiPhoton-GammaJet,PromptPhoton}.in) \
$(shell echo Rivet/TVT-Powheg-Run-II-{DiPhoton-GammaGamma,DiPhoton-GammaJet}.in) \
$(shell echo Rivet/TVT{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{Run-II-Jets-{0..11},Run-I-Jets-{1..8}}.in ) \
$(shell echo Rivet/TVT{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{630-Jets-{1..3},300-Jets-1,900-Jets-1}.in ) \
$(shell echo Rivet/TVT{,-Dipole}-{Run-I,Run-II,300,630,900}-UE.in) \
$(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-7-DiJets-{1..7}-{A,B,C}.in ) \
$(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{7,8,13}-Jets-{0..10}.in ) \
$(shell echo Rivet/LHC{,-Dipole}-{900,2360,2760,7,8,13}-UE.in ) \
$(shell echo Rivet/LHC{,-Dipole}-{900,7,13}-UE-Long.in ) \
$(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-7-Charm-{1..5}.in) \
$(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-7-Bottom-{0..8}.in) \
- $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-7-Top-{L,SL}.in) \
- $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{7,8,13}-Top-All.in) \
+ $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{7,8,13}-Top-{L,SL,All}.in) \
$(shell echo Rivet/Star{,-Dipole}-{UE,Jets-{1..4}}.in ) \
$(shell echo Rivet/SppS{,-Dipole}-{200,500,900,546}-UE.in ) \
- $(shell echo Rivet/LHC{,-Matchbox,-Matchbox-Powheg,-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{W-{e,mu},13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},Z-{e,mu,mu-SOPHTY},Z-LowMass-{e,mu},Z-MedMass-e,WZ,WW-{emu,ll},ZZ-{ll,lv},8-ZZ-lv,8-WW-ll,W-Z-{e,mu}}.in) \
+ $(shell echo Rivet/LHC{,-Matchbox,-Matchbox-Powheg,-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{W-{e,mu},13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},Z-{e,mu,mu-SOPHTY},Z-LowMass-{e,mu},Z-MedMass-e,WZ,WW-{emu,ll},ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll,W-Z-{e,mu}}.in) \
$(shell echo Rivet/LHC{,-Dipole}-7-{W,Z}Gamma-{e,mu}.in) \
$(shell echo Rivet/LHC{,-Matchbox,-Matchbox-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{7-W-Jet-{1..3}-e,7-Z-Jet-{0..3}-e,7-Z-Jet-0-mu}.in) \
$(shell echo Rivet/LHC{-Matchbox,-Matchbox-Powheg,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{Z-b,Z-bb,W-b,8-Z-jj}.in) \
$(shell echo Rivet/LHC{,-Dipole}-{7,8}-PromptPhoton-{1..4}.in) Rivet/LHC-GammaGamma-7.in \
$(shell echo Rivet/LHC{,-Powheg}-{7,8}-{DiPhoton-GammaGamma,DiPhoton-GammaJet}.in) \
$(shell echo Rivet/LHC{,-Powheg,-Matchbox,-Matchbox-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{ggH,VBF,WH,ZH}.in) \
$(shell echo Rivet/LHC{,-Powheg,-Matchbox,-Matchbox-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-8-{{ggH,VBF,WH,ZH}{,-GammaGamma},ggH-WW}.in) \
$(shell echo Rivet/LHC{,-Matchbox,-Matchbox-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-ggHJet.in)
# $(shell echo Rivet/ISR-{30,44,53,62}-UE.in ) $(shell echo Rivet/SppS-{53,63}-UE.in )
Rivet-LEP : Rivet-LEP/done
touch $@
Rivet-LEP/done : $(shell echo Rivet{,-Powheg,-Matchbox,-Dipole}-LEP-{9.4,12,13,17,27.6,29,30.2,30.7,30.75,30,31.3,34.8,43.6,50,52,55,56,57,60.8,60,61.4,10,12.8,22,26.8,35,44,48.0,91,93.0,130,133,136,161,172,177,183,189,192,196,197,200,202,206,91-nopi}.yoda) \
$(shell echo Rivet-LEP-{10.5,11.96,12.8,13.96,16.86,21.84,26.8,28.48,35.44,48.0,97.0}-gg.yoda) \
$(shell echo Rivet{,-Powheg,-Matchbox,-Matchbox-Powheg,-Dipole}-LEP-14.yoda)
rm -rf Rivet-LEP
python/merge-LEP --with-gg LEP
python/merge-LEP Powheg-LEP
python/merge-LEP Matchbox-LEP
python/merge-LEP Dipole-LEP
rivet-mkhtml -o Rivet-LEP LEP.yoda:Hw Powheg-LEP.yoda:Hw-Powheg Matchbox-LEP.yoda:Hw-Matchbox Dipole-LEP.yoda:Hw-Dipole
touch $@
Rivet-BFactory : Rivet-BFactory/done
touch $@
Rivet-BFactory/done: $(shell echo Rivet{,-Powheg,-Matchbox,-Dipole}-BFactory-{10.52,10.52-sym,10.54,10.45}.yoda) \
$(shell echo Rivet-BFactory-{Upsilon,Upsilon2,Upsilon4,Tau,10.58-res,10.58}.yoda)
rm -rf Rivet-BFactory
python/merge-BFactory BFactory
python/merge-BFactory Powheg-BFactory
python/merge-BFactory Matchbox-BFactory
python/merge-BFactory Dipole-BFactory
rivet-mkhtml -o Rivet-BFactory BFactory.yoda:Hw Powheg-BFactory.yoda:Hw-Powheg Matchbox-BFactory.yoda:Hw-Matchbox Dipole-BFactory.yoda:Hw-Dipole
touch $@
Rivet-DIS : Rivet-DIS/done
touch $@
Rivet-DIS/done: $(shell echo Rivet{-DIS,-DIS-NoME,-Powheg-DIS,-Matchbox-DIS,-Dipole-DIS}-{e--LowQ2,e+-LowQ2,e+-HighQ2}.yoda)
rm -rf Rivet-DIS
python/merge-DIS DIS
python/merge-DIS Powheg-DIS
python/merge-DIS DIS-NoME
python/merge-DIS Matchbox-DIS
python/merge-DIS Dipole-DIS
rivet-mkhtml -o Rivet-DIS DIS.yoda:Hw Powheg-DIS.yoda:Hw-Powheg DIS-NoME.yoda:Hw-NoME Matchbox-DIS.yoda:Hw-Matchbox Dipole-DIS.yoda:Hw-Dipole
touch $@
Rivet-TVT-WZ : Rivet-TVT-WZ/done
touch $@
Rivet-TVT-WZ/done: $(shell echo Rivet{,-Powheg,-Matchbox,-Dipole}-TVT-{Run-I-Z,Run-I-W,Run-I-WZ,Run-II-Z-{e,{,LowMass-,HighMass-}mu},Run-II-W}.yoda)
rm -rf Rivet-TVT-WZ
python/merge-TVT-EW Rivet-TVT-Run-II-W.yoda Rivet-TVT-Run-II-Z-{e,{,LowMass-,HighMass-}mu}.yoda\
Rivet-TVT-Run-I-{W,Z,WZ}.yoda -o TVT-WZ.yoda
python/merge-TVT-EW Rivet-TVT-Powheg-Run-II-W.yoda Rivet-TVT-Powheg-Run-II-Z-{e,{,LowMass-,HighMass-}mu}.yoda\
Rivet-TVT-Powheg-Run-I-{W,Z,WZ}.yoda -o TVT-Powheg-WZ.yoda
python/merge-TVT-EW Rivet-TVT-Matchbox-Run-II-W.yoda Rivet-TVT-Matchbox-Run-II-Z-{e,{,LowMass-,HighMass-}mu}.yoda\
Rivet-TVT-Matchbox-Run-I-{W,Z,WZ}.yoda -o TVT-Matchbox-WZ.yoda
python/merge-TVT-EW Rivet-TVT-Dipole-Run-II-W.yoda Rivet-TVT-Dipole-Run-II-Z-{e,{,LowMass-,HighMass-}mu}.yoda\
Rivet-TVT-Dipole-Run-I-{W,Z,WZ}.yoda -o TVT-Dipole-WZ.yoda
rivet-mkhtml -o Rivet-TVT-WZ TVT-WZ.yoda:Hw TVT-Powheg-WZ.yoda:Hw-Powheg TVT-Matchbox-WZ.yoda:Hw-Matchbox TVT-Dipole-WZ.yoda:Hw-Dipole
touch $@
Rivet-TVT-Photon : Rivet-TVT-Photon/done
touch $@
Rivet-TVT-Photon/done: $(shell echo Rivet-TVT-Run-II-{DiPhoton-GammaGamma,DiPhoton-GammaJet,PromptPhoton}.yoda) \
$(shell echo Rivet-Powheg-TVT-Run-II-{DiPhoton-GammaGamma,DiPhoton-GammaJet}.yoda)
rm -rf Rivet-TVT-Photon
python/merge-TVT-Photon TVT -o TVT-Photon.yoda
python/merge-TVT-Photon TVT-Powheg -o TVT-Powheg-Photon.yoda
rivet-mkhtml -o Rivet-TVT-Photon TVT-Photon.yoda:Hw TVT-Powheg-Photon.yoda:Hw-Powheg
touch $@
Rivet-TVT-Jets : Rivet-TVT-Jets/done
touch $@
Rivet-TVT-Jets/done: $(shell echo Rivet-TVT-{Run-II-Jets-{0..11},Run-I-Jets-{1..8}}.yoda ) \
$(shell echo Rivet-TVT-{630-Jets-{1..3},300-Jets-1,900-Jets-1}.yoda ) \
$(shell echo Rivet-TVT-{Run-I,Run-II,300,630,900}-UE.yoda)
rm -rf Rivet-TVT-Jets
python/merge-TVT-Jets TVT
rivet-mkhtml -o Rivet-TVT-Jets TVT-Jets.yoda:Hw
touch $@
#python/merge-TVT-Energy TVT
#rivet-merge-CDF_2012_NOTE10874 TVT-300-Energy.yoda TVT-900-Energy.yoda TVT-1960-Energy.yoda
#flat2yoda RatioPlots.dat -o TVT-RatioPlots.yoda
Rivet-Star : Rivet-Star/done
touch $@
Rivet-Star/done : $(shell echo Rivet-Star-{UE,Jets-{1..4}}.yoda )
rm -rf Rivet-Star
python/merge-Star Star
## broken DVI? ## rivet-mkhtml -v -o Rivet-Star Star.yoda
mkdir -p Rivet-Star # remove when fixed
touch $@
Rivet-SppS : Rivet-SppS/done
touch $@
## $(shell echo Rivet-ISR-{30,44,53,62}-UE.yoda ) \
## {53,63,200,500,900,546}
Rivet-SppS/done : $(shell echo Rivet-SppS-{200,500,900,546}-UE.yoda )
rm -rf Rivet-SppS
python/merge-SppS SppS
rivet-mkhtml -o Rivet-SppS SppS.yoda
touch $@
Rivet-LHC-Jets : Rivet-LHC-Jets/done
touch $@
Rivet-LHC-Jets/done : \
$(shell echo Rivet-LHC-7-DiJets-{1..7}-{A,B,C}.yoda ) \
$(shell echo Rivet-LHC-{7,8,13}-Jets-{0..10}.yoda ) \
$(shell echo Rivet-LHC-{900,2360,2760,7,8,13}-UE.yoda ) \
$(shell echo Rivet-LHC-{900,7,13}-UE-Long.yoda ) \
- $(shell echo Rivet-LHC-7-Charm-{1..5}.yoda ) \
- $(shell echo Rivet-LHC-7-Bottom-{0..8}.yoda ) \
- $(shell echo Rivet-LHC-7-Top-{L,SL}.yoda ) \
- $(shell echo Rivet-LHC-{7,8,13}-Top-All.yoda )
+ $(shell echo Rivet-LHC-7-Charm-{1..5}.yoda ) \
+ $(shell echo Rivet-LHC-7-Bottom-{0..8}.yoda ) \
+ $(shell echo Rivet-LHC-{7,8,13}-Top-{L,SL,All}.yoda )
rm -rf Rivet-LHC-Jets
python/merge-LHC-Jets LHC
rivet-mkhtml -o Rivet-LHC-Jets LHC-Jets.yoda:Hw
touch $@
Rivet-LHC-EW : Rivet-LHC-EW/done
touch $@
Rivet-LHC-EW/done: \
- $(shell echo Rivet{,-Matchbox,-Powheg,-Dipole}-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-SOPHTY},Z-LowMass-{e,mu},Z-MedMass-e,WZ,WW-{emu,ll},ZZ-{ll,lv},8-ZZ-lv,8-WW-ll,W-Z-{e,mu}}.yoda) \
+ $(shell echo Rivet{,-Matchbox,-Powheg,-Dipole}-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-SOPHTY},Z-LowMass-{e,mu},Z-MedMass-e,WZ,WW-{emu,ll},ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll,W-Z-{e,mu}}.yoda) \
$(shell echo Rivet{,-Matchbox,-Dipole}-LHC-{7-W-Jet-{1..3}-e,7-Z-Jet-{0..3}-e,7-Z-Jet-0-mu}.yoda) \
$(shell echo Rivet{-Matchbox,-Dipole}-LHC-{Z-b,Z-bb,W-b,8-Z-jj}.yoda) \
$(shell echo Rivet-LHC-7-{W,Z}Gamma-{e,mu}.yoda)
rm -rf Rivet-LHC-EW;
- python/merge-LHC-EW Rivet-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-7-{W,Z}-Jet-{1,2,3}-e.yoda Rivet-LHC-7-{W,Z}Gamma-{e,mu}.yoda -o LHC-EW.yoda;
- python/merge-LHC-EW Rivet-Matchbox-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-Matchbox-7-{W,Z}-Jet-{1,2,3}-e.yoda -o LHC-Matchbox-EW.yoda;
- python/merge-LHC-EW Rivet-Dipole-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-Dipole-7-{W,Z}-Jet-{1,2,3}-e.yoda -o LHC-Dipole-EW.yoda;
- python/merge-LHC-EW Rivet-Powheg-LHC-{W-{e,mu},Z-{e,mu},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},8-ZZ-lv,8-WW-ll}.yoda -o LHC-Powheg-EW.yoda;
+ python/merge-LHC-EW Rivet-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-7-{W,Z}-Jet-{1,2,3}-e.yoda Rivet-LHC-7-{W,Z}Gamma-{e,mu}.yoda -o LHC-EW.yoda;
+ python/merge-LHC-EW Rivet-Matchbox-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},{8,13}-WZ,{8,13}-WZ,8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-Matchbox-7-{W,Z}-Jet-{1,2,3}-e.yoda -o LHC-Matchbox-EW.yoda;
+ python/merge-LHC-EW Rivet-Dipole-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-Dipole-7-{W,Z}-Jet-{1,2,3}-e.yoda -o LHC-Dipole-EW.yoda;
+ python/merge-LHC-EW Rivet-Powheg-LHC-{W-{e,mu},Z-{e,mu},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll}.yoda -o LHC-Powheg-EW.yoda;
rivet-mkhtml -o Rivet-LHC-EW LHC-EW.yoda:Hw LHC-Powheg-EW.yoda:Hw-Powheg LHC-Matchbox-EW.yoda:Hw-Matchbox LHC-Matchbox-Z-b.yoda:Hw-Matchbox-Zb \
LHC-Matchbox-Z-bb.yoda:Hw-Matchbox-Zbb LHC-Matchbox-W-b.yoda:Hw-Matchbox-W-bb LHC-Dipole-EW.yoda:Hw-Dipole \
LHC-Dipole-Z-b.yoda:Hw-Dipole-Zb LHC-Dipole-Z-bb.yoda:Hw-Dipole-Zbb LHC-Dipole-W-b.yoda:Hw-Dipole-W-bb \
LHC-Z-mu-SOPHTY.yoda:Hw LHC-Powheg-Z-mu-SOPHTY.yoda:Hw-Powheg LHC-Matchbox-Z-mu-SOPHTY.yoda:Hw-Matchbox
touch $@
Rivet-LHC-Photon : Rivet-LHC-Photon/done
touch $@
Rivet-LHC-Photon/done: \
$(shell echo Rivet-LHC-{7,8}-PromptPhoton-{1..4}.yoda) \
Rivet-LHC-GammaGamma-7.yoda \
$(shell echo Rivet{,-Powheg}-LHC-{7,8}-{DiPhoton-GammaGamma,DiPhoton-GammaJet}.yoda)
rm -rf Rivet-LHC-Photon
python/merge-LHC-Photon LHC -o LHC-Photon.yoda
python/merge-LHC-Photon LHC-Powheg -o LHC-Powheg-Photon.yoda
rivet-mkhtml -o Rivet-LHC-Photon LHC-Photon.yoda:Hw LHC-Powheg-Photon.yoda:Hw-Powheg
touch $@
Rivet-LHC-Higgs : Rivet-LHC-Higgs/done
touch $@
Rivet-LHC-Higgs/done: \
$(shell echo Rivet{,-Powheg}-LHC-{ggH,VBF,WH,ZH}.yoda) \
$(shell echo Rivet{,-Powheg}-LHC-8-{{ggH,VBF,WH,ZH}{,-GammaGamma},ggH-WW}.yoda) \
Rivet-LHC-ggHJet.yoda
rm -rf Rivet-LHC-Higgs
rivet-mkhtml -o Rivet-LHC-Higgs LHC-Powheg-ggH.yoda:gg-Powheg LHC-ggH.yoda:gg LHC-ggHJet.yoda:HJet \
LHC-Powheg-VBF.yoda:VBF-Powheg LHC-VBF.yoda:VBF LHC-WH.yoda:WH LHC-ZH.yoda:ZH \
LHC-Powheg-WH.yoda:WH-Powheg LHC-Powheg-ZH.yoda:ZH-Powheg
touch $@
clean-local:
rm -f *.out *.log *.tex *.top *.run *.dump *.mult *.Bmult *.yoda Rivet/*.in
rm -rf Rivet-*
distclean-local:
rm -rf .cache
diff --git a/Tests/Rivet/LHC/LHC-13-Top-All.in b/Tests/Rivet/LHC/LHC-13-Top-All.in
--- a/Tests/Rivet/LHC/LHC-13-Top-All.in
+++ b/Tests/Rivet/LHC/LHC-13-Top-All.in
@@ -1,5 +1,3 @@
##################################################
# select the analyses
-##################################################
-# ATLAS top
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1468168
+##################################################
\ No newline at end of file
diff --git a/Tests/Rivet/LHC/LHC-13-Top-L.in b/Tests/Rivet/LHC/LHC-13-Top-L.in
new file mode 100644
--- /dev/null
+++ b/Tests/Rivet/LHC/LHC-13-Top-L.in
@@ -0,0 +1,6 @@
+##################################################
+# select the analyses
+##################################################
+# ATLAS top
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1468168
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1495243
\ No newline at end of file
diff --git a/Tests/Rivet/LHC/LHC-13-Top-SL.in b/Tests/Rivet/LHC/LHC-13-Top-SL.in
new file mode 100644
--- /dev/null
+++ b/Tests/Rivet/LHC/LHC-13-Top-SL.in
@@ -0,0 +1,4 @@
+##################################################
+# select the analyses
+##################################################
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1491950
\ No newline at end of file
diff --git a/Tests/Rivet/LHC/LHC-WZ.in b/Tests/Rivet/LHC/LHC-13-WZ.in
copy from Tests/Rivet/LHC/LHC-WZ.in
copy to Tests/Rivet/LHC/LHC-13-WZ.in
--- a/Tests/Rivet/LHC/LHC-WZ.in
+++ b/Tests/Rivet/LHC/LHC-13-WZ.in
@@ -1,5 +1,5 @@
##################################################
# select the analyses
##################################################
# general analysis
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I954993
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1469071
diff --git a/Tests/Rivet/LHC/LHC-13-Z-e.in b/Tests/Rivet/LHC/LHC-13-Z-e.in
--- a/Tests/Rivet/LHC/LHC-13-Z-e.in
+++ b/Tests/Rivet/LHC/LHC-13-Z-e.in
@@ -1,5 +1,6 @@
##################################################
# select the analyses
##################################################
# ATLAS Z
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_CONF_2015_041_EL
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1514251
\ No newline at end of file
diff --git a/Tests/Rivet/LHC/LHC-2760-UE.in b/Tests/Rivet/LHC/LHC-2760-UE.in
--- a/Tests/Rivet/LHC/LHC-2760-UE.in
+++ b/Tests/Rivet/LHC/LHC-2760-UE.in
@@ -1,7 +1,9 @@
##################################################
# select the analyses
##################################################
# underlying event forward rapidities
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1218372
# underlying event
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2015_I1385107
+# ALICE neutral pion cross section
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2017_I1512110
diff --git a/Tests/Rivet/LHC/LHC-7-UE.in b/Tests/Rivet/LHC/LHC-7-UE.in
--- a/Tests/Rivet/LHC/LHC-7-UE.in
+++ b/Tests/Rivet/LHC/LHC-7-UE.in
@@ -1,90 +1,90 @@
##################################################
# select the analyses
##################################################
# ATLAS jet shapes
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791
# ATLAS jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936
# ATLAS UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8994773
# ATLAS UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8894728
# ATLAS fragmentation function
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_CONF_2010_049
# ATLAS UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8918562
# ALICE charged particles
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2010_S8625980
# CMS particle spectra
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8978280
# CMS charged particle multiplicity
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8884919
# CMS charged particle pT and rapidity
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2010_S8656010
# CMS UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9120041
# ATLAS track jet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017
# LHCB phi production
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2011_I919315
# ATLAS phi production
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1282441
# LHCB promt hadron productiom
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2012_I1119400
# ATLAS rap gap
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1084540
# CMS forward energy flow
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9215166
# LHC K0s/Lambda
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2011_I917009
# TOTEM at large rapidity
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 TOTEM_2012_I1115294
# ATLAS Azimuthal ordering of charged hadrons
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1091481
# ALICE single/double diffractive and inelastic sigma
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2012_I1181770
# ATLAS inelastic cross section
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I894867
# CMS inelastic cross section
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1193338
# total transverse energy
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1183818
# underlying event forward rapidities
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1218372
# strange particles in underlying event
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_PAS_QCD_11_010
# CMS central and forward jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342
# CMS dijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1184941
# ATLAS charged particle in min bias
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1125575
# ATLAS two particle correlation
#insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094061
# ATLAS correlations
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1093734
# LHCB energy flow
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2013_I1208105
# ATLAS charged particle event shapes
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1124167
# CMS Jet/UE properties
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1261026
# ATLAS leading jet UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811
# LHCB charged particles in min bias
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2014_I1281685
# ALICE identified particle spectra
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2015_I1357424
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2014_I1300380
# LHCB min bias
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2015_I1333223
# ALICE pion and eta pT
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2012_I1116147
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_PAS_FSQ_12_020
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_PAS_FSQ_12_020
# CMS charged particle rapidity
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2010_PAS_QCD_10_024
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_QCD_10_024
# diffractive analyses
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCF_2012_I1115479
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2015_I1356998
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 TOTEM_2012_I1220862
\ No newline at end of file
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-1.in b/Tests/Rivet/LHC/LHC-8-Jets-1.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-1.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-1.in
@@ -1,4 +1,6 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-10.in b/Tests/Rivet/LHC/LHC-8-Jets-10.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-10.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-10.in
@@ -1,6 +1,8 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS multijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-2.in b/Tests/Rivet/LHC/LHC-8-Jets-2.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-2.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-2.in
@@ -1,4 +1,6 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-3.in b/Tests/Rivet/LHC/LHC-8-Jets-3.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-3.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-3.in
@@ -1,6 +1,8 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS multijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-4.in b/Tests/Rivet/LHC/LHC-8-Jets-4.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-4.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-4.in
@@ -1,6 +1,8 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS multijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-5.in b/Tests/Rivet/LHC/LHC-8-Jets-5.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-5.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-5.in
@@ -1,6 +1,8 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS multijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-6.in b/Tests/Rivet/LHC/LHC-8-Jets-6.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-6.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-6.in
@@ -1,6 +1,8 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS multijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-7.in b/Tests/Rivet/LHC/LHC-8-Jets-7.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-7.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-7.in
@@ -1,6 +1,8 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS multijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-8.in b/Tests/Rivet/LHC/LHC-8-Jets-8.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-8.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-8.in
@@ -1,6 +1,8 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS multijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Jets-9.in b/Tests/Rivet/LHC/LHC-8-Jets-9.in
--- a/Tests/Rivet/LHC/LHC-8-Jets-9.in
+++ b/Tests/Rivet/LHC/LHC-8-Jets-9.in
@@ -1,6 +1,8 @@
# ATLAS tracks in jets
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070
# ATLAS multijet
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679
# ATLAS jet charge
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758
+# ATLAS transverse energy correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253
diff --git a/Tests/Rivet/LHC/LHC-8-Top-All.in b/Tests/Rivet/LHC/LHC-8-Top-All.in
--- a/Tests/Rivet/LHC/LHC-8-Top-All.in
+++ b/Tests/Rivet/LHC/LHC-8-Top-All.in
@@ -1,21 +1,7 @@
##################################################
# select the analyses
##################################################
-# ATLAS pull in top events
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1376945
# CMS top
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2015_I1370682
-# ATLAS top + b jet
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1390114
-# ATLAS boosted t tbar
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1397637
# CMS
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1473674
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2015_I1397174
-# ATLAS l +jets
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1397635
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1404878
-# ATLAS charge asymmetry
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1449082
-# cms boosted top
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1454211
\ No newline at end of file
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1473674
diff --git a/Tests/Rivet/LHC/LHC-8-Top-L.in b/Tests/Rivet/LHC/LHC-8-Top-L.in
new file mode 100644
--- /dev/null
+++ b/Tests/Rivet/LHC/LHC-8-Top-L.in
@@ -0,0 +1,15 @@
+##################################################
+# select the analyses
+##################################################
+# ATLAS top + b jet
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1390114
+# CMS
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2015_I1397174
+# ATLAS l +jets
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1397635
+# ATLAS charge asymmetry
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1449082
+# CMS diplepton charge asym
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1430892
+# CMS spin correlations
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1413748
diff --git a/Tests/Rivet/LHC/LHC-8-Top-SL.in b/Tests/Rivet/LHC/LHC-8-Top-SL.in
new file mode 100644
--- /dev/null
+++ b/Tests/Rivet/LHC/LHC-8-Top-SL.in
@@ -0,0 +1,13 @@
+##################################################
+# select the analyses
+##################################################
+# ATLAS pull in top events
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1376945
+# ATLAS top + b jet
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1390114
+# ATLAS boosted t tbar
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1397637
+# cms boosted top
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1454211
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1518399
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_PAS_TOP_15_006
\ No newline at end of file
diff --git a/Tests/Rivet/LHC/LHC-WZ.in b/Tests/Rivet/LHC/LHC-8-WZ.in
copy from Tests/Rivet/LHC/LHC-WZ.in
copy to Tests/Rivet/LHC/LHC-8-WZ.in
--- a/Tests/Rivet/LHC/LHC-WZ.in
+++ b/Tests/Rivet/LHC/LHC-8-WZ.in
@@ -1,5 +1,5 @@
##################################################
# select the analyses
##################################################
# general analysis
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I954993
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1426523
diff --git a/Tests/Rivet/LHC/LHC-900-UE.in b/Tests/Rivet/LHC/LHC-900-UE.in
--- a/Tests/Rivet/LHC/LHC-900-UE.in
+++ b/Tests/Rivet/LHC/LHC-900-UE.in
@@ -1,53 +1,53 @@
##################################################
# select the analyses
##################################################
# ATLAS UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8994773
# ATLAS UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8918562
# ATLAS UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8894728
# ATLAS charged particles
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8591806
# ALICE charged particles
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2010_S8706239
# ALICE charged particles
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2010_S8625980
# ALICE charged particles
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2010_S8624100
# ALICE particle spectra
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2011_S8945144
# ALICE strange particle production
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2011_S8909580
# CMS particle spectra
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8978280
# CMS charged particle multiplicity
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8884919
# CMS charged particle pT and rapidity
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2010_S8547297
# CMS UE
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9120041
# LHCB k_s0
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2010_S8758301
# LHCB promt hadron production
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2012_I1119400
# CMS forward energy flow
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9215166
# LHC K0s/Lambda
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2011_I917009
# ATLAS Azimuthal ordering of charged hadrons
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1091481
# ALICE single/double diffractive and inelastic sigma
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2012_I1181770
# ATLAS inelastic cross section
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I894867
# underlying event forward rapidities
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1218372
# ATLAS two particle correlation
#insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094061
# ATLAS correlations
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1093734
# ALICE pion and eta pT
insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2012_I1116147
# CMS charged particle rapidity
-insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2010_PAS_QCD_10_024
+insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_QCD_10_024
diff --git a/Tests/python/make_input_files.py b/Tests/python/make_input_files.py
--- a/Tests/python/make_input_files.py
+++ b/Tests/python/make_input_files.py
@@ -1,1790 +1,1790 @@
#! /usr/bin/env python
import logging,sys,os
from string import strip, Template
import sys
if sys.version_info[:3] < (2,4,0):
print "rivet scripts require Python version >= 2.4.0... exiting"
sys.exit(1)
if __name__ == "__main__":
import logging
from optparse import OptionParser, OptionGroup
parser = OptionParser(usage="%prog name [...]")
simulation=""
numberOfAddedProcesses=0
def addProcess(thefactory,theProcess,Oas,Oew,scale,mergedlegs,NLOprocesses):
global numberOfAddedProcesses
global simulation
numberOfAddedProcesses+=1
res ="set "+thefactory+":OrderInAlphaS "+Oas+"\n"
res+="set "+thefactory+":OrderInAlphaEW "+Oew+"\n"
res+="do "+thefactory+":Process "+theProcess+" "
if ( mergedlegs != 0 ):
if simulation!="Merging":
print "simulation is not Merging, trying to add merged legs."
sys.exit(1)
res+="["
for j in range(mergedlegs):
res+=" j "
res+="]"
res+="\n"
if (NLOprocesses!=0):
if simulation!="Merging":
print "simulation is not Merging, trying to add NLOProcesses."
sys.exit(1)
res+="set MergingFactory:NLOProcesses %s \n" % NLOprocesses
if ( scale != "" ):
res+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/"+scale+"\n"
return res
def addLeptonPairCut(minmass,maxmass):
return "set /Herwig/Cuts/LeptonPairMassCut:MinMass "+minmass+"*GeV\nset /Herwig/Cuts/LeptonPairMassCut:MaxMass "+maxmass+"*GeV\n"
didaddfirstjet=False
def addFirstJet(ptcut):
global didaddfirstjet
if(didaddfirstjet):
logging.error("Can only add jetcut once.")
sys.exit(1)
res="set /Herwig/Cuts/Cuts:JetFinder /Herwig/Cuts/JetFinder\n"
res+="insert /Herwig/Cuts/Cuts:MultiCuts 0 /Herwig/Cuts/JetCuts\n"
res+="insert /Herwig/Cuts/JetCuts:JetRegions 0 /Herwig/Cuts/FirstJet\n"
if(ptcut!=""):
res+="set /Herwig/Cuts/FirstJet:PtMin "+ptcut+".*GeV\n"
didaddfirstjet=True
return res
didaddsecondjet=False
def addSecondJet(ptcut):
global didaddsecondjet
if(didaddsecondjet):
logging.error("Can only add second jetcut once.")
sys.exit(1)
res="insert /Herwig/Cuts/JetCuts:JetRegions 0 /Herwig/Cuts/SecondJet\n"
res+="set /Herwig/Cuts/SecondJet:PtMin "+ptcut+".*GeV\n"
didaddsecondjet=True
return res
didaddjetpair=False
def addJetPairCut(minmass):
global didaddjetpair
if(didaddjetpair):
logging.error("Can only add second jetcut once.")
sys.exit(1)
res="""\
create ThePEG::JetPairRegion /Herwig/Cuts/JetPairMass JetCuts.so
set /Herwig/Cuts/JetPairMass:FirstRegion /Herwig/Cuts/FirstJet
set /Herwig/Cuts/JetPairMass:SecondRegion /Herwig/Cuts/SecondJet
insert /Herwig/Cuts/JetCuts:JetPairRegions 0 /Herwig/Cuts/JetPairMass
set /Herwig/Cuts/JetPairMass:MassMin {mm}.*GeV
""".format(mm=minmass)
didaddjetpair=True
return res
addedBRReweighter=False
def addBRReweighter():
global addedBRReweighter
if(addedBRReweighter):
logging.error("Can only add BRReweighter once.")
sys.exit(1)
res="create Herwig::BranchingRatioReweighter /Herwig/Generators/BRReweighter\n"
res+="insert /Herwig/Generators/EventGenerator:EventHandler:PostHadronizationHandlers 0 /Herwig/Generators/BRReweighter\n"
addedBRReweighter=True
return res
def setHardProcessWidthToZero(list1):
res=""
for i in list1:
res+="set /Herwig/Particles/"+i+":HardProcessWidth 0.\n"
return res
selecteddecaymode=False
def selectDecayMode(particle,decaymodes):
global selecteddecaymode
res="do /Herwig/Particles/"+particle+":SelectDecayModes"
for decay in decaymodes:
res+=" /Herwig/Particles/"+particle+"/"+decay
res+="\n"
selecteddecaymode=True
return res
def jet_kt_cut(energy):
return "set /Herwig/Cuts/JetKtCut:MinKT {E}*GeV\n".format(E=energy)
def mhatmin_cut(energy):
return "set /Herwig/Cuts/Cuts:MHatMin {E}*GeV\n".format(E=energy)
def mhat_minm_maxm(e1,e2,e3):
return """\
set /Herwig/Cuts/Cuts:MHatMin {e1}*GeV
set /Herwig/Cuts/MassCut:MinM {e2}*GeV
set /Herwig/Cuts/MassCut:MaxM {e3}*GeV
""".format(**locals())
def collider_lumi(energy):
return "set /Herwig/Generators/EventGenerator:EventHandler:LuminosityFunction:Energy {E}*GeV\n".format(E=energy)
def insert_ME(me,process=None,ifname='Process'):
result = "insert /Herwig/MatrixElements/SubProcess:MatrixElements 0 /Herwig/MatrixElements/{me}\n".format(**locals())
if process is not None:
result += "set /Herwig/MatrixElements/{me}:{ifname} {process}".format(**locals())
return result
def particlegroup(name,*particles):
result = ["do /Herwig/MatrixElements/Matchbox/Factory:StartParticleGroup {n}".format(n=name)]
for p in particles:
result.append(
"insert /Herwig/MatrixElements/Matchbox/Factory:ParticleGroup 0 /Herwig/Particles/{p}".format(p=p)
)
result.append("do /Herwig/MatrixElements/Matchbox/Factory:EndParticleGroup")
return '\n'.join(result)
# settings for four flavour scheme
fourFlavour="""
read Matchbox/FourFlavourScheme.in
{bjetgroup}
set /Herwig/Cuts/MatchboxJetMatcher:Group bjet
""".format(bjetgroup=particlegroup('bjet','b','bbar','c', 'cbar',
's','sbar','d','dbar','u','ubar','g'))
ME_Upsilon = """\
create Herwig::MEee2VectorMeson /Herwig/MatrixElements/MEUpsilon HwMELepton.so
set /Herwig/MatrixElements/MEUpsilon:VectorMeson /Herwig/Particles/Upsilon(4S)
set /Herwig/MatrixElements/MEUpsilon:Coupling 0.0004151809
""" + insert_ME("MEUpsilon")
(opts, args) = parser.parse_args()
## Check args
if len(args) != 1:
logging.error("Must specify at least input file")
sys.exit(1)
name = args[0]
print name
# select the template to load
# collider
KNOWN_COLLIDERS = [
"BFactory",
"LEP",
"DIS",
"TVT",
"LHC-GammaGamma",
"LHC",
"ISR",
"SppS",
"Star",
]
collider = ""
for cand_collider in KNOWN_COLLIDERS:
if cand_collider in name:
collider = cand_collider
break
del cand_collider
assert collider
have_hadronic_collider = collider in ["TVT","LHC","ISR","SppS","Star"]
thefactory="Factory"
parameters = {
'shower' : '',
'bscheme' : '',
}
# istart determines how many name parts need to be skipped
istart = 1
# Dipole shower with Matchbox Powheg
if "Dipole-Matchbox-Powheg" in name :
istart = 4
simulation="Matchbox"
parameters["shower"] = "read Matchbox/Powheg-DipoleShower.in\n"
# Dipole shower with internal Powheg - Todo: Finish modifying template files.
'''
elif "Dipole-Powheg" in name :
istart = 3
simulation="Powheg"
- parameters["shower"] = "set /Herwig/EventHandlers/EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler\nread Matchbox/MCatNLO-Dipole-HardAlphaSTune.in\n"
+ parameters["shower"] = "set /Herwig/EventHandlers/EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler\nread snippets/Dipole_AutoTune_prel.in\n"
'''
# Dipole shower with MCatNLO
elif "Dipole-MCatNLO" in name :
istart = 3
simulation="Matchbox"
parameters["shower"] = "read Matchbox/MCatNLO-DipoleShower.in\n"
# Dipole shower with Matchbox LO
elif "Dipole-Matchbox-LO" in name :
istart = 4
simulation="Matchbox"
parameters["shower"] = "read Matchbox/LO-DipoleShower.in\n"
# Dipole shower with internal LO
elif "Dipole" in name :
istart = 2
simulation=""
- parameters["shower"] = "set /Herwig/EventHandlers/EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler\nread Matchbox/MCatNLO-Dipole-HardAlphaSTune.in\n"
+ parameters["shower"] = "set /Herwig/EventHandlers/EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler\nread snippets/Dipole_AutoTune_prel.in\n"
# AO shower with Matchbox Powheg
elif "Matchbox-Powheg" in name :
istart = 3
simulation="Matchbox"
parameters["shower"] = "read Matchbox/Powheg-DefaultShower.in\n"
# AO shower with MCatNLO
elif "Matchbox" in name :
istart = 2
simulation="Matchbox"
parameters["shower"] = "read Matchbox/MCatNLO-DefaultShower.in\n"
# AO shower with inernal Powheg
elif "Powheg" in name :
istart = 2
simulation="Powheg"
# Dipole shower with merging
elif "Merging" in name :
istart = 2
simulation="Merging"
thefactory="MergingFactory"
# Flavour settings for Matchbox
if simulation=="Matchbox" :
parameters["bscheme"] = "read Matchbox/FiveFlavourScheme.in\n"
if "Dipole" in parameters["shower"] :
parameters["bscheme"] += "read Matchbox/FiveFlavourNoBMassScheme.in\n"
if collider not in ['DIS','LEP'] :
parameters["nlo"] = "read Matchbox/MadGraph-OpenLoops.in\n"
# Flavour settings for dipole shower with internal ME
if simulation=="" and "Dipole" in parameters["shower"] :
parameters["bscheme"] = "read snippets/DipoleShowerFiveFlavours.in"
# find the template
if simulation=="" :
if collider=="LHC-GammaGamma" :
istart += 1
templateName="Hadron-Gamma.in"
elif have_hadronic_collider :
templateName="Hadron.in"
elif collider != "BFactory" :
templateName= "%s.in" % collider
else :
templateName= "LEP.in"
else :
if have_hadronic_collider :
templateName= "Hadron-%s.in" % simulation
elif collider != "BFactory" :
templateName= "%s-%s.in" % (collider,simulation)
else :
templateName= "LEP-%s.in" % simulation
# work out the name of the parameter file
parameterName="-".join(name.split("-")[istart:])
del istart
class StringBuilder(object):
"""
Avoid expensive string additions until the end
by building up a list first.
This helper class avoids rewriting all the += lower down
to list operations.
"""
def __init__(self, init = None):
self.lines = [] if init is None else [init]
def __iadd__(self, line):
self.lines.append(line)
return self
def __str__(self):
return '\n'.join(self.lines)
# work out the process and parameters
process=StringBuilder()
# Bfactory
if(collider=="BFactory") :
if(simulation=="") :
if(parameterName=="10.58-res") :
process += ME_Upsilon
elif(parameterName=="10.58") :
process += ME_Upsilon
process += "set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4\n"
else :
process+=insert_ME("MEee2gZ2qq")
process+= "set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4\n"
elif(simulation=="Powheg") :
process = StringBuilder("set /Herwig/MatrixElements/PowhegMEee2gZ2qq:MaximumFlavour 4\n")
elif(simulation=="Matchbox" ) :
process = StringBuilder(addProcess(thefactory,"e- e+ -> u ubar","0","2","",0,0))
process+=addProcess(thefactory,"e- e+ -> d dbar","0","2","",0,0)
process+=addProcess(thefactory,"e- e+ -> c cbar","0","2","",0,0)
process+=addProcess(thefactory,"e- e+ -> s sbar","0","2","",0,0)
elif(simulation=="Merging" ) :
logging.warning("BFactory not explicitly tested for %s " % simulation)
sys.exit(0)
# DIS
elif(collider=="DIS") :
if(simulation=="") :
if "NoME" in parameterName :
process = StringBuilder("set /Herwig/Shower/ShowerHandler:HardEmission None")
parameterName=parameterName.replace("NoME-","")
else :
process = StringBuilder("")
elif(simulation=="Powheg") :
process = StringBuilder("")
elif(simulation=="Matchbox" ) :
if "e-" in parameterName :
process = StringBuilder(addProcess(thefactory,"e- p -> e- j","0","2","",0,0))
else :
process = StringBuilder(addProcess(thefactory,"e+ p -> e+ j","0","2","",0,0))
elif(simulation=="Merging" ) :
if "e-" in parameterName :
process = StringBuilder(addProcess(thefactory,"e- p -> e- j","0","2","",2,2))
else :
process = StringBuilder(addProcess(thefactory,"e+ p -> e+ j","0","2","",2,2))
# LEP
elif(collider=="LEP") :
if(simulation=="") :
if "gg" in parameterName :
process = StringBuilder("create Herwig::MEee2Higgs2SM /Herwig/MatrixElements/MEee2Higgs2SM\n")
process+=insert_ME("MEee2Higgs2SM","Gluon","Allowed")
else :
process = StringBuilder(insert_ME("MEee2gZ2qq"))
if(parameterName=="10") :
process+="set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4"
elif(simulation=="Powheg") :
process = StringBuilder()
if(parameterName=="10") :
process = StringBuilder("set /Herwig/MatrixElements/PowhegMEee2gZ2qq:MaximumFlavour 4")
elif(simulation=="Matchbox" ) :
if(parameterName=="10") :
process = StringBuilder(addProcess(thefactory,"e- e+ -> u ubar","0","2","",0,0))
process+=addProcess(thefactory,"e- e+ -> d dbar","0","2","",0,0)
process+=addProcess(thefactory,"e- e+ -> c cbar","0","2","",0,0)
process+=addProcess(thefactory,"e- e+ -> s sbar","0","2","",0,0)
else :
process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",0,0))
elif(simulation=="Merging" ) :
if(parameterName=="10") :
process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",2,2))
process+="read Matchbox/FourFlavourScheme.in"
else :
process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",2,2))
# TVT
elif(collider=="TVT") :
process = StringBuilder("set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/pbar-\n")
if "Run-II" in parameterName : process+=collider_lumi(1960.0)
elif "Run-I" in parameterName : process+=collider_lumi(1800.0)
elif "900" in parameterName : process+=collider_lumi(900.0)
elif "630" in parameterName : process+=collider_lumi(630.0)
elif "300" in parameterName : process+=collider_lumi(300.0)
if(simulation=="") :
if "PromptPhoton" in parameterName :
process+=insert_ME("MEGammaJet")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 15.\n"
elif "DiPhoton-GammaGamma" in parameterName :
process+=insert_ME("MEGammaGamma")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
parameterName=parameterName.replace("-GammaGamma","")
elif "DiPhoton-GammaJet" in parameterName :
process+=insert_ME("MEGammaJet")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
parameterName=parameterName.replace("-GammaJet","")
elif "UE" in parameterName :
if "Dipole" in parameters["shower"]:
process+="read snippets/MB-DipoleShower.in\n"
else:
process+="read snippets/MB.in\n"
process+="read snippets/Diffraction.in\n"
process += "set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n"
process += "set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n"
elif "Jets" in parameterName :
process+=insert_ME("MEQCD2to2")
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "Run-II-Jets-10" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(500.)
elif "Run-II-Jets-11" in parameterName: process+=jet_kt_cut( 30.)+mhatmin_cut(900.)
elif "Run-I-Jets-1" in parameterName : process+=jet_kt_cut( 20.)
elif "Run-I-Jets-2" in parameterName : process+=jet_kt_cut( 40.)
elif "Run-I-Jets-3" in parameterName : process+=jet_kt_cut( 65.)
elif "Run-I-Jets-4" in parameterName : process+=jet_kt_cut( 90.)
elif "Run-I-Jets-5" in parameterName : process+=jet_kt_cut(160.)
elif "Run-I-Jets-6" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(100.)
elif "Run-I-Jets-7" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(400.)
elif "Run-I-Jets-8" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(700.)
elif "Run-II-Jets-0" in parameterName : process+=jet_kt_cut( 15.)
elif "Run-II-Jets-1" in parameterName : process+=jet_kt_cut( 25.)
elif "Run-II-Jets-2" in parameterName : process+=jet_kt_cut( 40.)
elif "Run-II-Jets-3" in parameterName : process+=jet_kt_cut( 60.)
elif "Run-II-Jets-4" in parameterName : process+=jet_kt_cut( 85.)
elif "Run-II-Jets-5" in parameterName : process+=jet_kt_cut(110.)
elif "Run-II-Jets-6" in parameterName : process+=jet_kt_cut(160.)
elif "Run-II-Jets-7" in parameterName : process+=jet_kt_cut(250.)
elif "Run-II-Jets-8" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(100.)
elif "Run-II-Jets-9" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(300.)
elif "900-Jets-1" in parameterName : process+=jet_kt_cut( 10.)
elif "300-Jets-1" in parameterName : process+=jet_kt_cut( 6.)
elif "630-Jets-1" in parameterName : process+=jet_kt_cut( 20.)
elif "630-Jets-2" in parameterName : process+=jet_kt_cut( 40.)
elif "630-Jets-3" in parameterName : process+=jet_kt_cut( 75.)
elif "900-Jets-1" in parameterName : process+=jet_kt_cut( 10.)
elif "Run-I-WZ" in parameterName :
process+=insert_ME("MEqq2W2ff","Electron")
process+=insert_ME("MEqq2gZ2ff","Electron")
elif "Run-II-W" in parameterName or "Run-I-W" in parameterName :
process+=insert_ME("MEqq2W2ff","Electron")
elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName :
process +=insert_ME("MEqq2gZ2ff","Electron")
elif "Run-II-Z-LowMass-mu" in parameterName :
process +=insert_ME("MEqq2gZ2ff","Muon")
process+=addLeptonPairCut("25","70")
elif "Run-II-Z-HighMass-mu" in parameterName :
process +=insert_ME("MEqq2gZ2ff","Muon")
process+=addLeptonPairCut("150","600")
elif "Run-II-Z-mu" in parameterName :
process +=insert_ME("MEqq2gZ2ff","Muon")
elif(simulation=="Powheg") :
if "Run-I-WZ" in parameterName :
process+=insert_ME("PowhegMEqq2W2ff","Electron")
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
elif "Run-II-W" in parameterName or "Run-I-W" in parameterName :
process+=insert_ME("PowhegMEqq2W2ff","Electron")
elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
elif "Run-II-Z-LowMass-mu" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
process+=addLeptonPairCut("25","70")
elif "Run-II-Z-HighMass-mu" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
process+=addLeptonPairCut("150","600")
elif "Run-II-Z-mu" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
elif "DiPhoton-GammaGamma" in parameterName :
process+=insert_ME("MEGammaGammaPowheg","GammaGamma")
process+=insert_ME("MEGammaGamma","gg")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
process+=jet_kt_cut(5.)
parameterName=parameterName.replace("-GammaGamma","")
elif "DiPhoton-GammaJet" in parameterName :
process+=insert_ME("MEGammaGammaPowheg","VJet")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
process+=jet_kt_cut(5.)
parameterName=parameterName.replace("-GammaJet","")
elif(simulation=="Matchbox" or simulation=="Merging" ) :
if "Jets" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p -> j j","2","0","MaxJetPtScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p -> j j","2","0","MaxJetPtScale",1,0)
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "Run-II-Jets-10" in parameterName :
process+=addFirstJet("30")
process+=addSecondJet("25")
process+=addJetPairCut("500")
elif "Run-II-Jets-11" in parameterName :
process+=addFirstJet("30")
process+=addSecondJet("25")
process+=addJetPairCut("900")
elif "Run-II-Jets-12" in parameterName :
process+=addFirstJet("30")
process+=addSecondJet("25")
process+=addJetPairCut("300")
elif "Run-I-Jets-1" in parameterName : process+=addFirstJet("20")
elif "Run-I-Jets-2" in parameterName : process+=addFirstJet("40")
elif "Run-I-Jets-3" in parameterName : process+=addFirstJet("65")
elif "Run-I-Jets-4" in parameterName : process+=addFirstJet("90")
elif "Run-I-Jets-5" in parameterName : process+=addFirstJet("160")
elif "Run-I-Jets-6" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("100")
elif "Run-I-Jets-7" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("400")
elif "Run-I-Jets-8" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("700")
elif "Run-II-Jets-0" in parameterName : process+=addFirstJet("15")
elif "Run-II-Jets-1" in parameterName : process+=addFirstJet("25")
elif "Run-II-Jets-2" in parameterName : process+=addFirstJet("40")
elif "Run-II-Jets-3" in parameterName : process+=addFirstJet("60")
elif "Run-II-Jets-4" in parameterName : process+=addFirstJet("85")
elif "Run-II-Jets-5" in parameterName : process+=addFirstJet("110")
elif "Run-II-Jets-6" in parameterName : process+=addFirstJet("160")
elif "Run-II-Jets-7" in parameterName : process+=addFirstJet("250")
elif "Run-II-Jets-8" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("100")
elif "Run-II-Jets-9" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("300")
elif "900-Jets-1" in parameterName : process+=addFirstJet("10")
elif "300-Jets-1" in parameterName : process+=addFirstJet("6")
elif "630-Jets-1" in parameterName : process+=addFirstJet("20")
elif "630-Jets-2" in parameterName : process+=addFirstJet("40")
elif "630-Jets-3" in parameterName : process+=addFirstJet("75")
elif "900-Jets-1" in parameterName : process+=addFirstJet("10")
else :
logging.error("Exit 00007")
sys.exit(1)
elif "Run-I-WZ" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p pbar e+ nu","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p pbar e- nu","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=particlegroup('epm','e+','e-')
process+=particlegroup('epmnu','e+','e-','nu_e','nu_ebar')
process+=addProcess(thefactory,"p pbar epm epmnu","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "Run-II-W" in parameterName or "Run-I-W" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p pbar e+ nu","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p pbar e- nu","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=particlegroup('epm','e+','e-')
process+=addProcess(thefactory,"p pbar epm nu","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "Run-II-Z-LowMass-mu" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("25","70")
elif "Run-II-Z-HighMass-mu" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("150","600")
elif "Run-II-Z-mu" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
# Star
elif(collider=="Star" ) :
process = StringBuilder("set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n")
process+= "set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n"
process+= "set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/p+\n"
process+= collider_lumi(200.0)
process+= "set /Herwig/Cuts/Cuts:X2Min 0.01\n"
if(simulation=="") :
if "UE" in parameterName :
if "Dipole" in parameters["shower"]:
process+="read snippets/MB-DipoleShower.in\n"
else:
process+="read snippets/MB.in\n"
process+="read snippets/Diffraction.in\n"
else :
process+=insert_ME("MEQCD2to2")
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "Jets-1" in parameterName : process+=jet_kt_cut(2.)
elif "Jets-2" in parameterName : process+=jet_kt_cut(5.)
elif "Jets-3" in parameterName : process+=jet_kt_cut(20.)
elif "Jets-4" in parameterName : process+=jet_kt_cut(25.)
else :
logging.error("Star not supported for %s " % simulation)
sys.exit(1)
# ISR and SppS
elif(collider=="ISR" or collider =="SppS" ) :
process = StringBuilder("set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n")
process+="set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n"
if(collider=="SppS") :
process = StringBuilder("set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/pbar-\n")
if "30" in parameterName : process+=collider_lumi( 30.4)
elif "44" in parameterName : process+=collider_lumi( 44.4)
elif "53" in parameterName : process+=collider_lumi( 53.0)
elif "62" in parameterName : process+=collider_lumi( 62.2)
elif "63" in parameterName : process+=collider_lumi( 63.0)
elif "200" in parameterName : process+=collider_lumi(200.0)
elif "500" in parameterName : process+=collider_lumi(500.0)
elif "546" in parameterName : process+=collider_lumi(546.0)
elif "900" in parameterName : process+=collider_lumi(900.0)
if(simulation=="") :
if "Dipole" in parameters["shower"]:
process+="read snippets/MB-DipoleShower.in\n"
else:
process+="read snippets/MB.in\n"
process+="read snippets/Diffraction.in\n"
else :
logging.error(" SppS and ISR not supported for %s " % simulation)
sys.exit(1)
# LHC
elif(collider=="LHC") :
if parameterName.startswith("7-") : process = StringBuilder(collider_lumi(7000.0))
elif parameterName.startswith("8-") : process = StringBuilder(collider_lumi(8000.0))
elif parameterName.startswith("13-") : process = StringBuilder(collider_lumi(13000.0))
elif parameterName.startswith("900") : process = StringBuilder(collider_lumi(900.0))
elif parameterName.startswith("2360") : process = StringBuilder(collider_lumi(2360.0))
elif parameterName.startswith("2760") : process = StringBuilder(collider_lumi(2760.0))
else : process = StringBuilder(collider_lumi(7000.0))
if(simulation=="") :
if "8-VBF" in parameterName :
process+=insert_ME("MEPP2HiggsVBF")
elif "VBF" in parameterName :
process+=selectDecayMode("h0",["h0->tau-,tau+;"])
process+=addBRReweighter()
process+="set /Herwig/Particles/tau-:Stable Stable\n"
process+=insert_ME("MEPP2HiggsVBF")
elif "ggHJet" in parameterName :
process+=selectDecayMode("h0",["h0->tau-,tau+;"])
process+=addBRReweighter()
process+="set /Herwig/Particles/tau-:Stable Stable\n"
process+=insert_ME("MEHiggsJet")
process+=jet_kt_cut(20.)
elif "8-ggH" in parameterName :
process+=insert_ME("MEHiggs")
process+=insert_ME("MEHiggsJet","qqbar")
process+=jet_kt_cut(0.0)
elif "ggH" in parameterName :
process+=selectDecayMode("h0",["h0->tau-,tau+;"])
process+=addBRReweighter()
process+="set /Herwig/Particles/tau-:Stable Stable\n"
process+=insert_ME("MEHiggs")
process+=insert_ME("MEHiggsJet","qqbar")
process+=jet_kt_cut(0.0)
elif "PromptPhoton" in parameterName :
process+=insert_ME("MEGammaJet")
if "PromptPhoton-1" in parameterName :
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
elif "PromptPhoton-2" in parameterName :
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 25.\n"
elif "PromptPhoton-3" in parameterName :
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 80.\n"
elif "PromptPhoton-4" in parameterName :
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 150.\n"
elif "DiPhoton-GammaGamma" in parameterName :
process+=insert_ME("MEGammaGamma")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
parameterName=parameterName.replace("-GammaGamma","")
elif "DiPhoton-GammaJet" in parameterName :
process+=insert_ME("MEGammaJet")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
parameterName=parameterName.replace("-GammaJet","")
elif "8-WH" in parameterName :
process+=insert_ME("MEPP2WH")
process+=jet_kt_cut(0.0)
elif "8-ZH" in parameterName :
process+=insert_ME("MEPP2ZH")
process+=jet_kt_cut(0.0)
elif "WH" in parameterName :
process+=selectDecayMode("h0",["h0->b,bbar;"])
process+=selectDecayMode("W+",["W+->nu_e,e+;",
"W+->nu_mu,mu+;"])
process+=addBRReweighter()
process+=insert_ME("MEPP2WH")
process+=jet_kt_cut(0.0)
elif "ZH" in parameterName :
process+=selectDecayMode("h0",["h0->b,bbar;"])
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;"])
process+=addBRReweighter()
process+=insert_ME("MEPP2ZH")
process+=jet_kt_cut(0.0)
elif "UE" in parameterName :
if "Dipole" in parameters["shower"]:
process+="read snippets/MB-DipoleShower.in\n"
else:
process+="set /Herwig/Shower/ShowerHandler:IntrinsicPtGaussian 2.2*GeV\n"
process+="read snippets/MB.in\n"
process+="read snippets/Diffraction.in\n"
if "Long" in parameterName :
process += "set /Herwig/Decays/DecayHandler:MaxLifeTime 100*mm\n"
elif "8-DiJets" in parameterName or "7-DiJets" in parameterName :
process+=insert_ME("MEQCD2to2")
process+="set MEQCD2to2:MaximumFlavour 5\n"
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "-A" in parameterName :
process+=jet_kt_cut(45.)
process+="set /Herwig/Cuts/JetKtCut:MinEta -3.\n"
process+="set /Herwig/Cuts/JetKtCut:MaxEta 3.\n"
elif "-B" in parameterName :
process+=jet_kt_cut(20.)
process+="set /Herwig/Cuts/JetKtCut:MinEta -2.7\n"
process+="set /Herwig/Cuts/JetKtCut:MaxEta 2.7\n"
elif "-C" in parameterName :
process+=jet_kt_cut(20.)
process+="set /Herwig/Cuts/JetKtCut:MinEta -4.8\n"
process+="set /Herwig/Cuts/JetKtCut:MaxEta 4.8\n"
if "DiJets-1" in parameterName : process+=mhatmin_cut(90.)
elif "DiJets-2" in parameterName : process+=mhatmin_cut(200.)
elif "DiJets-3" in parameterName : process+=mhatmin_cut(450.)
elif "DiJets-4" in parameterName : process+=mhatmin_cut(750.)
elif "DiJets-5" in parameterName : process+=mhatmin_cut(950.)
elif "DiJets-6" in parameterName : process+=mhatmin_cut(1550.)
elif "DiJets-7" in parameterName : process+=mhatmin_cut(2150.)
elif "DiJets-8" in parameterName : process+=mhatmin_cut(2750.)
elif( "7-Jets" in parameterName
or "8-Jets" in parameterName
or "13-Jets" in parameterName
) :
process+=insert_ME("MEQCD2to2")
process+="set MEQCD2to2:MaximumFlavour 5\n"
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "Jets-10" in parameterName : process+=jet_kt_cut(1800.)
elif "Jets-0" in parameterName : process+=jet_kt_cut(5.)
elif "Jets-1" in parameterName : process+=jet_kt_cut(10.)
elif "Jets-2" in parameterName : process+=jet_kt_cut(20.)
elif "Jets-3" in parameterName : process+=jet_kt_cut(40.)
elif "Jets-4" in parameterName : process+=jet_kt_cut(70.)
elif "Jets-5" in parameterName : process+=jet_kt_cut(150.)
elif "Jets-6" in parameterName : process+=jet_kt_cut(200.)
elif "Jets-7" in parameterName : process+=jet_kt_cut(300.)
elif "Jets-8" in parameterName : process+=jet_kt_cut(500.)
elif "Jets-9" in parameterName : process+=jet_kt_cut(800.)
elif("7-Charm" in parameterName or "7-Bottom" in parameterName) :
if "7-Bottom" in parameterName :
process+="cp MEHeavyQuark MEBottom\n"
process+="set MEBottom:QuarkType Bottom\n"
process+=insert_ME("MEBottom")
else :
process+="cp MEHeavyQuark MECharm\n"
process+="set MECharm:QuarkType Charm\n"
process+=insert_ME("MECharm")
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "-0" in parameterName :
if "7-Bottom" in parameterName :
process+="set MEBottom:Process Pair\n"
process+=jet_kt_cut(0.)
elif "-1" in parameterName : process+=jet_kt_cut(5.)
elif "-2" in parameterName : process+=jet_kt_cut(20.)
elif "-3" in parameterName : process+=jet_kt_cut(50.)
elif "-4" in parameterName : process+=jet_kt_cut(80.)
elif "-5" in parameterName : process+=jet_kt_cut(110.)
elif "-6" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(90.)
elif "-7" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(340.)
elif "-8" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(500.)
elif "Top-L" in parameterName :
process+="set MEHeavyQuark:QuarkType Top\n"
process+=insert_ME("MEHeavyQuark")
process+=selectDecayMode("t",["t->nu_e,e+,b;",
"t->nu_mu,mu+,b;"])
process+=addBRReweighter()
elif "Top-SL" in parameterName :
process+="set MEHeavyQuark:QuarkType Top\n"
process+=insert_ME("MEHeavyQuark")
process+="set /Herwig/Particles/t:Synchronized Not_synchronized\n"
process+="set /Herwig/Particles/tbar:Synchronized Not_synchronized\n"
process+=selectDecayMode("t",["t->nu_e,e+,b;","t->nu_mu,mu+,b;"])
process+=selectDecayMode("tbar",["tbar->b,bbar,cbar;",
"tbar->bbar,cbar,d;",
"tbar->bbar,cbar,s;",
"tbar->bbar,s,ubar;",
"tbar->bbar,ubar,d;"])
process+=addBRReweighter()
elif "Top-All" in parameterName :
process+="set MEHeavyQuark:QuarkType Top\n"
process+=insert_ME("MEHeavyQuark")
elif "WZ" in parameterName :
process+=insert_ME("MEPP2VV","WZ")
process+=selectDecayMode("W+",["W+->nu_e,e+;",
"W+->nu_mu,mu+;"])
process+=selectDecayMode("W-",["W-->nu_ebar,e-;",
"W-->nu_mubar,mu-;"])
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;"])
process+=addBRReweighter()
elif "WW-emu" in parameterName :
process+=insert_ME("MEPP2VV","WW")
process+="set /Herwig/Particles/W+:Synchronized 0\n"
process+="set /Herwig/Particles/W-:Synchronized 0\n"
process+=selectDecayMode("W+",["W+->nu_e,e+;"])
process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"])
process+=addBRReweighter()
elif "WW-ll" in parameterName :
process+=insert_ME("MEPP2VV","WW")
process+=selectDecayMode("W+",["W+->nu_e,e+;","W+->nu_mu,mu+;","W+->nu_tau,tau+;"])
process+=addBRReweighter()
elif "ZZ-ll" in parameterName :
process+=insert_ME("MEPP2VV","ZZ")
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;",
"Z0->tau-,tau+;"])
process+=addBRReweighter()
elif "ZZ-lv" in parameterName :
process+=insert_ME("MEPP2VV","ZZ")
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;",
"Z0->tau-,tau+;",
"Z0->nu_e,nu_ebar;",
"Z0->nu_mu,nu_mubar;",
"Z0->nu_tau,nu_taubar;"])
process+=addBRReweighter()
elif "W-Z-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
process+=insert_ME("MEqq2W2ff","Electron")
elif "W-Z-mu" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Muon")
process+=insert_ME("MEqq2W2ff","Muon")
elif "W-e" in parameterName :
process+=insert_ME("MEqq2W2ff","Electron")
elif "W-mu" in parameterName :
process+=insert_ME("MEqq2W2ff","Muon")
elif "Z-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
elif "Z-mu" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Muon")
elif "Z-LowMass-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
process+=mhat_minm_maxm(20,20,70)
elif "Z-MedMass-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
process+=mhat_minm_maxm(40,40,130)
elif "Z-LowMass-mu" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Muon")
process+=mhat_minm_maxm(10,10,70)
elif "Z-Mass1" in parameterName :
process+=mhat_minm_maxm(10,10,35)
if "-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
else :
process+=insert_ME("MEqq2gZ2ff","Muon")
elif "Z-Mass2" in parameterName :
process+=mhat_minm_maxm(25,25,70)
if "-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
else :
process+=insert_ME("MEqq2gZ2ff","Muon")
elif "Z-Mass3" in parameterName :
process+=mhat_minm_maxm(60,60,120)
if "-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
else :
process+=insert_ME("MEqq2gZ2ff","Muon")
elif "Z-Mass4" in parameterName :
process+=mhat_minm_maxm(110,110,8000)
if "-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
else :
process+=insert_ME("MEqq2gZ2ff","Muon")
elif "Z-HighMass1" in parameterName :
process+=mhat_minm_maxm(116,116,400)
if "-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
else :
process+=insert_ME("MEqq2gZ2ff","Muon")
elif "Z-HighMass2" in parameterName :
process+=mhat_minm_maxm(400,400,7000)
if "-e" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Electron")
else :
process+=insert_ME("MEqq2gZ2ff","Muon")
elif "W-Jet" in parameterName :
process+=insert_ME("MEWJet","Electron","WDecay")
if "W-Jet-1-e" in parameterName :
process+="set /Herwig/Cuts/WBosonKtCut:MinKT 100.0*GeV\n"
parameterName=parameterName.replace("W-Jet-1-e","W-Jet-e")
elif "W-Jet-2-e" in parameterName :
process+="set /Herwig/Cuts/WBosonKtCut:MinKT 190.0*GeV\n"
parameterName=parameterName.replace("W-Jet-2-e","W-Jet-e")
elif "W-Jet-3-e" in parameterName :
process+="set /Herwig/Cuts/WBosonKtCut:MinKT 270.0*GeV\n"
parameterName=parameterName.replace("W-Jet-3-e","W-Jet-e")
elif "Z-Jet" in parameterName :
if "-e" in parameterName :
process+=insert_ME("MEZJet","Electron","ZDecay")
if "Z-Jet-0-e" in parameterName :
process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 35.0*GeV\n"
parameterName=parameterName.replace("Z-Jet-0-e","Z-Jet-e")
elif "Z-Jet-1-e" in parameterName :
process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 100.0*GeV\n"
parameterName=parameterName.replace("Z-Jet-1-e","Z-Jet-e")
elif "Z-Jet-2-e" in parameterName :
process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 190.0*GeV\n"
parameterName=parameterName.replace("Z-Jet-2-e","Z-Jet-e")
elif "Z-Jet-3-e" in parameterName :
process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 270.0*GeV\n"
parameterName=parameterName.replace("Z-Jet-3-e","Z-Jet-e")
else :
process+=insert_ME("MEZJet","Muon","ZDecay")
process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 35.0*GeV\n"
parameterName=parameterName.replace("Z-Jet-0-mu","Z-Jet-mu")
elif "WGamma" in parameterName :
process+=insert_ME("MEPP2VGamma","1")
process+="set MEPP2VGamma:MassOption 1"
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 10.\n"
if "-e" in parameterName :
process+=selectDecayMode("W+",["W+->nu_e,e+;"])
process+=addBRReweighter()
else :
process+=selectDecayMode("W+",["W+->nu_mu,mu+;"])
process+=addBRReweighter()
elif "ZGamma" in parameterName :
process+=insert_ME("MEPP2VGamma","2")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 10.\n"
if "-e" in parameterName :
process+=selectDecayMode("Z0",["Z0->e-,e+;"])
process+=addBRReweighter()
else :
process+=selectDecayMode("Z0",["Z0->mu-,mu+;"])
process+=addBRReweighter()
else :
logging.error(" Process %s not supported for internal matrix elements" % name)
sys.exit(1)
elif(simulation=="Powheg") :
if "8-VBF" in parameterName :
process+=insert_ME("PowhegMEPP2HiggsVBF")
elif "VBF" in parameterName :
process+=selectDecayMode("h0",["h0->tau-,tau+;"])
process+=addBRReweighter()
process+="set /Herwig/Particles/tau-:Stable Stable\n"
process+=insert_ME("PowhegMEPP2HiggsVBF")
elif "ggHJet" in parameterName :
logging.error(" Process %s not supported for POWHEG matrix elements" % name)
sys.exit(1)
elif "8-ggH" in parameterName :
process+=insert_ME("PowhegMEHiggs")
elif "ggH" in parameterName :
process+=selectDecayMode("h0",["h0->tau-,tau+;"])
process+=addBRReweighter()
process+="set /Herwig/Particles/tau-:Stable Stable\n"
process+=insert_ME("PowhegMEHiggs")
elif "8-WH" in parameterName :
process+=insert_ME("PowhegMEPP2WH")
process+=jet_kt_cut(0.0)
elif "8-ZH" in parameterName :
process+=insert_ME("PowhegMEPP2ZH")
process+=jet_kt_cut(0.0)
elif "WH" in parameterName :
process+=selectDecayMode("h0",["h0->b,bbar;"])
process+=selectDecayMode("W+",["W+->nu_e,e+;",
"W+->nu_mu,mu+;"])
process+=addBRReweighter()
process+=insert_ME("PowhegMEPP2WH")
process+=jet_kt_cut(0.0)
elif "ZH" in parameterName :
process+=selectDecayMode("h0",["h0->b,bbar;"])
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;"])
process+=addBRReweighter()
process+=insert_ME("PowhegMEPP2ZH")
process+=jet_kt_cut(0.0)
elif "UE" in parameterName :
logging.error(" Process %s not supported for powheg matrix elements" % name)
sys.exit(1)
elif "WZ" in parameterName :
process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n"
process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n"
process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n";
process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n";
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n"
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n"
process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n"
process+=insert_ME("PowhegMEPP2VV","WZ")
process+=selectDecayMode("W+",["W+->nu_e,e+;",
"W+->nu_mu,mu+;"])
process+=selectDecayMode("W-",["W-->nu_ebar,e-;",
"W-->nu_mubar,mu-;"])
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;"])
process+=addBRReweighter()
elif "WW-emu" in parameterName :
process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n"
process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n"
process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n";
process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n";
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n"
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n"
process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n"
process+=insert_ME("PowhegMEPP2VV","WW")
process+="set /Herwig/Particles/W+:Synchronized 0\n"
process+="set /Herwig/Particles/W-:Synchronized 0\n"
process+=selectDecayMode("W+",["W+->nu_e,e+;"])
process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"])
process+=addBRReweighter()
elif "WW-ll" in parameterName :
process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n"
process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n"
process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n";
process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n";
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n"
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n"
process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n"
process+=insert_ME("PowhegMEPP2VV","WW")
process+=selectDecayMode("W+",["W+->nu_e,e+;",
"W+->nu_mu,mu+;",
"W+->nu_tau,tau+;"])
process+=addBRReweighter()
elif "ZZ-ll" in parameterName :
process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n"
process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n"
process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n";
process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n";
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n"
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n"
process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n"
process+=insert_ME("PowhegMEPP2VV","ZZ")
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;",
"Z0->tau-,tau+;"])
process+=addBRReweighter()
elif "ZZ-lv" in parameterName :
process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n"
process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n"
process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n";
process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n";
process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n";
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n"
process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n"
process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n"
process+=insert_ME("PowhegMEPP2VV","ZZ")
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;",
"Z0->tau-,tau+;",
"Z0->nu_e,nu_ebar;",
"Z0->nu_mu,nu_mubar;",
"Z0->nu_tau,nu_taubar;"])
process+=addBRReweighter()
elif "W-Z-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
process+=insert_ME("PowhegMEqq2W2ff","Electron")
elif "W-Z-mu" in parameterName :
process+=insert_ME("MEqq2gZ2ff","Muon")
process+=insert_ME("MEqq2W2ff","Muon")
elif "W-e" in parameterName :
process+=insert_ME("PowhegMEqq2W2ff","Electron")
elif "W-mu" in parameterName :
process+=insert_ME("PowhegMEqq2W2ff","Muon")
elif "Z-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
elif "Z-mu" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
elif "Z-LowMass-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
process+=mhat_minm_maxm(20,20,70)
elif "Z-MedMass-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
process+=mhat_minm_maxm(40,40,130)
elif "Z-LowMass-mu" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
process+=mhat_minm_maxm(10,10,70)
elif "Z-Mass1" in parameterName :
process+=mhat_minm_maxm(10,10,35)
if "-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
else :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
elif "Z-Mass2" in parameterName :
process+=mhat_minm_maxm(25,25,70)
if "-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
else :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
elif "Z-Mass3" in parameterName :
process+=mhat_minm_maxm(60,60,120)
if "-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
else :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
elif "Z-Mass4" in parameterName :
process+=mhat_minm_maxm(110,110,8000)
if "-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
else :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
elif "Z-HighMass1" in parameterName :
process+=mhat_minm_maxm(116,116,400)
if "-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
else :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
elif "Z-HighMass2" in parameterName :
process+=mhat_minm_maxm(400,400,7000)
if "-e" in parameterName :
process+=insert_ME("PowhegMEqq2gZ2ff","Electron")
else :
process+=insert_ME("PowhegMEqq2gZ2ff","Muon")
elif "DiPhoton-GammaGamma" in parameterName :
process+=insert_ME("MEGammaGammaPowheg","GammaGamma")
process+=insert_ME("MEGammaGamma","gg")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
process+=jet_kt_cut(5.)
parameterName=parameterName.replace("-GammaGamma","")
elif "DiPhoton-GammaJet" in parameterName :
process+=insert_ME("MEGammaGammaPowheg","VJet")
process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n"
process+=jet_kt_cut(5.)
parameterName=parameterName.replace("-GammaJet","")
else :
logging.error(" Process %s not supported for internal POWHEG matrix elements" % name)
sys.exit(1)
elif( simulation=="Matchbox" or simulation=="Merging" ) :
if "8-VBF" in parameterName :
parameters["nlo"] = "read Matchbox/VBFNLO.in\n"
if(simulation=="Merging"):
process+="cd /Herwig/Merging/\n"
process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/Z0\n"
process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W+\n"
process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W-\n"
process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/gamma\n"
process+="do "+thefactory+":DiagramGenerator:TimeLikeRange 0 0\n"
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",1,1)
process+=setHardProcessWidthToZero(["h0"])
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n"
if "GammaGamma" in parameterName :
process+=selectDecayMode("h0",["h0->gamma,gamma;"])
process+=addBRReweighter()
elif "WW" in parameterName :
process+=selectDecayMode("h0",["h0->W+,W-;"])
process+=addBRReweighter()
elif "VBF" in parameterName :
process+=selectDecayMode("h0",["h0->tau-,tau+;"])
process+=addBRReweighter()
process+="set /Herwig/Particles/tau-:Stable Stable\n"
parameters["nlo"] = "read Matchbox/VBFNLO.in\n"
if(simulation=="Merging"):
process+="cd /Herwig/Merging/\n"
process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/Z0\n"
process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W+\n"
process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W-\n"
process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/gamma\n"
process+="do "+thefactory+":DiagramGenerator:TimeLikeRange 0 0\n"
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",1,1)
process+=setHardProcessWidthToZero(["h0"])
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n"
elif "ggHJet" in parameterName :
if(simulation=="Merging"):
logging.warning("ggHJet not explicitly tested for %s " % simulation)
sys.exit(0)
parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n"
process+=selectDecayMode("h0",["h0->tau-,tau+;"])
process+=addBRReweighter()
process+="set /Herwig/Particles/tau-:Stable Stable\n"
process+=setHardProcessWidthToZero(["h0"])
process+=addProcess(thefactory,"p p h0 j","3","1","FixedScale",0,0)
process+=addFirstJet("20")
process+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/FixedScale\n"
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n"
elif "8-ggH" in parameterName :
parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n"
if(simulation=="Merging"):
process+= "cd /Herwig/MatrixElements/Matchbox/Amplitudes\nset OpenLoops:HiggsEff On\nset MadGraph:Model heft\n"
process+="cd /Herwig/Merging/\n"
process+=setHardProcessWidthToZero(["h0"])
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p h0","2","1","FixedScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p h0","2","1","FixedScale",2,2)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n"
if "GammaGamma" in parameterName :
process+=selectDecayMode("h0",["h0->gamma,gamma;"])
process+=addBRReweighter()
elif "WW" in parameterName :
process+=selectDecayMode("h0",["h0->W+,W-;"])
process+=addBRReweighter()
elif "ggH" in parameterName :
parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n"
if(simulation=="Merging"):
process+= "cd /Herwig/MatrixElements/Matchbox/Amplitudes\nset OpenLoops:HiggsEff On\nset MadGraph:Model heft\n"
process+="cd /Herwig/Merging/\n"
process+=selectDecayMode("h0",["h0->tau-,tau+;"])
process+=addBRReweighter()
process+="set /Herwig/Particles/tau-:Stable Stable\n"
process+=setHardProcessWidthToZero(["h0"])
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p h0","2","1","FixedScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p h0","2","1","FixedScale",2,2)
process+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/FixedScale\n"
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n"
elif "8-WH" in parameterName :
if(simulation=="Merging"):
logging.warning("8-WH not explicitly tested for %s " % simulation)
sys.exit(0)
process+=setHardProcessWidthToZero(["h0","W+","W-"])
process+=addProcess(thefactory,"p p W+ h0","0","2","FixedScale",0,0)
process+=addProcess(thefactory,"p p W- h0","0","2","FixedScale",0,0)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n"
if "GammaGamma" in parameterName :
process+=selectDecayMode("h0",["h0->gamma,gamma;"])
process+=addBRReweighter()
elif "WW" in parameterName :
process+=selectDecayMode("h0",["h0->W+,W-;"])
process+=addBRReweighter()
elif "8-ZH" in parameterName :
if(simulation=="Merging"):
logging.warning("8-ZH not explicitly tested for %s " % simulation)
sys.exit(0)
process+=setHardProcessWidthToZero(["h0","Z0"])
process+=addProcess(thefactory,"p p Z0 h0","0","2","FixedScale",0,0)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n"
if "GammaGamma" in parameterName :
process+=selectDecayMode("h0",["h0->gamma,gamma;"])
process+=addBRReweighter()
elif "WW" in parameterName :
process+=selectDecayMode("h0",["h0->W+,W-;"])
process+=addBRReweighter()
elif "WH" in parameterName :
if(simulation=="Merging"):
logging.warning("WH not explicitly tested for %s " % simulation)
sys.exit(0)
process+=selectDecayMode("h0",["h0->b,bbar;"])
process+=addBRReweighter()
process+=setHardProcessWidthToZero(["h0"])
process+=addProcess(thefactory,"p p e+ nu h0","0","3","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p e- nu h0","0","3","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p mu+ nu h0","0","3","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p mu- nu h0","0","3","LeptonPairMassScale",0,0)
process+=addLeptonPairCut("60","120")
elif "ZH" in parameterName :
if(simulation=="Merging"):
logging.warning("ZH not explicitly tested for %s " % simulation)
sys.exit(0)
process+=selectDecayMode("h0",["h0->b,bbar;"])
process+=addBRReweighter()
process+=setHardProcessWidthToZero(["h0"])
process+=addProcess(thefactory,"p p e+ e- h0","0","3","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p mu+ mu- h0","0","3","LeptonPairMassScale",0,0)
process+=addLeptonPairCut("60","120")
elif "UE" in parameterName :
logging.error(" Process %s not supported for Matchbox matrix elements" % name)
sys.exit(1)
elif "8-DiJets" in parameterName or "7-DiJets" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",1,1)
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "-A" in parameterName :
process+=addFirstJet("45")
process+=addSecondJet("25")
process+="set /Herwig/Cuts/FirstJet:YRange -3. 3.\n"
process+="set /Herwig/Cuts/SecondJet:YRange -3. 3.\n"
elif "-B" in parameterName :
process+=addFirstJet("20")
process+=addSecondJet("15")
process+="set /Herwig/Cuts/FirstJet:YRange -2.7 2.7\n"
process+="set /Herwig/Cuts/SecondJet:YRange -2.7 2.7\n"
elif "-C" in parameterName :
process+=addFirstJet("20")
process+=addSecondJet("15")
process+="set /Herwig/Cuts/FirstJet:YRange -4.8 4.8\n"
process+="set /Herwig/Cuts/SecondJet:YRange -4.8 4.8\n"
else :
logging.error("Exit 00001")
sys.exit(1)
if "DiJets-1" in parameterName : process+=addJetPairCut("90")
elif "DiJets-2" in parameterName : process+=addJetPairCut("200")
elif "DiJets-3" in parameterName : process+=addJetPairCut("450")
elif "DiJets-4" in parameterName : process+=addJetPairCut("750")
elif "DiJets-5" in parameterName : process+=addJetPairCut("950")
elif "DiJets-6" in parameterName : process+=addJetPairCut("1550")
elif "DiJets-7" in parameterName : process+=addJetPairCut("2150")
elif "DiJets-8" in parameterName : process+=addJetPairCut("2750")
else :
logging.error("Exit 00002")
sys.exit(1)
elif( "7-Jets" in parameterName
or "8-Jets" in parameterName
or "13-Jets" in parameterName
) :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",1,1)
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "Jets-10" in parameterName : process+=addFirstJet("1800")
elif "Jets-0" in parameterName : process+=addFirstJet("5")
elif "Jets-1" in parameterName : process+=addFirstJet("10")
elif "Jets-2" in parameterName : process+=addFirstJet("20")
elif "Jets-3" in parameterName : process+=addFirstJet("40")
elif "Jets-4" in parameterName : process+=addFirstJet("70")
elif "Jets-5" in parameterName : process+=addFirstJet("150")
elif "Jets-6" in parameterName : process+=addFirstJet("200")
elif "Jets-7" in parameterName : process+=addFirstJet("300")
elif "Jets-8" in parameterName : process+=addFirstJet("500")
elif "Jets-9" in parameterName : process+=addFirstJet("800")
else :
logging.error("Exit 00003")
sys.exit(1)
elif( "7-Charm" in parameterName or "7-Bottom" in parameterName) :
parameters["bscheme"]=fourFlavour
process+="set /Herwig/Particles/b:HardProcessMass 4.2*GeV\n"
process+="set /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n"
if "7-Bottom" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p b bbar","2","0","MaxJetPtScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p b bbar","2","0","MaxJetPtScale",1,0)
else:
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p c cbar","2","0","MaxJetPtScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p c cbar","2","0","MaxJetPtScale",1,0)
process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n"
if "-0" in parameterName : process+=addFirstJet("0")
elif "-1" in parameterName : process+=addFirstJet("5")
elif "-2" in parameterName : process+=addFirstJet("20")
elif "-3" in parameterName : process+=addFirstJet("50")
elif "-4" in parameterName : process+=addFirstJet("80")
elif "-5" in parameterName : process+=addFirstJet("110")
elif "-6" in parameterName :
process+=addFirstJet("30")
process+=addSecondJet("25")
process+=addJetPairCut("90")
elif "-7" in parameterName :
process+=addFirstJet("30")
process+=addSecondJet("25")
process+=addJetPairCut("340")
elif "-8" in parameterName :
process+=addFirstJet("30")
process+=addSecondJet("25")
process+=addJetPairCut("500")
else :
logging.error("Exit 00004")
sys.exit(1)
elif "Top-L" in parameterName :
process+=setHardProcessWidthToZero(["t","tbar"])
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2)
process+=selectDecayMode("t",["t->nu_e,e+,b;",
"t->nu_mu,mu+,b;"])
process+=addBRReweighter()
elif "Top-SL" in parameterName :
process+=setHardProcessWidthToZero(["t","tbar"])
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2)
process+="set /Herwig/Particles/t:Synchronized Not_synchronized\n"
process+="set /Herwig/Particles/tbar:Synchronized Not_synchronized\n"
process+=selectDecayMode("t",["t->nu_e,e+,b;",
"t->nu_mu,mu+,b;"])
process+=selectDecayMode("tbar",["tbar->b,bbar,cbar;",
"tbar->bbar,cbar,d;",
"tbar->bbar,cbar,s;",
"tbar->bbar,s,ubar;",
"tbar->bbar,ubar,d;"])
process+=addBRReweighter()
elif "Top-All" in parameterName :
process+=setHardProcessWidthToZero(["t","tbar"])
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2)
elif "WZ" in parameterName :
if(simulation=="Merging"):
logging.warning("WZ not explicitly tested for %s " % simulation)
sys.exit(0)
process+=setHardProcessWidthToZero(["W+","W-","Z0"])
process+=addProcess(thefactory,"p p W+ Z0","0","2","FixedScale",0,0)
process+=addProcess(thefactory,"p p W- Z0","0","2","FixedScale",0,0)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 171.6*GeV\n\n"
process+=selectDecayMode("W+",["W+->nu_e,e+;",
"W+->nu_mu,mu+;"])
process+=selectDecayMode("W-",["W-->nu_ebar,e-;",
"W-->nu_mubar,mu-;"])
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;"])
process+=addBRReweighter()
process+=addLeptonPairCut("60","120")
elif "WW-emu" in parameterName :
if(simulation=="Merging"):
logging.warning("WW-emu not explicitly tested for %s " % simulation)
sys.exit(0)
process+=setHardProcessWidthToZero(["W+","W-","Z0"])
process+=addProcess(thefactory,"p p W+ W-","0","2","FixedScale",0,0)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 160.8*GeV\n"
process+="set /Herwig/Particles/W+:Synchronized 0\n"
process+="set /Herwig/Particles/W-:Synchronized 0\n"
process+=selectDecayMode("W+",["W+->nu_e,e+;"])
process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"])
process+=addBRReweighter()
parameters["bscheme"] = "read Matchbox/FourFlavourScheme.in\n"
process+=addLeptonPairCut("60","120")
elif "WW-ll" in parameterName :
if(simulation=="Merging"):
logging.warning("WW-ll not explicitly tested for %s " % simulation)
sys.exit(0)
process+=setHardProcessWidthToZero(["W+","W-","Z0"])
process+=addProcess(thefactory,"p p W+ W-","0","2","FixedScale",0,0)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 160.8*GeV\n"
process+=selectDecayMode("W+",["W+->nu_e,e+;",
"W+->nu_mu,mu+;",
"W+->nu_tau,tau+;"])
process+=addBRReweighter()
process+=addLeptonPairCut("60","120")
parameters["bscheme"] = "read Matchbox/FourFlavourScheme.in\n"
elif "ZZ-ll" in parameterName :
if(simulation=="Merging"):
logging.warning("ZZ-ll not explicitly tested for %s " % simulation)
sys.exit(0)
process+=setHardProcessWidthToZero(["W+","W-","Z0"])
process+=addProcess(thefactory,"p p Z0 Z0","0","2","FixedScale",0,0)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 182.2*GeV\n"
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;",
"Z0->tau-,tau+;"])
process+=addBRReweighter()
process+=addLeptonPairCut("60","120")
elif "ZZ-lv" in parameterName :
if(simulation=="Merging"):
logging.warning("ZZ-lv not explicitly tested for %s " % simulation)
sys.exit(0)
process+=setHardProcessWidthToZero(["W+","W-","Z0"])
process+=addProcess(thefactory,"p p Z0 Z0","0","2","FixedScale",0,0)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 182.2*GeV\n"
process+=selectDecayMode("Z0",["Z0->e-,e+;",
"Z0->mu-,mu+;",
"Z0->tau-,tau+;",
"Z0->nu_e,nu_ebar;",
"Z0->nu_mu,nu_mubar;",
"Z0->nu_tau,nu_taubar;"])
process+=addBRReweighter()
process+=addLeptonPairCut("60","120")
elif "W-Z-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p e+ nu","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p e- nu","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=particlegroup('epm','e+','e-')
process+=particlegroup('epmnu','e+','e-','nu_e','nu_ebar')
process+=addProcess(thefactory,"p p epm epmnu","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "W-Z-mu" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p mu+ nu","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p mu- nu","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=particlegroup('mupm','mu+','mu-')
process+=particlegroup('mupmnu','mu+','mu-','nu_mu','nu_mubar')
process+=addProcess(thefactory,"p p mupm mupmnu","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "W-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ nu","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p e- nu","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=particlegroup('epm','e+','e-')
process+=addProcess(thefactory,"p p epm nu","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "W-mu" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ nu","0","2","LeptonPairMassScale",0,0)
process+=addProcess(thefactory,"p p mu- nu","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=particlegroup('mupm','mu+','mu-')
process+=addProcess(thefactory,"p p mupm nu","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "Z-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "Z-mu" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("60","120")
elif "Z-jj" in parameterName :
if(simulation=="Merging"):
logging.warning("Z-jj not explicitly tested for %s " % simulation)
sys.exit(0)
process+=addProcess(thefactory,"p p e+ e- j j","2","2","LeptonPairMassScale",0,0)
process+=addFirstJet("40")
process+=addSecondJet("30")
process+=addLeptonPairCut("60","120")
elif "Z-LowMass-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("20","70")
elif "Z-MedMass-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("40","130")
elif "Z-LowMass-mu" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2)
process+=addLeptonPairCut("10","70")
elif "Z-Mass1" in parameterName :
process+=addLeptonPairCut("10","35")
if "-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
else :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2)
elif "Z-Mass2" in parameterName :
process+=addLeptonPairCut("25","70")
if "-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
else :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2)
elif "Z-Mass3" in parameterName :
process+=addLeptonPairCut("60","120")
if "-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
else :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2)
elif "Z-Mass4" in parameterName :
process+=addLeptonPairCut("115","8000")
if "-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
else :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2)
elif "Z-HighMass1" in parameterName :
process+=addLeptonPairCut("116","400")
if "-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
else :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2)
elif "Z-HighMass2" in parameterName :
process+=addLeptonPairCut("400","7000")
if "-e" in parameterName :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2)
else :
if(simulation=="Matchbox"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0)
elif(simulation=="Merging"):
process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2)
elif "W-Jet" in parameterName :
if(simulation=="Merging"):
logging.warning("W-Jet not explicitly tested for %s " % simulation)
sys.exit(0)
process+=addProcess(thefactory,"p p e+ nu j","1","2","HTScale",0,0)
process+=addProcess(thefactory,"p p e- nu j","1","2","HTScale",0,0)
process+=addLeptonPairCut("60","120")
if "W-Jet-1-e" in parameterName :
process+=addFirstJet("100")
parameterName=parameterName.replace("W-Jet-1-e","W-Jet-e")
elif "W-Jet-2-e" in parameterName :
process+=addFirstJet("190")
parameterName=parameterName.replace("W-Jet-2-e","W-Jet-e")
elif "W-Jet-3-e" in parameterName :
process+=addFirstJet("270")
parameterName=parameterName.replace("W-Jet-3-e","W-Jet-e")
else :
logging.error("Exit 00005")
sys.exit(1)
elif "Z-Jet" in parameterName :
if(simulation=="Merging"):
logging.warning("Z-Jet not explicitly tested for %s " % simulation)
sys.exit(0)
if "-e" in parameterName :
process+=addProcess(thefactory,"p p e+ e- j","1","2","HTScale",0,0)
if "Z-Jet-0-e" in parameterName :
process+=addFirstJet("35")
parameterName=parameterName.replace("Z-Jet-0-e","Z-Jet-e")
elif "Z-Jet-1-e" in parameterName :
process+=addFirstJet("100")
parameterName=parameterName.replace("Z-Jet-1-e","Z-Jet-e")
elif "Z-Jet-2-e" in parameterName :
process+=addFirstJet("190")
parameterName=parameterName.replace("Z-Jet-2-e","Z-Jet-e")
elif "Z-Jet-3-e" in parameterName :
process+=addFirstJet("270")
parameterName=parameterName.replace("Z-Jet-3-e","Z-Jet-e")
else :
logging.error("Exit 00006")
sys.exit(1)
else :
process+=addProcess(thefactory,"p p mu+ mu- j","1","2","HTScale",0,0)
process+=addFirstJet("35")
parameterName=parameterName.replace("Z-Jet-0-mu","Z-Jet-mu")
process+=addLeptonPairCut("60","120")
elif "Z-bb" in parameterName :
if(simulation=="Merging"):
logging.warning("Z-bb not explicitly tested for %s " % simulation)
sys.exit(0)
parameters["bscheme"]=fourFlavour
process+="set /Herwig/Particles/b:HardProcessMass 4.2*GeV\nset /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n"
process+=addProcess(thefactory,"p p e+ e- b bbar","2","2","FixedScale",0,0)
process+=addLeptonPairCut("66","116")
process+=addFirstJet("18")
process+=addSecondJet("15")
process+=addLeptonPairCut("60","120")
elif "Z-b" in parameterName :
if(simulation=="Merging"):
logging.warning("Z-b not explicitly tested for %s " % simulation)
sys.exit(0)
process+=particlegroup('bjet','b','bbar')
process+=addProcess(thefactory,"p p e+ e- bjet","1","2","FixedScale",0,0)
process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 91.2*GeV\n"
process+=addLeptonPairCut("60","120")
process+=addFirstJet("15")
elif "W-b" in parameterName :
if(simulation=="Merging"):
logging.warning("W-b not explicitly tested for %s " % simulation)
sys.exit(0)
parameters["bscheme"]=fourFlavour
process += "set /Herwig/Particles/b:HardProcessMass 4.2*GeV\nset /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n"
process+=addProcess(thefactory,"p p e- nu b bbar","2","2","FixedScale",0,0)
process+=addProcess(thefactory,"p p mu+ nu b bbar","2","2","FixedScale",0,0)
process += "set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 80.4*GeV\n"
process+=addFirstJet("30")
process+=addLeptonPairCut("60","120")
else :
logging.error(" Process %s not supported for Matchbox matrix elements" % name)
sys.exit(1)
# LHC-GammaGamma
elif(collider=="LHC-GammaGamma" ) :
if "-7-" in parameterName : process = StringBuilder(collider_lumi(7000.0))
elif "-8-" in parameterName : process = StringBuilder(collider_lumi(8000.0))
else : process = StringBuilder(collider_lumi(7000.0))
if(simulation=="") :
if "7" in parameterName : process += insert_ME("MEgg2ff","Muon")
else :
logging.error(" Process %s not supported for default matrix elements" % name)
sys.exit(1)
else :
logging.error("LHC-GammaGamma not supported for %s " % simulation)
sys.exit(1)
parameters['parameterFile'] = os.path.join(collider,"{c}-{pn}.in".format(c=collider, pn=parameterName))
parameters['runname'] = 'Rivet-%s' % name
parameters['process'] = str(process)
#check if selecteddecaymode and addedBRReweighter is consistent
if selecteddecaymode and not addedBRReweighter:
logging.error("Decaymode was selected but no BRReweighter was added.")
sys.exit(1)
if addedBRReweighter and not selecteddecaymode:
logging.error("BRReweighter was added but no Decaymode was selected.")
sys.exit(1)
# check that we only add one process if in merging mode:
if numberOfAddedProcesses > 1 and simulation =="Merging":
logging.error("In Merging only one process is allowed at the moment. See ticket #403.")
sys.exit(1)
# Check if a process was added for Merging or Matchbox:
if numberOfAddedProcesses == 0 and (simulation =="Merging" or simulation =="Matchbox"):
logging.error("No process was selected.")
sys.exit(1)
# get template and write the file
with open(os.path.join("Rivet/Templates",templateName), 'r') as f:
templateText = f.read()
template = Template( templateText )
with open(os.path.join("Rivet",name+".in"), 'w') as f:
f.write( template.substitute(parameters) )
diff --git a/Tests/python/merge-LHC-Jets b/Tests/python/merge-LHC-Jets
--- a/Tests/python/merge-LHC-Jets
+++ b/Tests/python/merge-LHC-Jets
@@ -1,1427 +1,1442 @@
#! /usr/bin/env python
import logging
import sys
import math
if sys.version_info[:3] < (2,4,0):
print "rivet scripts require Python version >= 2.4.0... exiting"
sys.exit(1)
import os, yoda
# #############################################
def fillAbove(scale,desthisto, sourcehistosbyptmin) :
pthigh= 1e100
ptlow =-1e100
for pt, h in sorted(sourcehistosbyptmin.iteritems(),reverse=True):
ptlow=pt
if(type(desthisto)==yoda.core.Scatter2D) :
for i in range(0,h.numPoints) :
xMin = h.points[i].x-h.points[i].xErrs.minus
if( xMin*scale >= ptlow and
xMin*scale < pthigh ) :
desthisto.addPoint(h.points[i])
elif(type(desthisto)==yoda.core.Profile1D) :
for i in range(0,h.numBins) :
if(h.bins[i].xMin*scale >= ptlow and
h.bins[i].xMin*scale < pthigh ) :
desthisto.bins[i] += h.bins[i]
elif(type(desthisto)==yoda.core.Histo1D) :
for i in range(0,h.numBins) :
if(h.bins[i].xMin*scale >= ptlow and
h.bins[i].xMin*scale < pthigh ) :
desthisto.bins[i] += h.bins[i]
elif(type(desthisto)==yoda.core.Counter) :
desthisto += h
else :
logging.error("Can't merge %s, unknown type" % desthisto.path)
sys.exit(1)
pthigh=pt
def mergeByPt(hpath, sqrts, scale=1.) :
global inhistos_pt
global outhistos
try:
fillAbove(scale,outhistos[hpath], inhistos_pt[hpath][float(sqrts)])
except:
pass
def mergeByMass(hpath, sqrts, scale=1.):
global inhistos_mass
global outhistos
try:
fillAbove(scale,outhistos[hpath], inhistos_mass[hpath][float(sqrts)])
except:
pass
def useOnePt(hpath, sqrts, ptmin):
global inhistos_pt
global outhistos
try:
## Find best pT_min match
ptmins = inhistos_pt[hpath][float(sqrts)].keys()
closest_ptmin = None
for ptm in ptmins:
if closest_ptmin is None or \
abs(ptm-float(ptmin)) < abs(closest_ptmin-float(ptmin)):
closest_ptmin = ptm
if closest_ptmin != float(ptmin):
logging.warning("Inexact match for requested pTmin=%s: " % ptmin + \
"using pTmin=%e instead" % closest_ptmin)
outhistos[hpath] = inhistos_pt[hpath][float(sqrts)][closest_ptmin]
except:
pass
def useOneMass(hpath, sqrts, ptmin):
global inhistos_pt
global outhistos
try:
## Find best pT_min match
ptmins = inhistos_mass[hpath][float(sqrts)].keys()
closest_ptmin = None
for ptm in ptmins:
if closest_ptmin is None or \
abs(ptm-float(ptmin)) < abs(closest_ptmin-float(ptmin)):
closest_ptmin = ptm
if closest_ptmin != float(ptmin):
logging.warning("Inexact match for requested mass=%s: " % ptmin + \
"using mass=%e instead" % closest_ptmin)
outhistos[hpath] = inhistos_mass[hpath][float(sqrts)][closest_ptmin]
except:
pass
# #######################################
if __name__ == "__main__":
import logging
from optparse import OptionParser, OptionGroup
parser = OptionParser(usage="%prog name")
verbgroup = OptionGroup(parser, "Verbosity control")
parser.add_option("--with-ue",
action='store_true' ,
dest="ue",
default=True,
help="Include UE analyses")
parser.add_option("--without-ue",
action='store_false',
dest="ue",
default=True,
help="Don\'t include UE analyses")
verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL",
default=logging.INFO, help="print debug (very verbose) messages")
verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL",
default=logging.INFO, help="be very quiet")
parser.add_option_group(verbgroup)
(opts, args) = parser.parse_args()
logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s")
(opts, args) = parser.parse_args()
## Check args
if len(args) < 1:
logging.error("Must specify at least the name of the files")
sys.exit(1)
yodafiles=["-7-Bottom-0.yoda","-7-Bottom-1.yoda","-7-Bottom-2.yoda",
"-7-Bottom-3.yoda","-7-Bottom-4.yoda","-7-Bottom-5.yoda",
"-7-Charm-1.yoda","-7-Charm-2.yoda",
"-7-Charm-3.yoda","-7-Charm-4.yoda","-7-Charm-5.yoda",
"-7-Top-SL.yoda","-7-Top-L.yoda","-7-Top-All.yoda",
- "-8-Top-All.yoda","-13-Top-All.yoda"]
+ "-8-Top-SL.yoda","-8-Top-L.yoda","-8-Top-All.yoda",
+ "-13-Top-All.yoda"]
for i in range(1,10) :
for j in [7,8,13] :
yodafiles.append("-%1.1i-Jets-%1.1i.yoda" % (j,i))
if(opts.ue) :
yodafiles += ["-7-Jets-0.yoda" ,"-8-Jets-0.yoda" ,"-7-Jets-10.yoda",
"-8-Jets-10.yoda" ,"-900-UE.yoda" ,"-2360-UE.yoda" ,
"-2760-UE.yoda" ,"-7-UE.yoda" ,"-900-UE-Long.yoda",
"-900-UE-Short.yoda","-8-UE.yoda" ,
"-7-UE-Long.yoda","-13-UE.yoda","-13-UE-Long.yoda"]
## Get histos
inhistos_pt = {}
inhistos_mass = {}
outhistos={}
weights = {}
for f in yodafiles:
file='Rivet-'+args[0]+f
ptmin=0.
sqrts=7000
# CMS energy
if(file.find("-900-")>0) :
sqrts=900
elif(file.find("-2360-")>0) :
sqrts=2360
elif(file.find("-2760-")>0) :
sqrts=2760
elif(file.find("-7-")>=0) :
sqrts=7000
elif(file.find("-8-")>=0) :
sqrts=8000
elif(file.find("-13-")>0) :
sqrts=13000
# pT min
if(file.find("UE")>0) :
ptmin=0.
elif(file.find("Jets-0")>0) :
ptmin=4.
elif(file.find("Jets-10")>0) :
ptmin=1900.
elif(file.find("Jets-1")>0) :
if( not opts.ue) :
ptmin = 10.
else :
ptmin = 20.
elif(file.find("Jets-2")>0) :
ptmin=40.
elif(file.find("Jets-3")>0) :
ptmin=80.
elif(file.find("Jets-4")>0) :
ptmin=110.
elif(file.find("Jets-5")>0) :
ptmin=210.
elif(file.find("Jets-6")>0) :
ptmin=260.
elif(file.find("Jets-7")>0) :
ptmin=400.
elif(file.find("Jets-8")>0) :
ptmin=600.
elif(file.find("Jets-9")>0) :
ptmin=900.
elif(file.find("Bottom-0")>0) :
ptmin=0.
elif(file.find("Bottom-1")>0 or file.find("Charm-1")>0) :
ptmin=10.
elif(file.find("Bottom-2")>0 or file.find("Charm-2")>0) :
ptmin=30.
elif(file.find("Bottom-3")>0 or file.find("Charm-3")>0) :
ptmin=70.
elif(file.find("Bottom-4")>0 or file.find("Charm-4")>0) :
ptmin=100.
elif(file.find("Bottom-5")>0 or file.find("Charm-5")>0) :
ptmin=130.
elif(file.find("Top-SL.yoda")>0 or file.find("Top-L.yoda")>0 or \
file.find("Top-All.yoda")>0):
ptmin=0.
if not os.access(file, os.R_OK):
logging.error("%s can not be read" % file)
continue
try:
aos = yoda.read(file)
except:
logging.error("%s can not be parsed as YODA" % file)
continue
## Get histos from this YODA file
for aopath, ao in aos.iteritems() :
if(aopath.find("S8924791")>0 or aopath.find("S8971293")>0 or
aopath.find("S8817804")>0 or aopath.find("I1082936")>0 or
aopath.find("S8994773")>0 or aopath.find("S8918562")>0 or
aopath.find("S8624100")>0 or aopath.find("S8625980")>0 or
aopath.find("S8894728")>0 or aopath.find("S8957746")>0 or
aopath.find("S9126244")>0 or aopath.find("S9120041")>0 or
aopath.find("S8950903")>0 or aopath.find("S9086218")>0 or
aopath.find("S9088458")>0 or aopath.find("I919017" )>0 or
aopath.find("I926145" )>0 or aopath.find("S8941262")>0 or
aopath.find("S8973270")>0 or aopath.find("I1118269")>0 or
aopath.find("I1188891")>0 or aopath.find("I1082009")>0 or
aopath.find("I1087342")>0 or aopath.find("S9035664")>0 or
aopath.find("I1125575")>0 or aopath.find("I1094564")>0 or
aopath.find("I930220" )>0 or aopath.find("I1224539")>0 or
aopath.find("I1273574")>0 or aopath.find("I1261026")>0 or
aopath.find("I1307243")>0 or aopath.find("I1325553")>0 or
aopath.find("I1298810")>0 or aopath.find("I1298811")>0 or
aopath.find("I1208923")>0 or aopath.find("I1305624")>0 or
aopath.find("I1419070")>0 or aopath.find("I1394679")>0 or
aopath.find("I929691" )>0 or aopath.find("I1393758")>0 or
aopath.find("I1459051")>0 or aopath.find("ATLAS_2016_CONF_2016_092")>0 or
aopath.find("CMS_2012_PAS_QCD_11_010")>0) :
if not inhistos_pt.has_key(aopath):
inhistos_pt[aopath] = {}
tmpE = inhistos_pt[aopath]
if not tmpE.has_key(sqrts):
tmpE[sqrts] = {}
if not tmpE[sqrts].has_key(ptmin):
tmpE[sqrts][ptmin] = ao
else:
tmpE[sqrts][ptmin] += ao
#raise Exception("A set with ptmin = %s already exists" % ( ptmin))
else :
if(aopath.find("I1243871")>0) :
if(aopath.find("x01")>0 and file.find("-7-Top-L.yoda")>0 ) :
outhistos[aopath] = ao
elif(aopath.find("x02")>0 and file.find("-7-Top-SL.yoda")>0 ) :
outhistos[aopath] = ao
elif(aopath.find("1467230")>0 or aopath.find("1419652")>0) :
if(aopath.find("y01")>0 and file.find("Long")>0 ) :
outhistos[aopath] = ao
elif(aopath.find("y02")>0 and file.find("Long")<0 ) :
outhistos[aopath] = ao
else :
outhistos[aopath] = ao
yodafiles=["-7-Bottom-6.yoda","-7-Bottom-7.yoda","-7-Bottom-8.yoda"]
for i in range(1,8) :
yodafiles.append("-7-DiJets-%1.1i-A.yoda" % i)
yodafiles.append("-7-DiJets-%1.1i-B.yoda" % i)
yodafiles.append("-7-DiJets-%1.1i-C.yoda" % i)
for f in yodafiles:
print file
file='Rivet-'+args[0]+f
if(file.find("-7-Jets-1")>0) :
sqrts=7000
mass=0
if(file.find("-7-DiJets-1")>0) :
sqrts=7000
mass=100
elif(file.find("-7-DiJets-2")>0) :
sqrts=7000
mass=250
elif(file.find("-7-DiJets-3")>0) :
sqrts=7000
mass=500
elif(file.find("-7-DiJets-4")>0) :
sqrts=7000
mass=800
elif(file.find("-7-DiJets-5")>0) :
sqrts=7000
mass=1000
elif(file.find("-7-DiJets-6")>0) :
sqrts=7000
mass=1600
elif(file.find("-7-DiJets-7")>0) :
sqrts=7000
mass=2200
elif(file.find("-7-DiJets-8")>0) :
sqrts=7000
mass=2800
elif(file.find("-7-Bottom-6")>0) :
sqrts=7000
mass=110
elif(file.find("-7-Bottom-7")>0) :
sqrts=7000
mass=370
elif(file.find("-7-Bottom-8")>0) :
sqrts=7000
mass=550
if not os.access(file, os.R_OK):
logging.error("%s can not be read" % file)
continue
try:
aos = yoda.read(file)
except:
logging.error("%s can not be parsed as YODA" % file)
continue
## Get histos from this YODA file
for aopath, ao in aos.iteritems() :
if(aopath.find("8817804")>0 or
aopath.find("8968497")>0 or
aopath.find("1082936")>0 or
aopath.find("I930220")>0 or
aopath.find("1261026")>0 or
aopath.find("1090423")>0 or
aopath.find("1268975")>0 or
aopath.find("CMS_2013_I1208923")>0) :
if not inhistos_mass.has_key(aopath):
inhistos_mass[aopath] = {}
tmpE = inhistos_mass[aopath]
if not tmpE.has_key(sqrts):
tmpE[sqrts] = {}
tmpP = tmpE[sqrts]
if not tmpP.has_key(mass):
tmpP[mass] = ao
else:
print aopath
raise Exception("A set with mass = %s already exists" % ( mass))
## Make empty output histos if needed
for hpath,hsets in inhistos_pt.iteritems():
if( hpath.find("8924791")>0 or
hpath.find("8971293")>0 or
hpath.find("8817804")>0 or
hpath.find("8968497")>0 or
(hpath.find("9120041")>0 and (hpath.find("d01")>0 or hpath.find("d02")>0)) or
hpath.find("9126244")>0 or
hpath.find("926145") >0 or
hpath.find("9086218")>0 or
hpath.find("1082936")>0 or
hpath.find("8941262")>0 or
hpath.find("1118269")>0 or
hpath.find("1087342")>0 or
hpath.find("1188891")>0 or
hpath.find("919017")>0 or
hpath.find("9035664")>0 or
hpath.find("1125575")>0 or
hpath.find("1094564")>0 or
hpath.find("I930220")>0 or
hpath.find("S9088458")>0 or
hpath.find("I1273574")>0 or
hpath.find("I1261026")>0 or
hpath.find("I1090423")>0 or
hpath.find("QCD_11_010")>0 or
hpath.find("1298811" )>0 or
hpath.find("I1325553" )>0 or
hpath.find("I1298810" )>0 or
hpath.find("1307243" )>0 or
hpath.find("I1419070")>0 or
hpath.find("I1394679")>0 or
hpath.find("CMS_2013_I1208923")>0 or
hpath.find("1393758")>0 or
hpath.find("ATLAS_2016_CONF_2016_092")>0 or
hpath.find("1459051")>0) :
if(type(hsets.values()[0].values()[0])==yoda.core.Counter) :
outhistos[hpath] = yoda.core.Counter(hsets.values()[0].values()[0].path,
hsets.values()[0].values()[0].title)
elif(type(hsets.values()[0].values()[0])==yoda.core.Scatter2D) :
outhistos[hpath] = yoda.core.Scatter2D(hsets.values()[0].values()[0].path,
hsets.values()[0].values()[0].title)
elif(type(hsets.values()[0].values()[0])==yoda.core.Profile1D) :
outhistos[hpath] = yoda.core.Profile1D(hsets.values()[0].values()[0].path,
hsets.values()[0].values()[0].title)
for i in range(0,hsets.values()[0].values()[0].numBins) :
outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin,
hsets.values()[0].values()[0].bins[i].xMax)
elif(type(hsets.values()[0].values()[0])==yoda.core.Histo1D) :
outhistos[hpath] = yoda.core.Histo1D(hsets.values()[0].values()[0].path,
hsets.values()[0].values()[0].title)
for i in range(0,hsets.values()[0].values()[0].numBins) :
outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin,
hsets.values()[0].values()[0].bins[i].xMax)
else :
logging.error("Histogram %s is of unknown type" % hpath)
sys.exit(1)
## Make empty output histos if needed
for hpath,hsets in inhistos_mass.iteritems():
if(hpath.find("1268975")>0) :
if(type(hsets.values()[0].values()[0])==yoda.core.Counter) :
outhistos[hpath] = yoda.core.Counter(hsets.values()[0].values()[0].path,
hsets.values()[0].values()[0].title)
elif(type(hsets.values()[0].values()[0])==yoda.core.Scatter2D) :
outhistos[hpath] = yoda.core.Scatter2D(hsets.values()[0].values()[0].path,
hsets.values()[0].values()[0].title)
elif(type(hsets.values()[0].values()[0])==yoda.core.Profile1D) :
outhistos[hpath] = yoda.core.Profile1D(hsets.values()[0].values()[0].path,
hsets.values()[0].values()[0].title)
for i in range(0,hsets.values()[0].values()[0].numBins) :
outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin,
hsets.values()[0].values()[0].bins[i].xMax)
elif(type(hsets.values()[0].values()[0])==yoda.core.Histo1D) :
outhistos[hpath] = yoda.core.Histo1D(hsets.values()[0].values()[0].path,
hsets.values()[0].values()[0].title)
for i in range(0,hsets.values()[0].values()[0].numBins) :
outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin,
hsets.values()[0].values()[0].bins[i].xMax)
else :
logging.error("Histogram %s is of unknown type" % hpath)
sys.exit(1)
logging.info("Processing CMS_2011_S8957746")
useOnePt("/CMS_2011_S8957746/d01-x01-y01", "7000", "80" )
useOnePt("/CMS_2011_S8957746/d02-x01-y01", "7000", "80" )
useOnePt("/CMS_2011_S8957746/d03-x01-y01", "7000", "110" )
useOnePt("/CMS_2011_S8957746/d04-x01-y01", "7000", "110" )
useOnePt("/CMS_2011_S8957746/d05-x01-y01", "7000", "210" )
useOnePt("/CMS_2011_S8957746/d06-x01-y01", "7000", "210" )
logging.info("Processing ATLAS_2010_S8894728")
useOnePt("/ATLAS_2010_S8894728/d01-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d01-x01-y02", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d01-x01-y03", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d02-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d02-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d02-x01-y03", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d03-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d03-x01-y02", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d03-x01-y03", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d04-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d04-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d04-x01-y03", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d05-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d06-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d07-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d08-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d09-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d09-x01-y02", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d09-x01-y03", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d10-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d10-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d10-x01-y03", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d11-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d11-x01-y02", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d11-x01-y03", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d12-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d12-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d12-x01-y03", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d13-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d13-x01-y02", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d13-x01-y03", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d13-x01-y04", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d14-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d14-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d14-x01-y03", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d14-x01-y04", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d15-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d15-x01-y02", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d15-x01-y03", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d15-x01-y04", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d16-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d16-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d16-x01-y03", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d16-x01-y04", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d17-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d17-x01-y02", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d17-x01-y03", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d18-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d18-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d18-x01-y03", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d19-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d19-x01-y02", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d19-x01-y03", "900", "0" )
useOnePt("/ATLAS_2010_S8894728/d20-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d20-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d20-x01-y03", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d21-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8894728/d22-x01-y01", "7000", "0" )
logging.info("Processing ATLAS_2011_S8994773")
useOnePt("/ATLAS_2011_S8994773/d01-x01-y01", "900", "0" )
useOnePt("/ATLAS_2011_S8994773/d02-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2011_S8994773/d03-x01-y01", "900", "0" )
useOnePt("/ATLAS_2011_S8994773/d04-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2011_S8994773/d13-x01-y01", "900", "0" )
useOnePt("/ATLAS_2011_S8994773/d13-x01-y02", "900", "0" )
useOnePt("/ATLAS_2011_S8994773/d13-x01-y03", "900", "0" )
useOnePt("/ATLAS_2011_S8994773/d14-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2011_S8994773/d14-x01-y02", "7000", "0" )
useOnePt("/ATLAS_2011_S8994773/d14-x01-y03", "7000", "0" )
logging.info("Processing ALICE_2010_S8624100")
useOnePt("/ALICE_2010_S8624100/d11-x01-y01", "900", "0" )
useOnePt("/ALICE_2010_S8624100/d12-x01-y01", "900", "0" )
useOnePt("/ALICE_2010_S8624100/d13-x01-y01", "900", "0" )
useOnePt("/ALICE_2010_S8624100/d17-x01-y01","2360", "0" )
useOnePt("/ALICE_2010_S8624100/d18-x01-y01","2360", "0" )
useOnePt("/ALICE_2010_S8624100/d19-x01-y01","2360", "0" )
logging.info("Processing ALICE_2010_S8625980")
useOnePt("/ALICE_2010_S8625980/d03-x01-y01", "7000", "0" )
useOnePt("/ALICE_2010_S8625980/d04-x01-y01", "900", "0" )
useOnePt("/ALICE_2010_S8625980/d05-x01-y01", "2360", "0" )
useOnePt("/ALICE_2010_S8625980/d06-x01-y01", "7000", "0" )
logging.info("Processing ATLAS_2010_S8918562")
useOnePt("/ATLAS_2010_S8918562/d01-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d02-x01-y01", "2360", "0" )
useOnePt("/ATLAS_2010_S8918562/d03-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d04-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d05-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d06-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d07-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d08-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d09-x01-y01", "2360", "0" )
useOnePt("/ATLAS_2010_S8918562/d10-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d11-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d12-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d13-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d14-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d15-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d16-x01-y01", "2360", "0" )
useOnePt("/ATLAS_2010_S8918562/d17-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d18-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d19-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d20-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d21-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d22-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d23-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d24-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d25-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d26-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d27-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d28-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d29-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d30-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d31-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d32-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d33-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d34-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d35-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d36-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d37-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2010_S8918562/d38-x01-y01", "900", "0" )
useOnePt("/ATLAS_2010_S8918562/d39-x01-y01", "7000", "0" )
logging.info("Processing ATLAS_2011_S8971293")
useOnePt("/ATLAS_2011_S8971293/d01-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8971293/d01-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8971293/d01-x01-y03", "7000", "210" )
useOnePt("/ATLAS_2011_S8971293/d01-x01-y04", "7000", "260" )
useOnePt("/ATLAS_2011_S8971293/d01-x01-y05", "7000", "260" )
useOnePt("/ATLAS_2011_S8971293/d01-x01-y06", "7000", "400" )
useOnePt("/ATLAS_2011_S8971293/d01-x01-y07", "7000", "400" )
useOnePt("/ATLAS_2011_S8971293/d01-x01-y08", "7000", "600" )
useOnePt("/ATLAS_2011_S8971293/d01-x01-y09", "7000", "600" )
logging.info("Processing ATLAS_2011_S8924791")
if( not opts.ue) :
useOnePt("/ATLAS_2011_S8924791/d01-x01-y01", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x01-y02", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x02-y01", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x02-y02", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x03-y01", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x03-y02", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x04-y01", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x04-y02", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x05-y01", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x05-y02", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x06-y01", "7000", "10" )
useOnePt("/ATLAS_2011_S8924791/d01-x06-y02", "7000", "10" )
else :
useOnePt("/ATLAS_2011_S8924791/d01-x01-y01", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x01-y02", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x02-y01", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x02-y02", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x03-y01", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x03-y02", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x04-y01", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x04-y02", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x05-y01", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x05-y02", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x06-y01", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d01-x06-y02", "7000", "20" )
useOnePt("/ATLAS_2011_S8924791/d02-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x02-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x02-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x03-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x03-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x04-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x04-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x05-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x05-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x06-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d02-x06-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x02-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x02-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x03-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x03-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x04-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x04-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x05-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x05-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x06-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d03-x06-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S8924791/d04-x01-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x01-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x02-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x02-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x03-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x03-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x04-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x04-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x05-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x05-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x06-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d04-x06-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S8924791/d05-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x02-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x02-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x03-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x03-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x04-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x04-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x05-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x05-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x06-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d05-x06-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x02-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x02-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x03-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x03-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x04-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x04-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x05-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x05-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x06-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d06-x06-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S8924791/d07-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x02-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x02-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x03-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x03-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x04-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x04-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x05-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x05-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x06-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d07-x06-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S8924791/d08-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x01-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x02-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x02-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x03-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x03-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x04-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x04-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x05-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x05-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x06-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d08-x06-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x01-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x02-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x02-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x03-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x03-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x04-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x04-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x05-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x05-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x06-y01", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d09-x06-y02", "7000", "260" )
useOnePt("/ATLAS_2011_S8924791/d10-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x01-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x02-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x02-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x03-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x03-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x04-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x04-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x05-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x05-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x06-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d10-x06-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x01-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x02-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x02-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x03-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x03-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x04-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x04-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x05-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x05-y02", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x06-y01", "7000", "400" )
useOnePt("/ATLAS_2011_S8924791/d11-x06-y02", "7000", "400" )
logging.info("Processing ATLAS_2010_S8817804")
mergeByPt("/ATLAS_2010_S8817804/d01-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d02-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d03-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d04-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d05-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d06-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d07-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d08-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d09-x01-y01", "7000")
mergeByPt("/ATLAS_2010_S8817804/d10-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d11-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d12-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d13-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d14-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d15-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d16-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d17-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d18-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d19-x01-y01", "7000")
mergeByMass("/ATLAS_2010_S8817804/d20-x01-y01", "7000")
useOneMass("/ATLAS_2010_S8817804/d21-x01-y01", "7000", "250" )
useOneMass("/ATLAS_2010_S8817804/d22-x01-y01", "7000", "250" )
useOneMass("/ATLAS_2010_S8817804/d23-x01-y01", "7000", "650" )
useOneMass("/ATLAS_2010_S8817804/d24-x01-y01", "7000", "250" )
useOneMass("/ATLAS_2010_S8817804/d25-x01-y01", "7000", "250" )
useOneMass("/ATLAS_2010_S8817804/d26-x01-y01", "7000", "650" )
logging.info("Processing ATLAS_2011_I930220")
mergeByPt("/ATLAS_2011_I930220/d01-x01-y01", "7000" )
mergeByPt("/ATLAS_2011_I930220/d02-x01-y01", "7000" )
mergeByPt("/ATLAS_2011_I930220/d03-x01-y01", "7000" )
mergeByPt("/ATLAS_2011_I930220/d04-x01-y01", "7000" )
mergeByPt("/ATLAS_2011_I930220/d05-x01-y01", "7000" )
mergeByPt("/ATLAS_2011_I930220/d06-x01-y01", "7000" )
mergeByMass("/ATLAS_2011_I930220/d07-x01-y01", "7000")
useOneMass("/ATLAS_2011_I930220/d08-x01-y01", "7000", "110" )
useOneMass("/ATLAS_2011_I930220/d09-x01-y01", "7000", "110" )
useOneMass("/ATLAS_2011_I930220/d10-x01-y01", "7000", "370" )
logging.info("Processing ATLAS_2012_I1082936")
mergeByPt("/ATLAS_2012_I1082936/d01-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1082936/d01-x01-y02", "7000")
mergeByPt("/ATLAS_2012_I1082936/d01-x01-y03", "7000")
mergeByPt("/ATLAS_2012_I1082936/d01-x01-y04", "7000")
mergeByPt("/ATLAS_2012_I1082936/d01-x01-y05", "7000")
mergeByPt("/ATLAS_2012_I1082936/d01-x01-y06", "7000")
mergeByPt("/ATLAS_2012_I1082936/d01-x01-y07", "7000")
mergeByPt("/ATLAS_2012_I1082936/d02-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1082936/d02-x01-y02", "7000")
mergeByPt("/ATLAS_2012_I1082936/d02-x01-y03", "7000")
mergeByPt("/ATLAS_2012_I1082936/d02-x01-y04", "7000")
mergeByPt("/ATLAS_2012_I1082936/d02-x01-y05", "7000")
mergeByPt("/ATLAS_2012_I1082936/d02-x01-y06", "7000")
mergeByPt("/ATLAS_2012_I1082936/d02-x01-y07", "7000")
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y01", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y02", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y03", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y04", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y05", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y06", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y07", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y08", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d03-x01-y09", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y01", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y02", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y03", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y04", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y05", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y06", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y07", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y08", "7000", 1000.)
mergeByMass("/ATLAS_2012_I1082936/d04-x01-y09", "7000", 1000.)
logging.info("Processing CMS_2011_S8968497")
useOneMass("/CMS_2011_S8968497/d01-x01-y01", "7000", "1700" )
useOneMass("/CMS_2011_S8968497/d02-x01-y01", "7000", "1700" )
useOneMass("/CMS_2011_S8968497/d03-x01-y01", "7000", "1100" )
useOneMass("/CMS_2011_S8968497/d04-x01-y01", "7000", "1100" )
useOneMass("/CMS_2011_S8968497/d05-x01-y01", "7000", "650" )
useOneMass("/CMS_2011_S8968497/d06-x01-y01", "7000", "650" )
useOneMass("/CMS_2011_S8968497/d07-x01-y01", "7000", "250" )
useOneMass("/CMS_2011_S8968497/d08-x01-y01", "7000", "250" )
useOneMass("/CMS_2011_S8968497/d09-x01-y01", "7000", "250" )
logging.info("Processing ATLAS_2011_S9126244")
mergeByPt("/ATLAS_2011_S9126244/d01-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d01-x01-y02", "7000")
mergeByPt("/ATLAS_2011_S9126244/d02-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d02-x01-y02", "7000")
mergeByPt("/ATLAS_2011_S9126244/d03-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d03-x01-y02", "7000")
mergeByPt("/ATLAS_2011_S9126244/d04-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d04-x01-y02", "7000")
mergeByPt("/ATLAS_2011_S9126244/d05-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d05-x01-y02", "7000")
useOnePt("/ATLAS_2011_S9126244/d06-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d06-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d07-x01-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S9126244/d07-x01-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S9126244/d08-x01-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S9126244/d08-x01-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S9126244/d09-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d09-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d10-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d10-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d11-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d11-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d12-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d12-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d13-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d13-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d14-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d14-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d15-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d15-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d16-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d16-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d17-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d17-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d18-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d18-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d19-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d20-x01-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S9126244/d21-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d22-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d23-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d24-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d25-x01-y01", "7000", "210" )
mergeByPt("/ATLAS_2011_S9126244/d26-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d26-x01-y02", "7000")
mergeByPt("/ATLAS_2011_S9126244/d27-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d27-x01-y02", "7000")
mergeByPt("/ATLAS_2011_S9126244/d28-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d28-x01-y02", "7000")
mergeByPt("/ATLAS_2011_S9126244/d29-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9126244/d29-x01-y02", "7000")
useOnePt("/ATLAS_2011_S9126244/d30-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d31-x01-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S9126244/d32-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d33-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d34-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d35-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d36-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d37-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d37-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2011_S9126244/d38-x01-y01", "7000", "80" )
useOnePt("/ATLAS_2011_S9126244/d38-x01-y02", "7000", "80" )
useOnePt("/ATLAS_2011_S9126244/d39-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d39-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d40-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d40-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d41-x01-y01", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d41-x01-y02", "7000", "110" )
useOnePt("/ATLAS_2011_S9126244/d42-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d42-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d43-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2011_S9126244/d43-x01-y02", "7000", "210" )
# CMS_2011_S9120041 UE analysis
logging.info("Processing CMS_2011_S9120041")
mergeByPt("/CMS_2011_S9120041/d01-x01-y01", "7000")
mergeByPt("/CMS_2011_S9120041/d02-x01-y01", "7000")
if(opts.ue) :
useOnePt("/CMS_2011_S9120041/d03-x01-y01", "900", "0" )
useOnePt("/CMS_2011_S9120041/d04-x01-y01", "900", "0" )
useOnePt("/CMS_2011_S9120041/d05-x01-y01", "7000", "0" )
useOnePt("/CMS_2011_S9120041/d06-x01-y01", "7000", "0" )
useOnePt("/CMS_2011_S9120041/d07-x01-y01", "7000", "0" )
useOnePt("/CMS_2011_S9120041/d11-x01-y01", "900", "0" )
useOnePt("/CMS_2011_S9120041/d12-x01-y01", "900", "0" )
useOnePt("/CMS_2011_S9120041/d13-x01-y01", "900", "0" )
useOnePt("/CMS_2011_S9120041/d08-x01-y01", "7000", "20" )
useOnePt("/CMS_2011_S9120041/d09-x01-y01", "7000", "20" )
useOnePt("/CMS_2011_S9120041/d10-x01-y01", "7000", "20" )
else :
useOnePt("/CMS_2011_S9120041/d08-x01-y01", "7000", "10" )
useOnePt("/CMS_2011_S9120041/d09-x01-y01", "7000", "10" )
useOnePt("/CMS_2011_S9120041/d10-x01-y01", "7000", "10" )
# CMS dijet decorrelation
logging.info("Processing CMS_2011_S8950903")
useOnePt("/CMS_2011_S8950903/d01-x01-y01", "7000", "80" )
useOnePt("/CMS_2011_S8950903/d02-x01-y01", "7000", "110" )
useOnePt("/CMS_2011_S8950903/d03-x01-y01", "7000", "110" )
useOnePt("/CMS_2011_S8950903/d04-x01-y01", "7000", "210" )
useOnePt("/CMS_2011_S8950903/d05-x01-y01", "7000", "260" )
# CMS jet cross section
logging.info("Processing CMS_2011_S9086218")
mergeByPt("/CMS_2011_S9086218/d01-x01-y01", "7000")
mergeByPt("/CMS_2011_S9086218/d02-x01-y01", "7000")
mergeByPt("/CMS_2011_S9086218/d03-x01-y01", "7000")
mergeByPt("/CMS_2011_S9086218/d04-x01-y01", "7000")
mergeByPt("/CMS_2011_S9086218/d05-x01-y01", "7000")
mergeByPt("/CMS_2011_S9086218/d06-x01-y01", "7000")
# CMS 2/3 jet cross section ratio
logging.info("Processing CMS_2011_S9086218")
mergeByPt("/CMS_2011_S9088458/d01-x01-y01", "7000",500.)
# ATLAS track jet
logging.info("Processing ATLAS_2011_I919017")
for d in range(1,3) :
for y in range(1,5) :
mergeByPt("/ATLAS_2011_I919017/d0%s-x01-y0%s" % (d,y), "7000")
if( opts.ue) :
for x in range(2,6) :
for y in ["01","02","06","07","11","12","16","17","21","22"] :
useOnePt("/ATLAS_2011_I919017/d0%s-x0%s-y%s" % (d,x,y), "7000", "0" )
for y in ["03","04","08","09","13","14","18","19","23","24"] :
useOnePt("/ATLAS_2011_I919017/d0%s-x0%s-y%s" % (d,x,y), "7000", "4" )
for y in range(5,30,5) :
useOnePt("/ATLAS_2011_I919017/d0%s-x%02d-y%02d" % (d,x,y) , "7000", "20" )
else :
for x in range(2,6) :
for y in range(5,30,5) :
useOnePt("/ATLAS_2011_I919017/d0%s-x%02d-y%02d" % (d,x,y) , "7000", "10" )
logging.info("Processing ATLAS_2011_I926145")
mergeByPt("/ATLAS_2011_I926145/d01-x01-y01", "7000",1.5)
mergeByPt("/ATLAS_2011_I926145/d02-x01-y01", "7000",1.5)
mergeByPt("/ATLAS_2011_I926145/d03-x01-y01", "7000",1.5)
logging.info("Processing CMS_2011_S8941262")
useOnePt("/CMS_2011_S8941262/d01-x01-y01", "7000", "10" )
useOnePt("/CMS_2011_S8941262/d03-x01-y01", "7000", "10" )
mergeByPt("/CMS_2011_S8941262/d02-x01-y01", "7000",1.5)
logging.info("Processing CMS_2011_S8973270")
useOnePt("/CMS_2011_S8973270/d01-x01-y01", "7000", "70" )
useOnePt("/CMS_2011_S8973270/d02-x01-y01", "7000", "100" )
useOnePt("/CMS_2011_S8973270/d03-x01-y01", "7000", "130" )
useOnePt("/CMS_2011_S8973270/d04-x01-y01", "7000", "70" )
useOnePt("/CMS_2011_S8973270/d05-x01-y01", "7000", "100" )
useOnePt("/CMS_2011_S8973270/d06-x01-y01", "7000", "130" )
logging.info("Processing ATLAS_2012_I1082009")
useOnePt("/ATLAS_2012_I1082009/d08-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2012_I1082009/d09-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2012_I1082009/d10-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2012_I1082009/d11-x01-y01", "7000", "80" )
useOnePt("/ATLAS_2012_I1082009/d12-x01-y01", "7000", "80" )
useOnePt("/ATLAS_2012_I1082009/d13-x01-y01", "7000", "40" )
logging.info("Processing ATLAS_2012_I1118269")
mergeByPt("/ATLAS_2012_I1118269/d01-x01-y01", "7000")
useOnePt("/ATLAS_2012_I1118269/d02-x01-y01", "7000", "10" )
logging.info("Processing ATLAS_2012_I1188891")
mergeByPt("/ATLAS_2012_I1188891/d01-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1188891/d02-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1188891/d03-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1188891/d04-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1188891/d05-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1188891/d06-x01-y01", "7000")
logging.info("Processing CMS_2012_I1087342")
mergeByPt("/CMS_2012_I1087342/d01-x01-y01", "7000")
mergeByPt("/CMS_2012_I1087342/d02-x01-y01", "7000")
mergeByPt("/CMS_2012_I1087342/d03-x01-y01", "7000")
logging.info("Processing CMS_2012_PAS_QCD_11_010")
mergeByPt("/CMS_2012_PAS_QCD_11_010/d01-x01-y01", "7000")
mergeByPt("/CMS_2012_PAS_QCD_11_010/d02-x01-y01", "7000")
mergeByPt("/CMS_2012_PAS_QCD_11_010/d03-x01-y01", "7000")
mergeByPt("/CMS_2012_PAS_QCD_11_010/d04-x01-y01", "7000")
logging.info("Processing ATLAS_2011_S9035664")
mergeByPt("/ATLAS_2011_S9035664/d11-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d12-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d13-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d14-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d15-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d16-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d17-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d18-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d20-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d21-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d22-x01-y01", "7000")
mergeByPt("/ATLAS_2011_S9035664/d23-x01-y01", "7000")
logging.info("Processing ATLAS_2012_I1125575")
mergeByPt("/ATLAS_2012_I1125575/d01-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x01-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x02-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x02-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x03-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x03-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x04-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x04-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x05-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d01-x05-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x01-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x02-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x02-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x03-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x03-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x04-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x04-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x05-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d02-x05-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x01-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x01-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x02-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x02-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x03-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x03-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x04-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x04-y02", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x05-y01", "7000")
mergeByPt("/ATLAS_2012_I1125575/d03-x05-y02", "7000")
for d in range(4,7) :
for x in range(1,6) :
if(opts.ue) :
for y in range(1,9) :
useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y0%s" % (d,x,y), "7000", "0" )
for y in ["09","10","11","12","13","14","15","16"] :
useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y%s" % (d,x,y), "7000", "0" )
for y in range(17,19) :
useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y%s" % (d,x,y), "7000", "20" )
else :
for y in range(17,19) :
useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y%s" % (d,x,y), "7000", "10" )
for y in range(19,21) :
useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y%s" % (d,x,y), "7000", "40" )
# ATLAS_2012_I1094564
useOnePt("/ATLAS_2012_I1094564/d01-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d02-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d03-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d04-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d05-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d06-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d07-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d08-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d09-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d10-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d11-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d12-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d13-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d14-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d15-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d16-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d17-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d18-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d19-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d20-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d21-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d22-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d23-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d24-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d25-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d26-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d27-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d28-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d29-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d30-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d31-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d32-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d33-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2012_I1094564/d34-x01-y01", "7000", "260" )
useOnePt("/ATLAS_2012_I1094564/d35-x01-y01", "7000", "400" )
useOnePt("/ATLAS_2012_I1094564/d36-x01-y01", "7000", "400" )
logging.info("Processing CMS_2013_I1224539_DIJET")
useOnePt("/CMS_2013_I1224539_DIJET/d01-x01-y01", "7000", "210" )
useOnePt("/CMS_2013_I1224539_DIJET/d02-x01-y01", "7000", "260" )
useOnePt("/CMS_2013_I1224539_DIJET/d03-x01-y01", "7000", "400" )
useOnePt("/CMS_2013_I1224539_DIJET/d04-x01-y01", "7000", "400" )
useOnePt("/CMS_2013_I1224539_DIJET/d05-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d06-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d07-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d08-x01-y01", "7000", "210" )
useOnePt("/CMS_2013_I1224539_DIJET/d09-x01-y01", "7000", "260" )
useOnePt("/CMS_2013_I1224539_DIJET/d10-x01-y01", "7000", "400" )
useOnePt("/CMS_2013_I1224539_DIJET/d11-x01-y01", "7000", "400" )
useOnePt("/CMS_2013_I1224539_DIJET/d12-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d13-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d14-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d15-x01-y01", "7000", "210" )
useOnePt("/CMS_2013_I1224539_DIJET/d16-x01-y01", "7000", "260" )
useOnePt("/CMS_2013_I1224539_DIJET/d17-x01-y01", "7000", "400" )
useOnePt("/CMS_2013_I1224539_DIJET/d18-x01-y01", "7000", "400" )
useOnePt("/CMS_2013_I1224539_DIJET/d19-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d20-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d21-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d22-x01-y01", "7000", "210" )
useOnePt("/CMS_2013_I1224539_DIJET/d23-x01-y01", "7000", "260" )
useOnePt("/CMS_2013_I1224539_DIJET/d24-x01-y01", "7000", "400" )
useOnePt("/CMS_2013_I1224539_DIJET/d25-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d26-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d27-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1224539_DIJET/d28-x01-y01", "7000", "600" )
useOnePt("/CMS_2013_I1273574/d01-x01-y01", "7000", "80" )
mergeByPt("/CMS_2013_I1273574/d02-x01-y01", "7000",1.)
useOnePt("/CMS_2013_I1273574/d03-x01-y01", "7000", "80" )
useOnePt("/CMS_2013_I1273574/d04-x01-y01", "7000", "80" )
useOnePt("/CMS_2013_I1273574/d05-x01-y01", "7000", "80" )
useOnePt("/CMS_2013_I1273574/d06-x01-y01", "7000", "80" )
mergeByPt("/CMS_2013_I1273574/d07-x01-y01", "7000",1.)
useOnePt("/CMS_2013_I1273574/d08-x01-y01", "7000", "80" )
mergeByPt("/CMS_2013_I1273574/d09-x01-y01", "7000",1.)
useOnePt("/CMS_2013_I1273574/d10-x01-y01", "7000", "80" )
mergeByPt("/CMS_2013_I1273574/d11-x01-y01", "7000",1.)
useOnePt("/CMS_2013_I1261026/d01-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d02-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d03-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d04-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d05-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d06-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d07-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d08-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d09-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d10-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d11-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d12-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d13-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d14-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d15-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d16-x01-y01", "7000", "0" )
useOnePt("/CMS_2013_I1261026/d17-x01-y01", "7000", "0" )
logging.info("Processing CMS_2012_I1090423")
useOneMass("/CMS_2012_I1090423/d01-x01-y01", "7000", "2900" )
useOneMass("/CMS_2012_I1090423/d02-x01-y01", "7000", "2300" )
useOneMass("/CMS_2012_I1090423/d03-x01-y01", "7000", "1700" )
useOneMass("/CMS_2012_I1090423/d04-x01-y01", "7000", "1100" )
useOneMass("/CMS_2012_I1090423/d05-x01-y01", "7000", "1100" )
useOneMass("/CMS_2012_I1090423/d06-x01-y01", "7000", "650" )
useOneMass("/CMS_2012_I1090423/d07-x01-y01", "7000", "650" )
useOneMass("/CMS_2012_I1090423/d08-x01-y01", "7000", "250" )
useOneMass("/CMS_2012_I1090423/d09-x01-y01", "7000", "250" )
logging.info("Processing ATLAS_2014_I1298811")
mergeByPt("/ATLAS_2014_I1298811/d01-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d01-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d02-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d02-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d03-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d03-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d04-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d04-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d05-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d05-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d06-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d06-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d07-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d07-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d08-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d08-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d09-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d09-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1298811/d10-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1298811/d10-x01-y02", "7000")
useOnePt("/ATLAS_2014_I1298811/d11-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2014_I1298811/d12-x01-y01", "7000", "0" )
useOnePt("/ATLAS_2014_I1298811/d13-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d13-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d14-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d14-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d15-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d15-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d25-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d25-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d26-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d26-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d27-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d27-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d16-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d16-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d17-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d17-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d18-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d18-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d28-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d28-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d29-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d29-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d30-x01-y01", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d30-x01-y02", "7000", "4" )
useOnePt("/ATLAS_2014_I1298811/d19-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d19-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d20-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d20-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d21-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d21-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d31-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d31-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d32-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d32-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d33-x01-y01", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d33-x01-y02", "7000", "40" )
useOnePt("/ATLAS_2014_I1298811/d22-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d22-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d23-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d23-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d24-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d24-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d34-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d34-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d35-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d35-x01-y02", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d36-x01-y01", "7000", "210" )
useOnePt("/ATLAS_2014_I1298811/d36-x01-y02", "7000", "210" )
logging.info("Processing ATLAS_2014_I1268975")
mergeByMass("/ATLAS_2014_I1268975/d01-x01-y01", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d01-x01-y02", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d01-x01-y03", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d01-x01-y04", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d01-x01-y05", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d01-x01-y06", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d02-x01-y01", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d02-x01-y02", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d02-x01-y03", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d02-x01-y04", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d02-x01-y05", "7000", 1000.)
mergeByMass("/ATLAS_2014_I1268975/d02-x01-y06", "7000", 1000.)
logging.info("Processing ATLAS_2014_I1307243")
useOnePt( "/ATLAS_2014_I1307243/d01-x01-y01", "7000", "80" )
mergeByPt("/ATLAS_2014_I1307243/d02-x01-y01", "7000")
useOnePt( "/ATLAS_2014_I1307243/d03-x01-y01", "7000", "80" )
mergeByPt("/ATLAS_2014_I1307243/d04-x01-y01", "7000")
useOnePt( "/ATLAS_2014_I1307243/d05-x01-y01", "7000", "80" )
mergeByPt("/ATLAS_2014_I1307243/d06-x01-y01", "7000")
useOnePt( "/ATLAS_2014_I1307243/d07-x01-y01", "7000", "80" )
mergeByPt("/ATLAS_2014_I1307243/d08-x01-y01", "7000")
useOnePt( "/ATLAS_2014_I1307243/d09-x01-y01", "7000", "80" )
mergeByPt("/ATLAS_2014_I1307243/d10-x01-y01", "7000")
useOnePt( "/ATLAS_2014_I1307243/d11-x01-y01", "7000", "80" )
mergeByPt("/ATLAS_2014_I1307243/d12-x01-y01", "7000")
useOnePt( "/ATLAS_2014_I1307243/d13-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d14-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d15-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d16-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d17-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d18-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d19-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d20-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d21-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d22-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d23-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d24-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d25-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d26-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d27-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d28-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d29-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d30-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d31-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d32-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d33-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d34-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d35-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d36-x01-y01", "7000", "80" )
useOnePt( "/ATLAS_2014_I1307243/d37-x01-y01", "7000", "80" )
mergeByPt("/ATLAS_2014_I1307243/d38-x01-y01", "7000")
useOnePt( "/ATLAS_2014_I1307243/d39-x01-y01", "7000", "80" )
mergeByPt("/ATLAS_2014_I1307243/d40-x01-y01", "7000")
logging.info("Processing ATLAS_2014_I1325553")
mergeByPt("/ATLAS_2014_I1325553/d01-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1325553/d01-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1325553/d01-x01-y03", "7000")
mergeByPt("/ATLAS_2014_I1325553/d01-x01-y04", "7000")
mergeByPt("/ATLAS_2014_I1325553/d01-x01-y05", "7000")
mergeByPt("/ATLAS_2014_I1325553/d01-x01-y06", "7000")
mergeByPt("/ATLAS_2014_I1325553/d02-x01-y01", "7000")
mergeByPt("/ATLAS_2014_I1325553/d02-x01-y02", "7000")
mergeByPt("/ATLAS_2014_I1325553/d02-x01-y03", "7000")
mergeByPt("/ATLAS_2014_I1325553/d02-x01-y04", "7000")
mergeByPt("/ATLAS_2014_I1325553/d02-x01-y05", "7000")
mergeByPt("/ATLAS_2014_I1325553/d02-x01-y06", "7000")
logging.info("Processing ATLAS_2016_I1419070")
for i in range(1,13) :
if(i<10) :
mergeByPt("/ATLAS_2016_I1419070/d0%s-x01-y01" % i, "8000")
else :
mergeByPt("/ATLAS_2016_I1419070/d%s-x01-y01" % i, "8000")
# remake differences and sums
for ihist in range(1,4) :
if not ("/ATLAS_2016_I1419070/d0%s-x01-y01" % ihist) in outhistos :
continue
h1 = outhistos["/ATLAS_2016_I1419070/d0%s-x01-y01" % ihist ]
h2 = outhistos["/ATLAS_2016_I1419070/d0%s-x01-y01" % (ihist+3)]
sstring = "/ATLAS_2016_I1419070/d%s-x01-y01" % (9+ihist)
dstring = "/ATLAS_2016_I1419070/d0%s-x01-y01" % (6+ihist)
hdiff = yoda.Scatter2D(dstring,dstring)
hsum = yoda.Scatter2D(sstring,sstring)
outhistos[dstring]= hdiff
outhistos[sstring]= hsum
for nbin in range(0,h2.numBins) :
bsum = h1.bins[nbin]+h2.bins[nbin]
try:
ydiff = h2.bins[nbin].mean-h1.bins[nbin].mean
except:
ydiff = 0
try:
ysum = bsum.mean
bstderr = bsum.stdErr
except:
ysum = 0
bstderr = 0
try:
yerr = math.sqrt(h1.bins[nbin].stdErr**2+h2.bins[nbin].stdErr**2)
except:
yerr = 0
x = h1.bins[nbin].xMid
xerr = 0.5*h1.bins[nbin].xWidth
hdiff.addPoint(x,ydiff,xerr,yerr)
hsum.addPoint(x,ysum ,xerr,bstderr)
logging.info("ATLAS_2015_I1394679")
for i in range(1,5) :
mergeByPt("/ATLAS_2015_I1394679/d0%s-x01-y01" % i, "8000")
for i in range(5,11) :
if(i<10) :
useOnePt( "/ATLAS_2015_I1394679/d0%s-x01-y01" % i, "8000", "110" )
else :
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % i, "8000", "110" )
for i in range(0,4) :
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (11+4*i), "8000", "110" )
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (12+4*i), "8000", "260" )
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (13+4*i), "8000", "600" )
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (14+4*i), "8000", "900" )
for i in range(0,5) :
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (27+4*i), "8000", "110" )
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (28+4*i), "8000", "260" )
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (29+4*i), "8000", "400" )
useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (30+4*i), "8000", "400" )
logging.info("Processing CMS_2013_I1208923")
for i in range(1,6) :
mergeByPt ("/CMS_2013_I1208923/d01-x01-y0%s" % i, "7000")
mergeByMass("/CMS_2013_I1208923/d02-x01-y0%s" % i, "7000", 1.)
logging.info("Processing CMS_2014_I1298810")
for i in range(1,19) :
if(i<10) :
mergeByPt("/CMS_2014_I1298810/d0"+str(i)+"-x01-y01", "7000")
else :
mergeByPt("/CMS_2014_I1298810/d"+str(i)+"-x01-y01", "7000")
logging.info("Processing CMS_2014_I1305624")
for x in range(1,6) :
useOnePt( "/CMS_2014_I1305624/d01-x%02d-y01" % x, "7000", "110" )
useOnePt( "/CMS_2014_I1305624/d01-x%02d-y02" % x, "7000", "110" )
useOnePt( "/CMS_2014_I1305624/d01-x%02d-y03" % x, "7000", "260" )
useOnePt( "/CMS_2014_I1305624/d01-x%02d-y04" % x, "7000", "260" )
useOnePt( "/CMS_2014_I1305624/d01-x%02d-y05" % x, "7000", "400" )
logging.info("Processing ATLAS_2011_I929691")
for x in range(0,3) :
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 1), "7000", "20" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 2), "7000", "40" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 3), "7000", "40" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 4), "7000", "80" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 5), "7000", "110" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 6), "7000", "110" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 7), "7000", "210" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 8), "7000", "260" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 9), "7000", "260" )
useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+10), "7000", "400" )
logging.info("Processing ATLAS_2015_I1393758")
for i in range(1,13) :
mergeByPt("/ATLAS_2015_I1393758/d%02d-x01-y01" % i, "8000")
logging.info("Processing CMS_2016_I1459051")
for i in range(1,15) :
mergeByPt("/CMS_2016_I1459051/d%02d-x01-y01" % i, "13000")
logging.info("Processing ATLAS_2016_CONF_2016_092")
for i in range(1,7) :
mergeByPt("/ATLAS_2016_CONF_2016_092/d%02d-x01-y01" % i, "13000")
-aopath.find("")>0
+
+logging.info("Processing ATLAS_2017_I1609253")
+useOnePt( "/ATLAS_2017_I1609253/d01-x01-y01", "8000", "260" )
+useOnePt( "/ATLAS_2017_I1609253/d02-x01-y01", "8000", "260" )
+useOnePt( "/ATLAS_2017_I1609253/d03-x01-y01", "8000", "260" )
+useOnePt( "/ATLAS_2017_I1609253/d04-x01-y01", "8000", "260" )
+useOnePt( "/ATLAS_2017_I1609253/d05-x01-y01", "8000", "400" )
+useOnePt( "/ATLAS_2017_I1609253/d06-x01-y01", "8000", "400" )
+useOnePt( "/ATLAS_2017_I1609253/d07-x01-y01", "8000", "400" )
+useOnePt( "/ATLAS_2017_I1609253/d08-x01-y01", "8000", "400" )
+useOnePt( "/ATLAS_2017_I1609253/d09-x01-y01", "8000", "400" )
+useOnePt( "/ATLAS_2017_I1609253/d10-x01-y01", "8000", "400" )
+useOnePt( "/ATLAS_2017_I1609253/d11-x01-y01", "8000", "600" )
+useOnePt( "/ATLAS_2017_I1609253/d12-x01-y01", "8000", "600" )
+
# Choose output file
name = args[0]+"-Jets.yoda"
yoda.writeYODA(outhistos,name)
sys.exit(0)
diff --git a/Utilities/Interpolator.h b/Utilities/Interpolator.h
--- a/Utilities/Interpolator.h
+++ b/Utilities/Interpolator.h
@@ -1,218 +1,249 @@
// -*- C++ -*-
//
// Interpolator.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_Interpolator_H
#define HERWIG_Interpolator_H
//
// This is the declaration of the Interpolator class.
//
#include "ThePEG/Interface/Interfaced.h"
#include <cassert>
namespace Herwig {
using namespace ThePEG;
/** \ingroup Utilities
* \author Peter Richardson
*
* This class implments a polynominal interpolation of a table of values, it is
* based on the interpolation code in FORTRAN HERWIG.
*
*/
template <typename ValT, typename ArgT>
class Interpolator: public Interfaced {
public:
/**
* Pointer to an Interpolator
*/
typedef typename Ptr<Interpolator<ValT,ArgT> >::pointer Ptr;
/** @name Standard constructors and destructors. */
//@{
/**
* The default constructor.
*/
Interpolator() : _order(3), _copyx(5),_copyfun(5) {}
/**
* Constructor with data as vectors.
*/
Interpolator(const vector<ValT> & f,
- const vector<ArgT> & x,
- unsigned int order)
+ const vector<ArgT> & x,
+ unsigned int order)
: _fun(f.size(),0.0),_xval(x.size(),0.0),_order(order),
_funit(TypeTraits<ValT>::baseunit()),
_xunit(TypeTraits<ArgT>::baseunit()),
_copyx(order+2),_copyfun(order+2) {
assert(_order>0);
assert(x.size() == f.size());
for (size_t i = 0; i < f.size(); ++i) {
_fun [i] = f[i] / _funit;
_xval[i] = x[i] / _xunit;
}
}
+
+ /**
+ * Constructor with data as arrays.
+ */
+ template <size_t N>
+ Interpolator(const array<ValT,N> & f,
+ const array<ArgT,N> & x,
+ unsigned int order)
+ : _fun(N,0.0),_xval(N,0.0),_order(order),
+ _funit(TypeTraits<ValT>::baseunit()),
+ _xunit(TypeTraits<ArgT>::baseunit()),
+ _copyx(order+2),_copyfun(order+2) {
+ assert(_order>0);
+ for (size_t i = 0; i < N; ++i) {
+ _fun [i] = f[i] / _funit;
+ _xval[i] = x[i] / _xunit;
+ }
+ }
//@}
/**
* Constructor from bare arrays
*/
Interpolator(size_t size,
const double f[], ValT funit,
const double x[], ArgT xunit,
unsigned int order)
: _fun(size,0.0),_xval(size,0.0),_order(order),
_funit(funit),_xunit(xunit), _copyx(order+2),_copyfun(order+2) {
assert(_order>0);
for (size_t i = 0; i < size; ++i) {
_fun [i] = f[i];
_xval[i] = x[i];
}
}
//@}
/**
* Return the interpolated value
*/
ValT operator () (ArgT) const;
/** Return type for GaussianIntegrator */
typedef ValT ValType;
/** Argument type for GaussianIntegrator */
typedef ArgT ArgType;
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* The standard Init function used to initialize the interfaces.
* Called exactly once for each class by the class description system
* before the main function starts or
* when this class is dynamically loaded.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const { return new_ptr(*this); }
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const { return new_ptr(*this); }
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
Interpolator & operator=(const Interpolator &);
private:
/**
* the function values.
*/
vector<double> _fun;
/**
* The x values.
*/
vector<double> _xval;
/**
* the order of interpolation.
*/
unsigned int _order;
/**
* The Unit of the function values
*/
ValT _funit;
/**
* The Unit of the argument values
*/
ArgT _xunit;
/**
* Temporary storage vector
*/
mutable vector<double> _copyx;
/**
* Temporary storage vector
*/
mutable vector<double> _copyfun;
};
/**
* helper function to create InterpolatorPtr easily
- * (analogous to make_pair() )
+ * from bare arrays (analogous to make_pair() )
*/
template <typename ValT, typename ArgT>
inline typename Interpolator<ValT,ArgT>::Ptr
make_InterpolatorPtr(size_t size,
- const double f[], ValT funit,
- const double x[], ArgT xunit,
- unsigned int order)
+ const double f[], ValT funit,
+ const double x[], ArgT xunit,
+ unsigned int order)
{
return new_ptr(Interpolator<ValT,ArgT>(size,
- f,funit,
- x,xunit,
- order));
+ f,funit,
+ x,xunit,
+ order));
}
/**
* helper function to create InterpolatorPtr easily
- * (analogous to make_pair() )
+ * from vectors (analogous to make_pair() )
*/
template <typename ValT, typename ArgT>
inline typename Interpolator<ValT,ArgT>::Ptr
make_InterpolatorPtr(const typename std::vector<ValT> & f,
- const typename std::vector<ArgT> & x,
- unsigned int order)
+ const typename std::vector<ArgT> & x,
+ unsigned int order)
+{
+ return new_ptr(Interpolator<ValT,ArgT>(f,x,order));
+}
+
+/**
+ * helper function to create InterpolatorPtr easily
+ * from arrays (analogous to make_pair() )
+ */
+template <typename ValT, typename ArgT, size_t N>
+inline typename Interpolator<ValT,ArgT>::Ptr
+make_InterpolatorPtr(const typename std::array<ValT,N> & f,
+ const typename std::array<ArgT,N> & x,
+ unsigned int order)
{
return new_ptr(Interpolator<ValT,ArgT>(f,x,order));
}
}
#ifndef ThePEG_TEMPLATES_IN_CC_FILE
#include "Interpolator.tcc"
#endif
#endif /* HERWIG_Interpolator_H */
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -1,243 +1,245 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
AC_INIT([Herwig],[devel],[herwig@projects.hepforge.org],[Herwig])
AC_CONFIG_SRCDIR([Utilities/HerwigStrategy.cc])
AC_CONFIG_AUX_DIR([Config])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([Config/config.h])
dnl AC_PRESERVE_HELP_ORDER
AC_CANONICAL_HOST
dnl === disable debug symbols by default =====
if test "x$CXXFLAGS" = "x"; then
CXXFLAGS=-O2
fi
if test "x$CFLAGS" = "x"; then
CFLAGS=-O2
fi
AC_LANG([C++])
AM_INIT_AUTOMAKE([1.11 subdir-objects gnu dist-bzip2 no-dist-gzip -Wall -Wno-portability])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
dnl Checks for C++ compiler. Handle C++11 flags.
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX([11],[noext],[mandatory])
dnl check for POSIX
AC_CHECK_HEADER([unistd.h],[],
[AC_MSG_ERROR([Herwig needs "unistd.h". Non-POSIX systems are not supported.])])
AC_CHECK_HEADER([sys/stat.h],[],
[AC_MSG_ERROR([Herwig needs "sys/stat.h". Non-POSIX systems are not supported.])])
dnl Checks for programs.
AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_PROG_LN_S
dnl modified search order
AC_PROG_FC([gfortran g95 g77])
dnl xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn xlf90 f90 pgf90 pghpf epcf90 xlf f77 frt pgf77 cf77 fort77 fl32 af77])
AC_LANG_PUSH([Fortran])
AC_MSG_CHECKING([if the Fortran compiler ($FC) works])
AC_COMPILE_IFELSE(
AC_LANG_PROGRAM([],[ print *[,]"Hello"]),
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([A Fortran compiler is required to build Herwig.])
]
)
AC_LANG_POP([Fortran])
+AC_FC_WRAPPERS
LT_PREREQ([2.2.6])
LT_INIT([disable-static dlopen pic-only])
dnl ####################################
dnl ####################################
dnl for Doc/fixinterfaces.pl
AC_PATH_PROG(PERL, perl)
dnl for Models/Feynrules
AM_PATH_PYTHON([2.6],, [:])
AM_CONDITIONAL([HAVE_PYTHON], [test "x$PYTHON" != "x:"])
HERWIG_CHECK_GSL
HERWIG_CHECK_THEPEG
BOOST_REQUIRE([1.41])
BOOST_FIND_HEADER([boost/numeric/ublas/io.hpp])
dnl Boost 1.64 is missing a required header to make these work
dnl we just assume they're there if io.hpp has been found OK above
dnl BOOST_FIND_HEADER([boost/numeric/ublas/matrix.hpp])
dnl BOOST_FIND_HEADER([boost/numeric/ublas/matrix_proxy.hpp])
dnl BOOST_FIND_HEADER([boost/numeric/ublas/matrix_sparse.hpp])
dnl BOOST_FIND_HEADER([boost/numeric/ublas/symmetric.hpp])
dnl BOOST_FIND_HEADER([boost/numeric/ublas/vector.hpp])
BOOST_FIND_HEADER([boost/operators.hpp])
BOOST_TEST()
HERWIG_CHECK_VBFNLO
HERWIG_CHECK_NJET
HERWIG_CHECK_GOSAM
HERWIG_CHECK_GOSAM_CONTRIB
HERWIG_CHECK_OPENLOOPS
HERWIG_CHECK_MADGRAPH
HERWIG_CHECK_EVTGEN
HERWIG_CHECK_PYTHIA
HERWIG_COMPILERFLAGS
HERWIG_LOOPTOOLS
FASTJET_CHECK_FASTJET
HERWIG_ENABLE_MODELS
SHARED_FLAG=-shared
AM_CONDITIONAL(NEED_APPLE_FIXES,
[test "xx${host/darwin/foundit}xx" != "xx${host}xx"])
if test "xx${host/darwin/foundit}xx" != "xx${host}xx"; then
APPLE_DSO_FLAGS=-Wl,-undefined,dynamic_lookup
SHARED_FLAG=-bundle
fi
AC_SUBST([APPLE_DSO_FLAGS])
AC_SUBST([SHARED_FLAG])
AC_CONFIG_FILES([UnderlyingEvent/Makefile
Models/Makefile
Models/StandardModel/Makefile
Models/RSModel/Makefile
Models/General/Makefile
Models/Susy/Makefile
Models/Susy/NMSSM/Makefile
Models/Susy/RPV/Makefile
Models/UED/Makefile
Models/LH/Makefile
Models/LHTP/Makefile
Models/Transplanckian/Makefile
Models/Leptoquarks/Makefile
Models/Zprime/Makefile
Models/TTbAsymm/Makefile
Models/Feynrules/Makefile
Models/Feynrules/python/Makefile-FR
Models/ADD/Makefile
Models/Sextet/Makefile
Decay/Makefile
Decay/FormFactors/Makefile
Decay/Tau/Makefile
Decay/Baryon/Makefile
Decay/VectorMeson/Makefile
Decay/Perturbative/Makefile
Decay/ScalarMeson/Makefile
Decay/TensorMeson/Makefile
Decay/WeakCurrents/Makefile
Decay/Partonic/Makefile
Decay/General/Makefile
Decay/Radiation/Makefile
Decay/EvtGen/Makefile
Doc/refman.conf
Doc/refman.h
PDT/Makefile
PDF/Makefile
MatrixElement/Makefile
MatrixElement/General/Makefile
MatrixElement/Lepton/Makefile
MatrixElement/Hadron/Makefile
MatrixElement/DIS/Makefile
MatrixElement/Powheg/Makefile
MatrixElement/Gamma/Makefile
MatrixElement/Reweighters/Makefile
MatrixElement/EW/Makefile
MatrixElement/Matchbox/Makefile
MatrixElement/Matchbox/Base/Makefile
MatrixElement/Matchbox/Utility/Makefile
MatrixElement/Matchbox/Phasespace/Makefile
MatrixElement/Matchbox/Dipoles/Makefile
MatrixElement/Matchbox/InsertionOperators/Makefile
MatrixElement/Matchbox/Matching/Makefile
MatrixElement/Matchbox/Cuts/Makefile
MatrixElement/Matchbox/Scales/Makefile
MatrixElement/Matchbox/ColorFull/Makefile
MatrixElement/Matchbox/CVolver/Makefile
MatrixElement/Matchbox/Builtin/Makefile
MatrixElement/Matchbox/Builtin/Amplitudes/Makefile
MatrixElement/Matchbox/Tests/Makefile
MatrixElement/Matchbox/External/Makefile
MatrixElement/Matchbox/External/BLHAGeneric/Makefile
MatrixElement/Matchbox/External/VBFNLO/Makefile
MatrixElement/Matchbox/External/NJet/Makefile
MatrixElement/Matchbox/External/GoSam/Makefile
MatrixElement/Matchbox/External/OpenLoops/Makefile
MatrixElement/Matchbox/External/MadGraph/Makefile
MatrixElement/Matchbox/External/MadGraph/mg2herwig
Sampling/Makefile
Sampling/CellGrids/Makefile
Shower/Makefile
Shower/QTilde/Makefile
Shower/QTilde/Matching/Makefile
Shower/Dipole/Makefile
Shower/Dipole/Base/Makefile
Shower/Dipole/Kernels/Makefile
Shower/Dipole/Kinematics/Makefile
Shower/Dipole/Utility/Makefile
Shower/Dipole/AlphaS/Makefile
Utilities/Makefile
Utilities/XML/Makefile
Utilities/Statistics/Makefile
Hadronization/Makefile
lib/Makefile
include/Makefile
src/Makefile
src/defaults/Makefile
src/snippets/Makefile
src/Matchbox/Makefile
src/herwig-config
Doc/Makefile
Doc/HerwigDefaults.in
Looptools/Makefile
Analysis/Makefile
API/Makefile
src/Makefile-UserModules
src/defaults/Analysis.in
src/defaults/MatchboxDefaults.in
src/defaults/Decays.in
src/defaults/decayers.in
src/defaults/setup.gosam.in
src/Matchbox/LO-DefaultShower.in
src/Matchbox/LO-DipoleShower.in
src/Matchbox/MCatLO-DefaultShower.in
src/Matchbox/MCatLO-DipoleShower.in
src/Matchbox/LO-NoShower.in
src/Matchbox/MCatNLO-DefaultShower.in
src/Matchbox/MCatNLO-DipoleShower.in
src/Matchbox/NLO-NoShower.in
src/Matchbox/Powheg-DefaultShower.in
src/Matchbox/Powheg-DipoleShower.in
src/Merging/Makefile
Shower/Dipole/Merging/Makefile
+ Shower/Dipole/Colorea/Makefile
src/defaults/MatchboxMergingDefaults.in
Contrib/Makefile
Contrib/make_makefiles.sh
Tests/Makefile
Makefile])
AC_CONFIG_LINKS([Doc/BSMlibs.in:Doc/BSMlibs.in])
AC_CONFIG_FILES([Doc/fixinterfaces.pl],[chmod +x Doc/fixinterfaces.pl])
-
+AC_CONFIG_HEADERS([PDF/SaSPhotonPDF.cc])
HERWIG_OVERVIEW
AC_CONFIG_COMMANDS([summary],[cat config.herwig])
AC_OUTPUT
diff --git a/lib/Makefile.am b/lib/Makefile.am
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,49 +1,49 @@
pkglib_LTLIBRARIES = Herwig.la
Herwig_la_SOURCES =
Herwig_la_LIBTOOLFLAGS = --tag=CXX
-Herwig_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 23:0:0
-Herwig_la_LDFLAGS += $(THEPEGLDFLAGS) $(FCLIBS)
+Herwig_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 24:0:0
+Herwig_la_LDFLAGS += $(THEPEGLDFLAGS) $(BOOST_SYSTEM_LDFLAGS) $(BOOST_FILESYSTEM_LDFLAGS) $(FCLIBS)
Herwig_la_LIBADD = \
$(top_builddir)/Hadronization/libHwHadronization.la \
$(top_builddir)/Models/libHwStandardModel.la \
$(top_builddir)/Decay/libHwDecay.la \
$(top_builddir)/Decay/libHwFormFactor.la \
$(top_builddir)/Decay/libHwDecRad.la \
$(top_builddir)/Utilities/libHwUtils.la \
$(top_builddir)/Models/libHwModelGenerator.la \
$(top_builddir)/Decay/General/libHwGeneralDecay.la \
$(top_builddir)/MatrixElement/General/libHwGeneralME.la \
$(top_builddir)/MatrixElement/libHwME.la \
$(top_builddir)/MatrixElement/Reweighters/libHwReweighters.la \
$(top_builddir)/MatrixElement/Matchbox/libHwMatchbox.la \
$(top_builddir)/Decay/libHwWeakCurrent.la \
$(top_builddir)/Looptools/libHwLooptools.la \
$(top_builddir)/Shower/libHwShower.la \
$(THEPEGLIB) -ldl
dist_noinst_SCRIPTS = fix-osx-path
POSTPROCESSING = done-all-links
if NEED_APPLE_FIXES
POSTPROCESSING += apple-fixes
endif
all-local: $(POSTPROCESSING)
done-all-links: Herwig.la
find $(top_builddir) \( -name '*.so.*' -or -name '*.so' \) \
-not -name 'lib*' -not -path '$(top_builddir)/lib/*' \
-not -path '$(top_builddir)/.hg/*' -exec $(LN_S) -f \{\} \;
$(LN_S) -f .libs/Herwig*so* .
echo "stamp" > $@
apple-fixes: fix-osx-path done-all-links
./$<
echo "stamp" > $@
clean-local:
rm -f *.so *.so.* done-all-links apple-fixes
diff --git a/m4/herwig.m4 b/m4/herwig.m4
--- a/m4/herwig.m4
+++ b/m4/herwig.m4
@@ -1,900 +1,900 @@
dnl ##### THEPEG #####
AC_DEFUN([HERWIG_CHECK_THEPEG],
[
defaultlocation="${prefix}"
test "x$defaultlocation" = xNONE && defaultlocation="${ac_default_prefix}"
AC_MSG_CHECKING([for libThePEG in])
AC_ARG_WITH(thepeg,
AC_HELP_STRING([--with-thepeg=DIR],[location of ThePEG installation]),
[],
[with_thepeg="${defaultlocation}"])
AC_MSG_RESULT([$with_thepeg])
if test "x$with_thepeg" = "xno"; then
AC_MSG_ERROR([Cannot build Herwig without ThePEG. Please set --with-thepeg.])
fi
THEPEGLDFLAGS="-L${with_thepeg}/lib/ThePEG"
THEPEGHASLHAPDF="no"
if test -e ${with_thepeg}/lib/ThePEG/ThePEGLHAPDF.so ; then
THEPEGHASLHAPDF="yes"
fi
if test "${host_cpu}" == "x86_64" -a -e ${with_thepeg}/lib64/ThePEG/libThePEG.so ; then
THEPEGLDFLAGS="-L${with_thepeg}/lib64/ThePEG"
if test -e ${with_thepeg}/lib64/ThePEG/ThePEGLHAPDF.so ; then
THEPEGHASLHAPDF="yes"
fi
fi
if test "x$THEPEGHASLHAPDF" == "xno" ; then
AC_MSG_ERROR([Herwig requires ThePEG to be build with lhapdf.])
fi
THEPEGHASFASTJET="no"
if test -e ${with_thepeg}/lib/ThePEG/FastJetFinder.so ; then
THEPEGHASFASTJET="yes"
fi
if test "${host_cpu}" == "x86_64" -a -e ${with_thepeg}/lib64/ThePEG/libThePEG.so ; then
THEPEGLDFLAGS="-L${with_thepeg}/lib64/ThePEG"
if test -e ${with_thepeg}/lib64/ThePEG/FastJetFinder.so ; then
THEPEGHASFASTJET="yes"
fi
fi
if test "x$THEPEGHASFASTJET" == "xno" ; then
AC_MSG_ERROR([Herwig requires ThePEG to be build with FastJet.])
fi
THEPEGPATH="${with_thepeg}"
oldldflags="$LDFLAGS"
oldlibs="$LIBS"
LDFLAGS="$LDFLAGS $THEPEGLDFLAGS"
AC_CHECK_LIB([ThePEG],[debugThePEG],[],
[AC_MSG_ERROR([No ThePEG libraries in $THEPEGLDFLAGS. Please set --with-thepeg.])])
AC_SUBST([THEPEGLIB],[-lThePEG])
AC_SUBST(THEPEGLDFLAGS)
AC_SUBST(THEPEGPATH)
AC_SUBST(THEPEGHASLHAPDF)
AC_SUBST(THEPEGHASFASTJET)
LIBS="$oldlibs"
LDFLAGS="$oldldflags"
AC_MSG_CHECKING([for ThePEG headers in])
AC_ARG_WITH([thepeg-headers],
AC_HELP_STRING([--with-thepeg-headers=DIR],[location of ThePEG include directory]),
[],
[with_thepeg_headers="${with_thepeg}/include"])
AC_MSG_RESULT([$with_thepeg_headers])
if test "x$with_thepeg_headers" = "xno"; then
AC_MSG_ERROR([Cannot build Herwig without ThePEG headers. Please set --with-thepeg-headers.])
fi
THEPEGINCLUDE="-I$with_thepeg_headers"
oldcppflags="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $THEPEGINCLUDE"
AC_CHECK_HEADER([ThePEG/Config/ThePEG.h],[],
[AC_MSG_ERROR([No ThePEG headers in $with_thepeg_headers. Please set --with-thepeg-headers.])])
CPPFLAGS="$oldcppflags"
AC_SUBST(THEPEGINCLUDE)
AC_MSG_CHECKING([for HepMCAnalysis.so in ThePEG])
THEPEGHASHEPMC="no"
if test -e ${with_thepeg}/lib/ThePEG/HepMCAnalysis.so ; then
THEPEGHASHEPMC="yes"
fi
if test "${host_cpu}" == "x86_64" -a -e ${with_thepeg}/lib64/ThePEG/libThePEG.so ; then
THEPEGLDFLAGS="-L${with_thepeg}/lib64/ThePEG"
if test -e ${with_thepeg}/lib64/ThePEG/HepMCAnalysis.so ; then
THEPEGHASHEPMC="yes"
fi
fi
if test "x$THEPEGHASHEPMC" == "xno" ; then
CREATE_HEPMC="# create"
AC_MSG_RESULT([not found])
else
CREATE_HEPMC="create"
AC_MSG_RESULT([found])
fi
AC_SUBST([CREATE_HEPMC])
AC_MSG_CHECKING([for RivetAnalysis.so in ThePEG])
THEPEGHASRIVET="no"
if test -e ${with_thepeg}/lib/ThePEG/RivetAnalysis.so ; then
THEPEGHASRIVET="yes"
fi
if test "${host_cpu}" == "x86_64" -a -e ${with_thepeg}/lib64/ThePEG/libThePEG.so ; then
THEPEGLDFLAGS="-L${with_thepeg}/lib64/ThePEG"
if test -e ${with_thepeg}/lib64/ThePEG/RivetAnalysis.so ; then
THEPEGHASRIVET="yes"
fi
fi
if test "x$THEPEGHASRIVET" == "xno" ; then
CREATE_RIVET="# create"
AC_MSG_RESULT([not found])
else
CREATE_RIVET="create"
AC_MSG_RESULT([found])
fi
AC_SUBST([CREATE_RIVET])
])
dnl ##### LOOPTOOLS #####
AC_DEFUN([HERWIG_LOOPTOOLS],
[
AC_REQUIRE([AC_PROG_FC])
AC_REQUIRE([AC_FC_LIBRARY_LDFLAGS])
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([HERWIG_COMPILERFLAGS])
AC_MSG_CHECKING([if Looptools build works])
enable_looptools=yes
if test "x$GCC" = "xyes"; then
case "${host}" in
x86_64-*|*-darwin1*)
AM_FCFLAGS="$AM_FCFLAGS -fdefault-integer-8"
;;
esac
AC_LANG_PUSH([Fortran])
oldFCFLAGS="$FCFLAGS"
FCFLAGS="$AM_FCFLAGS"
AC_COMPILE_IFELSE(
AC_LANG_PROGRAM([],[ print *[,]"Hello"]),
[],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([needs gfortran on 64bit machines])]
)
FCFLAGS="$oldFCFLAGS"
AC_LANG_POP([Fortran])
fi
AC_MSG_RESULT([$enable_looptools])
AC_SUBST([F77],[$FC])
AC_SUBST([FFLAGS],[$FCFLAGS])
AC_SUBST([AM_FFLAGS],[$AM_FCFLAGS])
AC_SUBST([FLIBS],[$FCLIBS])
])
dnl ##### VBFNLO #####
AC_DEFUN([HERWIG_CHECK_VBFNLO],
[
AC_MSG_CHECKING([for VBFNLO])
AC_ARG_WITH([vbfnlo],
AS_HELP_STRING([--with-vbfnlo=DIR], [Installation path of VBFNLO]),
[],
[with_vbfnlo=no]
)
AC_MSG_RESULT([$with_vbfnlo])
AS_IF([test "x$with_vbfnlo" != "xno"],
[AC_CHECK_FILES(
${with_vbfnlo}/lib/VBFNLO/libVBFNLO.so,
[have_vbfnlo=lib], [have_vbfnlo=no])],
[have_vbfnlo=no])
AS_IF([test "x$with_vbfnlo" != "xno" -a "x$have_vbfnlo" = "xno" ],
[AC_CHECK_FILES(
${with_vbfnlo}/lib64/VBFNLO/libVBFNLO.so,
[have_vbfnlo=lib64], [have_vbfnlo=no])])
AS_IF([test "x$with_vbfnlo" != "xno" -a "x$have_vbfnlo" = "xno" ],
[AC_CHECK_FILES(
${with_vbfnlo}/lib/VBFNLO/libVBFNLO.dylib,
[have_vbfnlo=lib], [have_vbfnlo=no])])
AS_IF([test "x$with_vbfnlo" != "xno" -a "x$have_vbfnlo" = "xno" ],
[AC_CHECK_FILES(
${with_vbfnlo}/lib64/VBFNLO/libVBFNLO.dylib,
[have_vbfnlo=lib64], [have_vbfnlo=no])])
AS_IF([test "x$have_vbfnlo" = "xlib"],
[VBFNLOLIBS=${with_vbfnlo}/lib/VBFNLO
AC_SUBST(VBFNLOLIBS)
])
AS_IF([test "x$have_vbfnlo" = "xlib64"],
[VBFNLOLIBS=${with_vbfnlo}/lib64/VBFNLO
AC_SUBST(VBFNLOLIBS)
])
AS_IF([test "x$with_vbfnlo" != "xno" -a "x$have_vbfnlo" = "xno"],
[AC_MSG_ERROR([vbfnlo requested but not found])])
AM_CONDITIONAL(HAVE_VBFNLO,[test "x$have_vbfnlo" = "xlib" -o "x$have_vbfnlo" = "xlib64"])
if test "x$have_vbfnlo" = "xlib" -o "x$have_vbfnlo" = "xlib64" ; then
AC_REQUIRE([AC_PROG_SED])
VBFNLOINCLUDE=${with_vbfnlo}/include
AC_SUBST(VBFNLOINCLUDE)
VBFNLOLIB=$(echo ${with_vbfnlo}/${have_vbfnlo}/VBFNLO | $SED -e 's%/\+%/%g')
AC_SUBST(VBFNLOLIB)
LOAD_VBFNLO="library"
CREATE_VBFNLO="create"
INSERT_VBFNLO="insert"
SET_VBFNLO="set"
DO_VBFNLO="do"
MKDIR_VBFNLO="mkdir"
else
LOAD_VBFNLO="# library"
CREATE_VBFNLO="# create"
INSERT_VBFNLO="# insert"
SET_VBFNLO="# set"
DO_VBFNLO="# do"
MKDIR_VBFNLO="# mkdir"
fi
AC_SUBST([LOAD_VBFNLO])
AC_SUBST([CREATE_VBFNLO])
AC_SUBST([INSERT_VBFNLO])
AC_SUBST([SET_VBFNLO])
AC_SUBST([DO_VBFNLO])
AC_SUBST([MKDIR_VBFNLO])
])
dnl ##### njet #####
AC_DEFUN([HERWIG_CHECK_NJET],
[
AC_MSG_CHECKING([for njet])
AC_ARG_WITH([njet],
AS_HELP_STRING([--with-njet=DIR], [Installation path of njet]),
[],
[with_njet=no]
)
AC_MSG_RESULT([$with_njet])
AS_IF([test "x$with_njet" != "xno"],
[AC_CHECK_FILES(
${with_njet}/lib/libnjet2.so,
[have_njet=lib], [have_njet=no])],
[have_njet=no])
AS_IF([test "x$with_njet" != "xno" -a "x$have_njet" = "xno" ],
[AC_CHECK_FILES(
${with_njet}/lib64/libnjet2.so,
[have_njet=lib64], [have_njet=no])])
AS_IF([test "x$with_njet" != "xno" -a "x$have_njet" = "xno" ],
[AC_CHECK_FILES(
${with_njet}/lib/libnjet2.dylib,
[have_njet=lib], [have_njet=no])])
AS_IF([test "x$have_njet" = "xlib"],
[NJETLIBPATH=${with_njet}/lib
AC_SUBST(NJETLIBPATH)
NJETINCLUDEPATH=${with_njet}/include
AC_SUBST(NJETINCLUDEPATH)
NJETPREFIX=${with_njet}
AC_SUBST(NJETPREFIX)
])
AS_IF([test "x$have_njet" = "xlib64"],
[NJETLIBPATH=${with_njet}/lib64
AC_SUBST(NJETLIBPATH)
NJETINCLUDEPATH=${with_njet}/include
AC_SUBST(NJETINCLUDEPATH)
NJETPREFIX=${with_njet}
AC_SUBST(NJETPREFIX)
])
AS_IF([test "x$with_njet" != "xno" -a "x$have_njet" = "xno"],
[AC_MSG_ERROR([njet requested but not found])])
AM_CONDITIONAL(HAVE_NJET,[test "x$have_njet" = "xlib" -o "x$have_njet" = "xlib64"])
if test "x$have_njet" = "xlib" -o "x$have_njet" = "xlib64" ; then
LOAD_NJET="library"
CREATE_NJET="create"
INSERT_NJET="insert"
DO_NJET="do"
else
LOAD_NJET="# library"
CREATE_NJET="# create"
INSERT_NJET="# insert"
DO_NJET="# do"
fi
AC_SUBST([LOAD_NJET])
AC_SUBST([CREATE_NJET])
AC_SUBST([INSERT_NJET])
AC_SUBST([DO_NJET])
])
dnl ##### gosam #####
AC_DEFUN([HERWIG_CHECK_GOSAM],
[
AC_MSG_CHECKING([for GoSam])
AC_ARG_WITH([gosam],
AS_HELP_STRING([--with-gosam=DIR], [Installation path of GoSam]),
[],
[with_gosam=no]
)
AC_MSG_RESULT([$with_gosam])
AS_IF([test "x$with_gosam" != "xno"],
[AC_CHECK_FILES(
${with_gosam}/bin/gosam.py,
[have_gosam=lib], [have_gosam=no])],
[have_gosam=no])
AS_IF([test "x$have_gosam" = "xlib"],
[GOSAMPREFIX=${with_gosam}
AC_SUBST(GOSAMPREFIX)
])
AS_IF([test "x$with_gosam" != "xno" -a "x$have_gosam" = "xno"],
[AC_MSG_ERROR([GoSam requested but not found])])
AS_IF([test "x$with_gosam" != "xno"],
[AC_MSG_CHECKING([for GoSam version >= 2.0.4])
tmp_gosamversion=[$(${with_gosam}/bin/gosam.py --version | grep 'GoSam.*rev' | cut -d' ' -f2)]
AX_COMPARE_VERSION([${tmp_gosamversion}],[lt],[2.0.4],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([Herwig requires GoSam 2.0.4 or later, found ${tmp_gosamversion}])],
[AC_MSG_RESULT([yes])])])
AM_CONDITIONAL(HAVE_GOSAM,[test "x$have_gosam" = "xlib" ])
if test "x$have_gosam" = "xlib" ; then
LOAD_GOSAM="library"
CREATE_GOSAM="create"
INSERT_GOSAM="insert"
DO_GOSAM="do"
else
LOAD_GOSAM="# library"
CREATE_GOSAM="# create"
INSERT_GOSAM="# insert"
DO_GOSAM="# do"
fi
AC_SUBST([LOAD_GOSAM])
AC_SUBST([CREATE_GOSAM])
AC_SUBST([INSERT_GOSAM])
AC_SUBST([DO_GOSAM])
])
dnl ##### gosam-contrib #####
AC_DEFUN([HERWIG_CHECK_GOSAM_CONTRIB],
[
AC_MSG_CHECKING([for gosam-contrib])
AC_ARG_WITH([gosam-contrib],
AS_HELP_STRING([--with-gosam-contrib=DIR], [Installation path of gosam-contrib]),
[],
[with_gosam_contrib=no]
)
AC_MSG_RESULT([$with_gosam_contrib])
AS_IF([test "x$with_gosam_contrib" = "xno" -a "x$with_gosam" != "xno"],
[AC_CHECK_FILES(
${with_gosam}/lib/libsamurai.so,
[with_gosam_contrib=${with_gosam}], [])
])
AS_IF([test "x$with_gosam_contrib" = "xno" -a "x$with_gosam" != "xno"],
[AC_CHECK_FILES(
${with_gosam}/lib64/libsamurai.so,
[with_gosam_contrib=${with_gosam}], [])
])
AS_IF([test "x$with_gosam_contrib" = "xno" -a "x$with_gosam" != "xno"],
[AC_CHECK_FILES(
${with_gosam}/lib/libsamurai.dylib,
[with_gosam_contrib=${with_gosam}], [])
])
AS_IF([test "x$with_gosam_contrib" = "xno" -a "x$with_gosam" != "xno"],
[AC_CHECK_FILES(
${with_gosam}/lib64/libsamurai.dylib,
[with_gosam_contrib=${with_gosam}], [])
])
AS_IF([test "x$with_gosam_contrib" = "xno" -a "x$with_gosam" != "xno"],
[AC_MSG_ERROR([GoSam requested without requesting GoSam-Contrib])])
AS_IF([test "x$with_gosam_contrib" != "xno"],
[AC_CHECK_FILES(
${with_gosam_contrib}/lib/libsamurai.so,
[have_gosam_contrib=lib], [have_gosam_contrib=no])],
[have_gosam_contrib=no])
AS_IF([test "x$with_gosam_contrib" != "xno" -a "x$have_gosam_contrib" = "xno" ],
[AC_CHECK_FILES(
${with_gosam_contrib}/lib64/libsamurai.so,
[have_gosam_contrib=lib64], [have_gosam_contrib=no])])
AS_IF([test "x$with_gosam_contrib" != "xno" -a "x$have_gosam_contrib" = "xno" ],
[AC_CHECK_FILES(
${with_gosam_contrib}/lib/libsamurai.dylib,
[have_gosam_contrib=lib], [have_gosam_contrib=no])])
AS_IF([test "x$with_gosam_contrib" != "xno" -a "x$have_gosam_contrib" = "xno" ],
[AC_CHECK_FILES(
${with_gosam_contrib}/lib64/libsamurai.dylib,
[have_gosam_contrib=lib64], [have_gosam_contrib=no])])
AS_IF([test "x$have_gosam_contrib" != "xno"],
[GOSAMCONTRIBPREFIX=${with_gosam_contrib}
AC_SUBST(GOSAMCONTRIBPREFIX)
])
AS_IF([test "x$have_gosam_contrib" = "xlib"],
[GOSAMCONTRIBLIBS=${with_gosam_contrib}/lib
AC_SUBST(GOSAMCONTRIBLIBS)
])
AS_IF([test "x$have_gosam_contrib" = "xlib64"],
[GOSAMCONTRIBLIBS=${with_gosam_contrib}/lib64
AC_SUBST(GOSAMCONTRIBLIBS)
])
AS_IF([test "x$with_gosam_contrib" != "xno" -a "x$have_gosam_contrib" = "xno"],
[AC_MSG_ERROR([GoSam-Contrib requested but not found])])
AM_CONDITIONAL(HAVE_GOSAM_CONTRIB,[test "x$have_gosam_contrib" = "xlib" -o "x$have_gosam_contrib" = "xlib64"])
if test "x$have_gosam_contrib" = "xlib" -o "x$have_gosam_contrib" = "xlib64" ; then
LOAD_GOSAM_CONTRIB="library"
CREATE_GOSAM_CONTRIB="create"
INSERT_GOSAM_CONTRIB="insert"
else
LOAD_GOSAM_CONTRIB="# library"
CREATE_GOSAM_CONTRIB="# create"
INSERT_GOSAM_CONTRIB="# insert"
fi
AC_SUBST([LOAD_GOSAM_CONTRIB])
AC_SUBST([CREATE_GOSAM_CONTRIB])
AC_SUBST([INSERT_GOSAM_CONTRIB])
])
dnl ##### OpenLoops #####
AC_DEFUN([HERWIG_CHECK_OPENLOOPS],
[
AC_MSG_CHECKING([for OpenLoops])
AC_ARG_WITH([openloops],
AS_HELP_STRING([--with-openloops=DIR], [Installation path of OpenLoops]),
[],
[with_openloops=no]
)
AC_MSG_RESULT([$with_openloops])
AS_IF([test "x$with_openloops" != "xno"],
[AC_CHECK_FILES(
${with_openloops}/lib/libopenloops.so,
[have_openloops=lib], [have_openloops=no])],
[have_openloops=no])
AS_IF([test "x$with_openloops" != "xno" -a "x$have_openloops" = "xno" ],
[AC_CHECK_FILES(
${with_openloops}/lib/libopenloops.dylib,
[have_openloops=lib], [have_openloops=no])])
AS_IF([test "x$with_openloops" != "xno" -a "x$have_openloops" = "xno" ],
[AC_CHECK_FILES(
${with_openloops}/lib64/libopenloops.so,
[have_openloops=lib64], [have_openloops=no])])
AS_IF([test "x$with_openloops" != "xno" -a "x$have_openloops" = "xno" ],
[AC_CHECK_FILES(
${with_openloops}/lib64/libopenloops.dylib,
[have_openloops=lib64], [have_openloops=no])])
AS_IF([test "x$have_openloops" = "xlib"],
[OPENLOOPSLIBS=${with_openloops}/lib
AC_SUBST(OPENLOOPSLIBS)
])
AS_IF([test "x$have_openloops" = "xlib64"],
[OPENLOOPSLIBS=${with_openloops}/lib64
AC_SUBST(OPENLOOPSLIBS)
])
AS_IF([test "x$with_openloops" != "xno" -a "x$have_openloops" = "xno"],
[AC_MSG_ERROR([OpenLoops requested but not found])])
AM_CONDITIONAL(HAVE_OPENLOOPS,[test "x$have_openloops" = "xlib" -o "x$have_openloops" = "xlib64"])
if test "x$have_openloops" = "xlib" -o "x$have_openloops" = "xlib64" ; then
OPENLOOPSPREFIX=${with_openloops}
LOAD_OPENLOOPS="library"
CREATE_OPENLOOPS="create"
INSERT_OPENLOOPS="insert"
SET_OPENLOOPS="set"
DO_OPENLOOPS="do"
MKDIR_OPENLOOPS="mkdir"
else
LOAD_OPENLOOPS="# library"
CREATE_OPENLOOPS="# create"
INSERT_OPENLOOPS="# insert"
SET_OPENLOOPS="# set"
DO_OPENLOOPS="# do"
MKDIR_OPENLOOPS="# mkdir"
fi
AC_SUBST([OPENLOOPSPREFIX])
AC_SUBST([LOAD_OPENLOOPS])
AC_SUBST([CREATE_OPENLOOPS])
AC_SUBST([INSERT_OPENLOOPS])
AC_SUBST([SET_OPENLOOPS])
AC_SUBST([DO_OPENLOOPS])
AC_SUBST([MKDIR_OPENLOOPS])
])
#########################################
dnl ##### madgraph #####
AC_DEFUN([HERWIG_CHECK_MADGRAPH],
[
AC_MSG_CHECKING([for MadGraph])
AC_ARG_WITH([madgraph],
AS_HELP_STRING([--with-madgraph=DIR], [Installation path of MadGraph]),
[],
[with_madgraph=no]
)
AC_MSG_RESULT([$with_madgraph])
AS_IF([test "x$with_madgraph" != "xno"],
[AC_CHECK_FILES(
${with_madgraph}/bin/mg5_aMC,
[have_madgraph=yes], [have_madgraph=no])],
[have_madgraph=no])
AS_IF([test "x$have_madgraph" = "xyes"],
[MADGRAPHPREFIX=${with_madgraph}
AC_SUBST(MADGRAPHPREFIX)
])
AS_IF([test "x$with_madgraph" != "xno" -a "x$have_madgraph" = "xno"],
[AC_MSG_ERROR([MadGraph requested but not found])])
AM_CONDITIONAL(HAVE_MADGRAPH,[test "x$have_madgraph" = "xyes" ])
if test "x$have_madgraph" = "xyes" ; then
LOAD_MADGRAPH="library"
CREATE_MADGRAPH="create"
INSERT_MADGRAPH="insert"
SET_MADGRAPH="set"
DO_MADGRAPH="do"
else
LOAD_MADGRAPH="# library"
CREATE_MADGRAPH="# create"
INSERT_MADGRAPH="# insert"
SET_MADGRAPH="# set"
DO_MADGRAPH="# do"
fi
AC_SUBST([LOAD_MADGRAPH])
AC_SUBST([CREATE_MADGRAPH])
AC_SUBST([INSERT_MADGRAPH])
AC_SUBST([SET_MADGRAPH])
AC_SUBST([DO_MADGRAPH])
])
dnl ##### EvtGen #####
AC_DEFUN([HERWIG_CHECK_EVTGEN],
[
AC_MSG_CHECKING([for evtgen])
AC_ARG_WITH([evtgen],
AS_HELP_STRING([--with-evtgen=DIR], [Installation path of EvtGen]),
[],
[with_evtgen=no]
)
AC_MSG_RESULT([$with_evtgen])
AS_IF([test "x$with_evtgen" != "xno"],
[AC_CHECK_FILES(
${with_evtgen}/lib/libEvtGenExternal.so,
[have_evtgen=lib], [have_evtgen=no])],
[have_evtgen=no])
AS_IF([test "x$with_evtgen" != "xno" -a "x$have_evtgen" = "xno"],
[AC_CHECK_FILES(
${with_evtgen}/lib64/libEvtGenExternal.so,
[have_evtgen=lib64], [have_evtgen=no])])
AS_IF([test "x$with_evtgen" != "xno" -a "x$have_evtgen" = "xno" ],
[AC_CHECK_FILES(
${with_evtgen}/lib/libEvtGenExternal.dylib,
[have_evtgen=lib], [have_evtgen=no])])
AS_IF([test "x$have_evtgen" = "xlib" -o "x$have_evtgen" = "xlib64" ],
[EVTGENPREFIX=${with_evtgen}
AC_SUBST(EVTGENPREFIX)
])
AS_IF([test "x$with_evtgen" != "xno" -a "x$have_evtgen" = "xno"],
[AC_MSG_ERROR([EvtGen requested but not found])])
AC_SUBST([EVTGENINCLUDE],[-I$EVTGENPREFIX/include])
-AM_CONDITIONAL(HAVE_EVTGEN,[test "x$have_evtgen" = "xlib" ])
+AM_CONDITIONAL(HAVE_EVTGEN,[test "x$have_evtgen" = "xlib" -o "x$have_evtgen" = "xlib64"])
if test "x$have_evtgen" = "xlib" ; then
LOAD_EVTGEN_DECAYS="read EvtGenBDecays.in"
LOAD_EVTGEN_DECAYER="read EvtGenDecayer.in"
EVTGENLIBS="-L$with_evtgen/lib -lEvtGen -lEvtGenExternal"
elif test "x$have_evtgen" = "xlib64" ; then
LOAD_EVTGEN_DECAYS="read EvtGenBDecays.in"
LOAD_EVTGEN_DECAYER="read EvtGenDecayer.in"
EVTGENLIBS="-L$with_evtgen/lib64 -lEvtGen -lEvtGenExternal"
else
LOAD_EVTGEN_DECAYS="read HerwigBDecays.in"
LOAD_EVTGEN_DECAYER="#read EvtGenDecayer.in"
EVTGENLIBS=""
fi
AC_SUBST([LOAD_EVTGEN_DECAYS])
AC_SUBST([LOAD_EVTGEN_DECAYER])
AC_SUBST([EVTGENLIBS])
])
AC_DEFUN([HERWIG_CHECK_PYTHIA],
[
dnl check if a directory is specified for Pythia
AC_ARG_WITH(pythia,
[AC_HELP_STRING([--with-pythia=dir],
[Assume the given directory for Pythia])])
dnl search for the pythia-config script
if test "$with_pythia" = ""; then
AC_PATH_PROG(pythiaconfig, pythia8-config, no)
else
AC_PATH_PROG(pythiaconfig, pythia8-config, no, ${with_pythia}/bin)
fi
if test "${pythiaconfig}" = "no"; then
AC_MSG_CHECKING(Pythia)
AC_MSG_RESULT(no);
# $2
else
PYTHIA8DATA=`${pythiaconfig} --datadir`/xmldoc
fi
AC_SUBST(PYTHIA8DATA)
])
dnl CHECK PYTHIA END
dnl ###### GSL ######
AC_DEFUN([HERWIG_CHECK_GSL],
[
AC_MSG_CHECKING([for gsl location])
GSLINCLUDE=""
GSLLIBS=""
AC_ARG_WITH(gsl,
AC_HELP_STRING([--with-gsl=DIR],[location of gsl installation @<:@default=system libs@:>@]),
[],
[with_gsl=system])
if test "x$with_gsl" = "xno"; then
AC_MSG_ERROR([libgsl is required. Please install the GNU scientific library and header files.])
fi
if test "x$with_gsl" = "xsystem"; then
AC_MSG_RESULT([in system libraries])
oldlibs="$LIBS"
AC_CHECK_LIB(m,main)
AC_CHECK_LIB(gslcblas,main)
AC_CHECK_LIB(gsl,main,[],
[
AC_MSG_ERROR([Cannot find libgsl. Please install the GNU scientific library and header files or use --with-gsl=.])
]
)
GSLLIBS="$LIBS"
GSLPATH="$with_gsl"
LIBS=$oldlibs
else
if test "`uname -m`" = "x86_64" -a -e "$with_gsl/lib64/libgsl.a" -a -d "$with_gsl/include/gsl"; then
AC_MSG_RESULT([found in $with_gsl])
GSLLIBS="-L$with_gsl/lib64 -R$with_gsl/lib64 -lgslcblas -lgsl"
GSLINCLUDE="-I$with_gsl/include"
GSLPATH="$with_gsl"
elif test -e "$with_gsl/lib/libgsl.a" -a -d "$with_gsl/include/gsl"; then
AC_MSG_RESULT([found in $with_gsl])
GSLLIBS="-L$with_gsl/lib -R$with_gsl/lib -lgslcblas -lgsl"
GSLINCLUDE="-I$with_gsl/include"
GSLPATH="$with_gsl"
else
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Can't find $with_gsl/lib/libgsl.a or the headers in $with_gsl/include])
fi
fi
AC_SUBST(GSLINCLUDE)
AC_SUBST(GSLLIBS)
AC_SUBST(GSLPATH)
])
dnl ##### COMPILERFLAGS #####
AC_DEFUN([HERWIG_COMPILERFLAGS],
[
AC_REQUIRE([HERWIG_CHECK_GSL])
AC_REQUIRE([HERWIG_CHECK_THEPEG])
AC_REQUIRE([BOOST_REQUIRE])
AC_REQUIRE([AX_COMPILER_VENDOR])
AM_CPPFLAGS="-I\$(top_builddir)/include $THEPEGINCLUDE \$(GSLINCLUDE) \$(BOOST_CPPFLAGS)"
AC_MSG_CHECKING([for debugging mode])
AC_ARG_ENABLE(debug,
AC_HELP_STRING([--enable-debug],[debug mode, use --enable-debug=slow for additional options that slow down the run.]),
[],
[enable_debug=no]
)
AC_MSG_RESULT([$enable_debug])
if test "x$enable_debug" = "xno"; then
debugflags=""
else
debugflags="-g"
fi
dnl -Wfloat-equal -fvisibility-inlines-hidden -Wctor-dtor-privacy -Weffc++
if test -n "$GCC"; then
warnflags="-pedantic -Wall -Wextra -Wno-overloaded-virtual"
if test "x$enable_debug" = "xslow"; then
debugflags="$debugflags -fno-inline"
AM_CPPFLAGS="$AM_CPPFLAGS -D_GLIBCXX_DEBUG"
fi
fi
dnl do an actual capability check on ld instead of this workaround
case "${host}" in
*-darwin*)
;;
*)
AM_LDFLAGS="-Wl,--enable-new-dtags"
;;
esac
case "${ax_cv_cxx_compiler_vendor}" in
gnu)
AM_CXXFLAGS="-pedantic -Wall -W"
;;
clang)
AM_CXXFLAGS="-pedantic -Wall -Wno-overloaded-virtual -Wno-unused-function -Wno-unused-parameter"
dnl -Wno-unneeded-internal-declaration
;;
intel)
AM_CXXFLAGS="-strict-ansi -Wall -wd13000,1418,981,444,383,1599,1572,2259,980"
;;
esac
AC_SUBST(AM_CPPFLAGS)
AC_SUBST(AM_CFLAGS, ["$warnflags $debugflags"])
AC_SUBST(AM_CXXFLAGS,["$AM_CXXFLAGS $warnflags $debugflags"])
AC_SUBST(AM_FCFLAGS, ["$debugflags"])
AC_SUBST(AM_LDFLAGS)
])
AC_DEFUN([HERWIG_ENABLE_MODELS],
[
AC_MSG_CHECKING([if BSM models should be built])
AC_ARG_ENABLE(models,
AC_HELP_STRING([--disable-models],[Turn off compilation of BSM models.]),
[],
[enable_models=yes]
)
AC_MSG_RESULT([$enable_models])
LOAD_BSM=""
if test "$enable_models" = "yes"; then
LOAD_BSM="read BSMlibs.in"
fi
AC_SUBST(LOAD_BSM)
AM_CONDITIONAL(WANT_BSM,[test "$enable_models" = "yes"])
])
AC_DEFUN([HERWIG_OVERVIEW],
[
FCSTRING=`$FC --version | head -1`
CXXSTRING=`$CXX --version | head -1`
CCSTRING=`$CC --version | head -1`
if test "x$PYTHON" != "x:"
then
python_was_found="yes, using Python $PYTHON_VERSION"
else
python_was_found="no, requires Python >= 2.6"
fi
cat << _HW_EOF_ > config.herwig
*****************************************************
*** $PACKAGE_STRING configuration summary
*** Please include this information in bug reports!
***--------------------------------------------------
*** Prefix: $prefix
***
*** BSM models: $enable_models
*** UFO converter: ${python_was_found}
***
*** Herwig debug mode: $enable_debug
***
*** ThePEG: $with_thepeg
*** ThePEG headers: $with_thepeg_headers
***
*** GoSam: $with_gosam
*** GoSam-Contrib: $with_gosam_contrib
*** MadGraph: $with_madgraph
*** njet: $with_njet
*** OpenLoops: $with_openloops
*** VBFNLO: $with_vbfnlo
***
*** EvtGen: $with_evtgen
*** GSL: $with_gsl
*** boost: ${BOOST_CPPFLAGS:-system}
*** Fastjet: ${fjconfig}
***
*** Host: $host
*** CC: $CCSTRING
*** CXX: $CXXSTRING
*** FC: $FCSTRING
***
*** CXXFLAGS: $CXXFLAGS
*****************************************************
_HW_EOF_
])
diff --git a/src/LEP-Matchbox.in b/src/LEP-Matchbox.in
--- a/src/LEP-Matchbox.in
+++ b/src/LEP-Matchbox.in
@@ -1,144 +1,144 @@
# -*- ThePEG-repository -*-
##################################################
## Herwig/Matchbox example input file
##################################################
##################################################
## Collider type
##################################################
read snippets/Matchbox.in
read snippets/EECollider.in
##################################################
## Beam energy sqrt(s)
##################################################
cd /Herwig/EventHandlers
set EventHandler:LuminosityFunction:Energy 91.2*GeV
##################################################
## Process selection
##################################################
## Note that event generation may fail if no matching matrix element has
## been found. Coupling orders are with respect to the Born process,
## i.e. NLO QCD does not require an additional power of alphas.
## Model assumptions
read Matchbox/StandardModelLike.in
read Matchbox/DiagonalCKM.in
## Set the order of the couplings
cd /Herwig/MatrixElements/Matchbox
set Factory:OrderInAlphaS 0
set Factory:OrderInAlphaEW 2
## Select the process
## You may use identifiers such as p, pbar, j, l, mu+, h0 etc.
do Factory:Process e- e+ -> j j
## Special settings required for on-shell production of unstable particles
## enable for on-shell top production
# read Matchbox/OnShellTopProduction.in
## enable for on-shell W, Z or h production
# read Matchbox/OnShellWProduction.in
# read Matchbox/OnShellZProduction.in
# read Matchbox/OnShellHProduction.in
##################################################
## Matrix element library selection
##################################################
## Select a generic tree/loop combination or a
## specialized NLO package
# read Matchbox/MadGraph-GoSam.in
# read Matchbox/MadGraph-MadGraph.in
# read Matchbox/MadGraph-NJet.in
-read Matchbox/MadGraph-OpenLoops.in
+# read Matchbox/MadGraph-OpenLoops.in
## Uncomment this to use ggh effective couplings
## currently only supported by MadGraph-GoSam
# read Matchbox/HiggsEffective.in
##################################################
## Cut selection
## See the documentation for more options
##################################################
## cuts on additional jets
# cd /Herwig/Cuts
# read Matchbox/DefaultEEJets.in
# set NJetsCut:NJetsMin 3
##################################################
## Scale choice
## See the documentation for more options
##################################################
cd /Herwig/MatrixElements/Matchbox
set Factory:ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/SHatScale
##################################################
## Matching and shower selection
##################################################
read Matchbox/MCatNLO-DefaultShower.in
# read Matchbox/Powheg-DefaultShower.in
## use for strict LO/NLO comparisons
# read Matchbox/MCatLO-DefaultShower.in
## use for improved LO showering
# read Matchbox/LO-DefaultShower.in
# read Matchbox/MCatNLO-DipoleShower.in
# read Matchbox/Powheg-DipoleShower.in
## use for strict LO/NLO comparisons
# read Matchbox/MCatLO-DipoleShower.in
## use for improved LO showering
# read Matchbox/LO-DipoleShower.in
# read Matchbox/NLO-NoShower.in
# read Matchbox/LO-NoShower.in
##################################################
## Scale uncertainties
##################################################
# read Matchbox/MuDown.in
# read Matchbox/MuUp.in
##################################################
## Shower scale uncertainties
##################################################
# read Matchbox/MuQDown.in
# read Matchbox/MuQUp.in
##################################################
## Analyses
##################################################
# cd /Herwig/Analysis
# insert Rivet:Analyses 0 XXX_2015_ABC123
# insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 Rivet
# insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 HepMC
##################################################
## Do not apply profile scales for LEP as hard
## scale coincides with kinematic limit
##################################################
set /Herwig/Shower/ShowerHandler:HardScaleProfile NULL
set /Herwig/DipoleShower/DipoleShowerHandler:HardScaleProfile NULL
##################################################
## Save the generator
##################################################
do /Herwig/MatrixElements/Matchbox/Factory:ProductionMode
cd /Herwig/Generators
saverun LEP-Matchbox EventGenerator
diff --git a/src/LHC-MB.in b/src/LHC-MB.in
--- a/src/LHC-MB.in
+++ b/src/LHC-MB.in
@@ -1,61 +1,69 @@
# -*- ThePEG-repository -*-
################################################################################
# This file contains our best tune to UE data from ATLAS at 7 TeV. More recent
# tunes and tunes for other centre-of-mass energies as well as more usage
# instructions can be obtained from this Herwig wiki page:
# http://projects.hepforge.org/herwig/trac/wiki/MB_UE_tunes
# The model for soft interactions and diffractions is explained in
# [S. Gieseke, P. Kirchgaesser, F. Loshaj, arXiv:1612.04701]
################################################################################
read snippets/PPCollider.in
##################################################
# Technical parameters for this run
##################################################
cd /Herwig/Generators
##################################################
# LHC physics parameters (override defaults here)
##################################################
set EventGenerator:EventHandler:LuminosityFunction:Energy 7000.0
# Minimum Bias
read snippets/MB.in
# Read in parameters of the soft model recommended for MB/UE simulations
read snippets/SoftTune.in
# Diffraction model
read snippets/Diffraction.in
+# Read in snippet in order to use baryonic reconnection model with modified gluon splitting (uds)
+# For more details see [S. Gieseke, P. Kirchgaeßer, S. Plätzer. arXiv:1710.10906]]
+##############################################################################################
+
+# read snippets/BaryonicReconnection.in
+
+
##################################################
# Analyses
##################################################
+
# cd /Herwig/Analysis
# create ThePEG::RivetAnalysis RivetAnalysis RivetAnalysis.so
# cd /Herwig/Generators
# insert EventGenerator:AnalysisHandlers 0 /Herwig/Analysis/RivetAnalysis
# insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_20XX_XXXXXXX
#set /Herwig/Analysis/Plot:EventNumber 54
#cd /Herwig/Generators
#insert EventGenerator:AnalysisHandlers 0 /Herwig/Analysis/Plot
#insert EventGenerator:AnalysisHandlers 0 /Herwig/Analysis/HepMCFile
#set /Herwig/Analysis/HepMCFile:PrintEvent 1000000
#set /Herwig/Analysis/HepMCFile:Format GenEvent
#set /Herwig/Analysis/HepMCFile:Units GeV_mm
#set /Herwig/Analysis/HepMCFile:Filename events.fifo
##################################################
# Save run for later usage with 'Herwig run'
##################################################
cd /Herwig/Generators
saverun LHC-MB EventGenerator
diff --git a/src/LHC-ResolvedGammaGamma.in b/src/LHC-ResolvedGammaGamma.in
new file mode 100644
--- /dev/null
+++ b/src/LHC-ResolvedGammaGamma.in
@@ -0,0 +1,73 @@
+# -*- ThePEG-repository -*-
+
+##################################################
+# Example generator based on LEP parameters
+# usage: Herwig read LEP.in
+##################################################
+
+read snippets/PPCollider.in
+
+##################################################
+# Technical parameters for this run
+##################################################
+cd /Herwig/Generators
+set EventGenerator:EventHandler:Sampler:Ntry 10000
+
+##################################################
+# Choice of phase-space generation for PDFs
+##################################################
+set /Herwig/Partons/PPExtractor:FlatSHatY 0
+
+##################################################
+# Change the proton PDFs to those for photon radiation
+##################################################
+set /Herwig/Particles/p+:PDF /Herwig/Partons/BudnevPDF
+set /Herwig/Particles/pbar-:PDF /Herwig/Partons/BudnevPDF
+set /Herwig/Partons/PPExtractor:FirstPDF /Herwig/Partons/BudnevPDF
+set /Herwig/Partons/PPExtractor:SecondPDF /Herwig/Partons/BudnevPDF
+
+set /Herwig/Shower/ShowerHandler:PDFA /Herwig/Partons/SaSPDF
+set /Herwig/Shower/ShowerHandler:PDFB /Herwig/Partons/SaSPDF
+set /Herwig/Particles/gamma:PDF /Herwig/Partons/SaSPDF
+
+
+##################################################
+# Cuts
+##################################################
+cd /Herwig/Cuts
+set Cuts:ScaleMin 0.0
+set Cuts:X1Min 0
+set Cuts:X2Min 0
+set Cuts:X1Max 1.
+set Cuts:X2Max 1.
+set Cuts:MHatMin 1.*GeV
+erase Cuts:MultiCuts 0
+set LeptonKtCut:MinKT 3*GeV
+
+##################################################
+# Selected the hard process
+##################################################
+cd /Herwig/MatrixElements
+
+# fermion-antifermion
+insert SubProcess:MatrixElements 0 /Herwig/MatrixElements/MEqq2gZ2ff
+
+##################################################
+# LHC physics parameters (override defaults)
+##################################################
+cd /Herwig/Generators
+set EventGenerator:EventHandler:CascadeHandler:MPIHandler NULL
+
+##################################################
+## prepare for Rivet analysis or HepMC output
+## when running with parton shower
+##################################################
+#read snippets/Rivet.in
+#insert /Herwig/Analysis/Rivet:Analyses 0 XXX_2015_ABC123
+#read snippets/HepMC.in
+#set /Herwig/Analysis/HepMC:PrintEvent NNN
+
+###################################################
+# Save run for later usage with 'Herwig run'
+##################################################
+saverun LHC-ResolvedGammaGamma EventGenerator
diff --git a/src/Makefile.am b/src/Makefile.am
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,225 +1,226 @@
SUBDIRS = defaults snippets Matchbox Merging
defaultsdir = ${pkgdatadir}/defaults
bin_PROGRAMS = Herwig
Herwig_SOURCES = \
HerwigMain.cc HerwigCLI.cc HerwigCLI.h \
herwigopts.c herwigopts.h
BUILT_SOURCES = herwigopts.c herwigopts.h
Herwig_LDFLAGS = $(AM_LDFLAGS) -export-dynamic $(THEPEGLDFLAGS)
Herwig_LDADD = $(THEPEGLIB) -ldl \
$(top_builddir)/API/libHerwigAPI.la
bin_SCRIPTS = herwig-config
HELPERFILES = \
CMSSM40.1.1.slha \
NMSSM.spc \
ADD.model \
Leptoquark.model \
LH.model \
LHTP.model \
MSSM.model \
MUED.model \
NMSSM.model \
RPV-Bi.model \
RPV-Tri.model \
RS.model \
Sextet.model \
TTBA.model \
Zprime.model \
RPV-BI.slha \
RPV-TRI.slha \
RPV-UDD.slha
INPUTFILES = \
DIS.in \
DIS-Matchbox.in \
GammaGamma.in \
ILC.in \
ILC-MSSM.in \
ILC-MUED.in \
ILC-RS.in \
LEP.in \
LEP-Matchbox.in \
LHC-ADD.in \
LHC-CEX.in \
LHC-GammaGamma.in \
+LHC-ResolvedGammaGamma.in \
LHC.in \
LHC-Matchbox.in \
LHC-LQ.in \
LHC-MSSM.in \
LHC-MUED.in \
LHC-NMSSM.in \
LHC-Powheg.in \
LHC-RPV.in \
LHC-RS.in \
LHC-Sextet.in \
LHC-TRP.in \
LHC-TTBA.in \
LHC-MB.in \
LHC-ZP.in \
TVT.in \
TVT-Powheg.in \
TVT-TTBA.in \
LHC-LH.in \
LHC-LHTP.in \
LHE.in
dist_pkgdata_DATA = $(INPUTFILES) $(HELPERFILES)
pkgdata_DATA = Makefile-UserModules
CLEANFILES = HerwigDefaults.rpo \
*.run *.log *.out *.tex \
multi.test *.output probs.test chisq.value \
LHC-RS-BR.spc LHC-MSSM-BR.spc LHC-RPV-BR.spc
clean-local:
-rm -rf Herwig
## checking targets ##
HerwigDefaults.rpo: Herwig $(srcdir)/defaults/*.in defaults/PDF.in defaults/Analysis.in $(top_builddir)/lib/*.so
./Herwig init -L$(top_builddir)/lib defaults/HerwigDefaults.in -D
check_BSM_Full=
check_BSM=
if WANT_BSM
check_BSM += check-LHC-RPV check-LHC-RS
check_BSM_Full += \
check-LHC-RPV check-LHC-MSSM check-ILC-MSSM \
check-LHC-NMSSM \
check-LHC-MUED check-ILC-MUED \
check-LHC-RS check-ILC-RS check-LHC-ADD \
check-LHC-LH check-LHC-LHTP \
check-LHC-TRP \
check-LHC-TTBA check-TVT-TTBA \
check-LHC-ZP \
check-LHC-LQ \
check-LHC-Sextet
endif
check_BSM_Full_valgrind = $(subst check,check-valgrind,$(check_BSM_Full))
check_BSM_valgrind = $(subst check,check-valgrind,$(check_BSM))
check-local: check-LEP check-LHC $(check_BSM) check-DIS check-ILC check-GammaGamma check-LHC-Powheg
check-valgrind-local: check-valgrind-LEP check-valgrind-LHC $(check_BSM_valgrind) check-valgrind-DIS check-valgrind-ILC check-valgrind-GammaGamma check-valgrind-LHC-Powheg
check-Powheg: check-LHC-Powheg check-TVT-Powheg
check-valgrind-Powheg: check-valgrind-LHC-Powheg check-valgrind-TVT-Powheg
check-BSM: $(check_BSM_Full)
check-valgrind-BSM: $(check_BSM_Full_valgrind)
check_Matchbox= \
check-LEP-Matchbox check-DIS-Matchbox check-LHC-Matchbox
check_Matchbox_valgrind = $(subst check,check-valgrind,$(check_Matchbox))
check-Matchbox: $(check_Matchbox)
check-valgrind-Matchbox: $(check_Matchbox_valgrind)
-check-extra: check-LHC-CEX check-LHC-GammaGamma check-LHC-MB check-TVT
+check-extra: check-LHC-CEX check-LHC-GammaGamma check-LHC-ResolvedGammaGamma check-LHC-MB check-TVT
check-valgrind-extra: check-valgrind-LHC-CEX check-valgrind-LHC-GammaGamma check-valgrind-LHC-MB check-valgrind-TVT
check-all: check-local check-Powheg check-BSM check-Matchbox check-extra
check-valgrind-all: check-valgrind-local check-valgrind-Powheg check-valgrind-BSM check-valgrind-Matchbox check-valgrind-extra
link-helper-files:
@for i in $(HELPERFILES); do \
if test -f $(srcdir)/$$i -a ! -e $$i; then \
$(LN_S) -f $(srcdir)/$$i; fi; done
## valgrind targets ##
VALGRIND=valgrind --leak-check=full --num-callers=25 --freelist-vol=100000000 --leak-resolution=med --trace-children=yes
check-valgrind-%: $(srcdir)/%.in HerwigDefaults.rpo link-helper-files
$(VALGRIND) ./Herwig read -d1 -D $< &> valgrind-$(notdir $(subst .in,,$<))-read.log
$(VALGRIND) ./Herwig run $(notdir $(subst .in,.run,$<)) -N 500 -d1 -D &> valgrind-$(notdir $(subst .in,,$<))-run.log
valgrind: valgrind-init valgrind-read valgrind-run
valgrind-init:
$(VALGRIND) ./Herwig init -d1 -D -L$(top_builddir)/lib defaults/HerwigDefaults.in \
&> /tmp/valgrind-init.log
valgrind-read:
$(VALGRIND) ./Herwig read -d1 -D LHC.in &> /tmp/valgrind-read.log
valgrind-run:
$(VALGRIND) ./Herwig run -d1 -D -N5 LHC.run &> /tmp/valgrind-run.log
CHECKCOMMAND = ./Herwig run $(notdir $(subst .in,.run,$<)) -N500 -d1 -D
check-%: $(srcdir)/%.in HerwigDefaults.rpo link-helper-files
./Herwig read -i . $< -D
@echo $(CHECKCOMMAND)
@$(CHECKCOMMAND) && echo "# $@ OK #" \
|| (echo "###### $@ BAD ######"; false)
SETUPTHEPEG=$(THEPEGPATH)/bin/setupThePEG
THEPEGREPO=$(THEPEGLIBPATH)/ThePEGDefaults.rpo
install-data-hook:
@echo Creating repository
@./Herwig init -L$(DESTDIR)$(pkglibdir) -i$(DESTDIR)$(pkgdatadir) -i$(DESTDIR)$(pkgdatadir)/snippets $(DESTDIR)$(defaultsdir)/HerwigDefaults.in --repo=$(DESTDIR)$(pkgdatadir)/HerwigDefaults.rpo
@if test -n "$(DESTDIR)"; \
then sed -i.bak -e "s@$(DESTDIR)@@g" $(DESTDIR)$(pkgdatadir)/HerwigDefaults.rpo; \
rm -f $(DESTDIR)$(pkgdatadir)/HerwigDefaults.rpo.bak; \
fi
uninstall-hook:
rm -f $(DESTDIR)$(pkgdatadir)/HerwigDefaults.rpo
register: register-with-thepeg-repo
register-with-thepeg-repo:
@if test -x "$(SETUPTHEPEG)" -a -w "$(THEPEGREPO)"; \
then echo Registering with ThePEG; \
"$(SETUPTHEPEG)" --init \
$(DESTDIR)$(defaultsdir)/HerwigDefaults.in \
-r "$(THEPEGREPO)" -o "$(THEPEGREPO)" \
-i $(DESTDIR)$(pkgdatadir) \
-l$(DESTDIR)$(pkglibdir) ; \
if test -n "$(DESTDIR)"; \
then sed -i -e "s@$(DESTDIR)@@g" "$(THEPEGREPO)" ; fi ; \
fi
unregister : unregister-from-thepeg-repo
unregister-from-thepeg-repo:
@if test -x "$(SETUPTHEPEG)" -a -w "$(THEPEGREPO)"; \
then echo Unregistering with ThePEG; \
"$(SETUPTHEPEG)" --init defaults/HerwigCleanup.in \
-r "$(THEPEGREPO)" -o "$(THEPEGREPO)" \
-l$(DESTDIR)$(pkglibdir) ; \
fi
EXTRA_DIST = herwigopts.ggo
nodist_Herwig_SOURCES = hgstamp.inc
BUILT_SOURCES += hgstamp.inc
CLEANFILES += hgstamp.inc
HGVERSION := $(shell hg -R $(top_srcdir) parents --template '"Herwig {node|short} ({branch})"' 2> /dev/null || echo \"$(PACKAGE_STRING)\" || true )
.PHONY: update_hgstamp
hgstamp.inc: update_hgstamp
@[ -f $@ ] || touch $@
@echo '$(HGVERSION)' | cmp -s $@ - || echo '$(HGVERSION)' > $@
GENGETOPT = gengetopt
%opts.h %opts.c : %opts.ggo
$(GENGETOPT) < $<
diff --git a/src/Matchbox/LO-DipoleShower.in.in b/src/Matchbox/LO-DipoleShower.in.in
--- a/src/Matchbox/LO-DipoleShower.in.in
+++ b/src/Matchbox/LO-DipoleShower.in.in
@@ -1,24 +1,24 @@
# -*- ThePEG-repository -*-
read Matchbox/LO.in
cd /Herwig/EventHandlers
set EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler
-read Matchbox/MCatNLO-Dipole-HardAlphaSTune.in
+read snippets/Dipole_AutoTune_prel.in
cd /Herwig/Analysis
@CREATE_RIVET@ ThePEG::RivetAnalysis Rivet RivetAnalysis.so
@CREATE_HEPMC@ ThePEG::HepMCFile HepMC HepMCAnalysis.so
cd /Herwig/Particles
do c:UnsetHardProcessMass
do cbar:UnsetHardProcessMass
set c:NominalMass 0*GeV
set cbar:NominalMass 0*GeV
cd /Herwig/UnderlyingEvent
set MEQCD2to2Fast:StrictFlavourScheme Yes
diff --git a/src/Matchbox/MCatLO-DipoleShower.in.in b/src/Matchbox/MCatLO-DipoleShower.in.in
--- a/src/Matchbox/MCatLO-DipoleShower.in.in
+++ b/src/Matchbox/MCatLO-DipoleShower.in.in
@@ -1,28 +1,28 @@
# -*- ThePEG-repository -*-
read Matchbox/LO.in
cd /Herwig/EventHandlers
set EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler
-read Matchbox/MCatNLO-Dipole-HardAlphaSTune.in
+read snippets/Dipole_AutoTune_prel.in
set /Herwig/DipoleShower/DipoleShowerHandler:RestrictPhasespace Yes
set /Herwig/DipoleShower/DipoleShowerHandler:MaxPtIsMuF Yes
set /Herwig/DipoleShower/DipoleShowerHandler:HardScaleProfile /Herwig/MatrixElements/Matchbox/HardScaleProfile
cd /Herwig/Analysis
@CREATE_RIVET@ ThePEG::RivetAnalysis Rivet RivetAnalysis.so
@CREATE_HEPMC@ ThePEG::HepMCFile HepMC HepMCAnalysis.so
cd /Herwig/Particles
do c:UnsetHardProcessMass
do cbar:UnsetHardProcessMass
set c:NominalMass 0*GeV
set cbar:NominalMass 0*GeV
cd /Herwig/UnderlyingEvent
set MEQCD2to2Fast:StrictFlavourScheme Yes
diff --git a/src/Matchbox/MCatNLO-DipoleShower.in.in b/src/Matchbox/MCatNLO-DipoleShower.in.in
--- a/src/Matchbox/MCatNLO-DipoleShower.in.in
+++ b/src/Matchbox/MCatNLO-DipoleShower.in.in
@@ -1,32 +1,32 @@
# -*- ThePEG-repository -*-
cd /Herwig/EventHandlers
set EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler
set /Herwig/DipoleShower/DipoleShowerHandler:RestrictPhasespace Yes
set /Herwig/DipoleShower/DipoleShowerHandler:MaxPtIsMuF Yes
set /Herwig/DipoleShower/DipoleShowerHandler:HardScaleProfile /Herwig/MatrixElements/Matchbox/HardScaleProfile
cd /Herwig/MatrixElements/Matchbox
set Factory:ShowerApproximation DipoleMatching
# tunes
-read Matchbox/MCatNLO-Dipole-HardAlphaSTune.in
+read snippets/Dipole_AutoTune_prel.in
cd /Herwig/Analysis
@CREATE_RIVET@ ThePEG::RivetAnalysis Rivet RivetAnalysis.so
@CREATE_HEPMC@ ThePEG::HepMCFile HepMC HepMCAnalysis.so
cd /Herwig/Particles
do c:UnsetHardProcessMass
do cbar:UnsetHardProcessMass
set c:NominalMass 0*GeV
set cbar:NominalMass 0*GeV
cd /Herwig/UnderlyingEvent
set MEQCD2to2Fast:StrictFlavourScheme Yes
diff --git a/src/Matchbox/Makefile.am b/src/Matchbox/Makefile.am
--- a/src/Matchbox/Makefile.am
+++ b/src/Matchbox/Makefile.am
@@ -1,64 +1,65 @@
BUILT_SOURCES = done-all-links
Matchboxdir = ${pkgdatadir}/Matchbox
INPUTFILES = \
DefaultEEJets.in \
DefaultEPJets.in \
DefaultPPJets.in \
DiagonalCKM.in \
FiveFlavourNoBMassScheme.in \
FiveFlavourScheme.in \
FourFlavourScheme.in \
GoSam-GoSam.in \
HiggsEffective.in \
HJets.in \
IdentifiedBs.in \
InclusiveDurhamJets.in \
IncreaseVerbosity.in \
KrkNLO-DipoleShower.in \
LO-DefaultShower.in \
LO-DipoleShower.in \
LO.in \
LO-NoShower.in \
MadGraph-GoSam.in \
MadGraph-MadGraph.in \
MadGraph-NJet.in \
MadGraph-OpenLoops.in \
MCatLO-DefaultShower.in \
MCatLO-DipoleShower.in \
MCatNLO-DefaultShower.in \
MCatNLO-Dipole-HardAlphaSTune.in \
MCatNLO-DipoleShower.in \
MMHT2014.in \
MuDown.in \
MuQDown.in \
MuQUp.in \
MuUp.in \
NJet-NJet.in \
NLO-NoShower.in \
NonDiagonalCKM.in \
OnShellHProduction.in \
OnShellTopProduction.in \
OnShellWProduction.in \
OnShellZProduction.in \
OpenLoops-OpenLoops.in \
Powheg-DefaultShower.in \
Powheg-DipoleShower.in \
Powheg.in \
PQCDLevel.in \
StandardModelLike.in \
+ShowerBenchmarks.in \
VBFDiagramsOnly.in \
VBFNLO.in \
VBFNLOPhasespace.in
dist_Matchbox_DATA = $(INPUTFILES)
CLEANFILES = done-all-links
done-all-links: $(INPUTFILES)
@echo "Linking input files"
@for i in $(INPUTFILES); do \
if test -f $(srcdir)/$$i -a ! -e $$i; then \
$(LN_S) -f $(srcdir)/$$i; fi; done
@touch done-all-links
diff --git a/src/Matchbox/Powheg-DipoleShower.in.in b/src/Matchbox/Powheg-DipoleShower.in.in
--- a/src/Matchbox/Powheg-DipoleShower.in.in
+++ b/src/Matchbox/Powheg-DipoleShower.in.in
@@ -1,30 +1,30 @@
# -*- ThePEG-repository -*-
read Matchbox/Powheg.in
set /Herwig/MatrixElements/Matchbox/MEMatching:TruncatedShower No
cd /Herwig/EventHandlers
set EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler
set /Herwig/DipoleShower/DipoleShowerHandler:RestrictPhasespace Yes
set /Herwig/DipoleShower/DipoleShowerHandler:MaxPtIsMuF Yes
set /Herwig/DipoleShower/DipoleShowerHandler:HardScaleProfile NULL
# tunes
-read Matchbox/MCatNLO-Dipole-HardAlphaSTune.in
+read snippets/Dipole_AutoTune_prel.in
cd /Herwig/Analysis
@CREATE_RIVET@ ThePEG::RivetAnalysis Rivet RivetAnalysis.so
@CREATE_HEPMC@ ThePEG::HepMCFile HepMC HepMCAnalysis.so
cd /Herwig/Particles
do c:UnsetHardProcessMass
do cbar:UnsetHardProcessMass
set c:NominalMass 0*GeV
set cbar:NominalMass 0*GeV
cd /Herwig/UnderlyingEvent
set MEQCD2to2Fast:StrictFlavourScheme Yes
diff --git a/src/Matchbox/ShowerBenchmarks.in b/src/Matchbox/ShowerBenchmarks.in
new file mode 100644
--- /dev/null
+++ b/src/Matchbox/ShowerBenchmarks.in
@@ -0,0 +1,143 @@
+# -*- ThePEG-repository -*-
+
+# ##############################################################################
+#
+# unify alphas running
+#
+# ##############################################################################
+
+cd /Herwig/Couplings
+
+set NLOAlphaS:input_alpha_s 0.118
+set NLOAlphaS:input_scale 91.1876
+set NLOAlphaS:two_largeq_terms No
+
+clear NLOAlphaS:QuarkMasses
+insert NLOAlphaS:QuarkMasses[0] 0.005
+insert NLOAlphaS:QuarkMasses[1] 0.0023
+insert NLOAlphaS:QuarkMasses[2] 0.095
+insert NLOAlphaS:QuarkMasses[3] 1.25
+insert NLOAlphaS:QuarkMasses[4] 4.2
+insert NLOAlphaS:QuarkMasses[5] 174.2
+
+cd /Herwig/Shower
+
+set AlphaQCD:ScaleFactor 1.0
+set AlphaQCD:NPAlphaS 2
+set AlphaQCD:Qmin 0.935
+set AlphaQCD:NumberOfLoops 2
+set AlphaQCD:InputOption 1
+
+set AlphaQCD:AlphaMZ 0.118
+set AlphaQCD:InputScale 91.1876
+
+clear AlphaQCD:QuarkMasses
+insert AlphaQCD:QuarkMasses[0] 0.005
+insert AlphaQCD:QuarkMasses[1] 0.0023
+insert AlphaQCD:QuarkMasses[2] 0.095
+insert AlphaQCD:QuarkMasses[3] 1.25
+insert AlphaQCD:QuarkMasses[4] 4.2
+insert AlphaQCD:QuarkMasses[5] 174.2
+
+set /Herwig/Model:QCD/RunningAlphaS /Herwig/Couplings/NLOAlphaS
+set /Herwig/DipoleShower/DipoleShowerHandler:GlobalAlphaS /Herwig/Couplings/NLOAlphaS
+set /Herwig/Generators/EventGenerator:StandardModelParameters:QCD/RunningAlphaS /Herwig/Couplings/NLOAlphaS
+
+# ##############################################################################
+#
+# PDF settings -- same NLO PDF everywhere
+#
+# ##############################################################################
+
+read Matchbox/FourFlavourScheme.in
+
+cd /Herwig/Partons
+
+set HardNLOPDF:PDFName MMHT2014nlo68cl
+set ShowerNLOPDF:PDFName MMHT2014nlo68cl
+
+set /Herwig/Particles/p+:PDF HardNLOPDF
+set /Herwig/Particles/pbar-:PDF HardNLOPDF
+set /Herwig/Partons/PPExtractor:FirstPDF HardNLOPDF
+set /Herwig/Partons/PPExtractor:SecondPDF HardNLOPDF
+
+set /Herwig/Shower/ShowerHandler:PDFA ShowerNLOPDF
+set /Herwig/Shower/ShowerHandler:PDFB ShowerNLOPDF
+set /Herwig/DipoleShower/DipoleShowerHandler:PDFA ShowerNLOPDF
+set /Herwig/DipoleShower/DipoleShowerHandler:PDFB ShowerNLOPDF
+
+# ##############################################################################
+#
+# Quark kinematic masses are all zero
+#
+# ##############################################################################
+
+cd /Herwig/Particles
+
+do d:UnsetHardProcessMass
+do dbar:UnsetHardProcessMass
+set d:NominalMass 0*GeV
+set dbar:NominalMass 0*GeV
+
+do u:UnsetHardProcessMass
+do ubar:UnsetHardProcessMass
+set u:NominalMass 0*GeV
+set ubar:NominalMass 0*GeV
+
+do s:UnsetHardProcessMass
+do sbar:UnsetHardProcessMass
+set s:NominalMass 0*GeV
+set sbar:NominalMass 0*GeV
+
+do c:UnsetHardProcessMass
+do cbar:UnsetHardProcessMass
+set c:NominalMass 0*GeV
+set cbar:NominalMass 0*GeV
+
+# ##############################################################################
+#
+# Shower settings are those appropriate to the uncertainties studies
+#
+# ##############################################################################
+
+read Matchbox/PQCDLevel.in
+
+set /Herwig/Shower/ShowerHandler:MaxPtIsMuF Yes
+set /Herwig/Shower/ShowerHandler:HardEmission None
+set /Herwig/Shower/ShowerHandler:Interactions QCD
+set /Herwig/Shower/ShowerHandler:SpinCorrelations No
+set /Herwig/Shower/ShowerHandler:SoftCorrelations No
+set /Herwig/Shower/KinematicsReconstructor:ReconstructionOption Colour4
+set /Herwig/Shower/KinematicsReconstructor:InitialStateReconOption SofterFraction
+set /Herwig/Shower/PartnerFinder:PartnerMethod 0
+set /Herwig/Shower/PartnerFinder:ScaleChoice 0
+set /Herwig/DipoleShower/DipoleShowerHandler:MaxPtIsMuF Yes
+
+set /Herwig/Shower/ShowerHandler:IntrinsicPtGaussian 0.0*GeV
+set /Herwig/DipoleShower/IntrinsicPtGenerator:ValenceIntrinsicPtScale 0.0*GeV
+set /Herwig/DipoleShower/IntrinsicPtGenerator:SeaIntrinsicPtScale 0.0*GeV
+
+set /Herwig/DipoleShower/DipoleShowerHandler:MPIHandler NULL
+set /Herwig/Shower/ShowerHandler:MPIHandler NULL
+
+set /Herwig/DipoleShower/DipoleShowerHandler:HardScaleProfile /Herwig/MatrixElements/Matchbox/HardScaleProfile
+set /Herwig/Shower/ShowerHandler:HardScaleProfile /Herwig/MatrixElements/Matchbox/HardScaleProfile
+
+set /Herwig/MatrixElements/Matchbox/HardScaleProfile:ProfileType Resummation
+
+set /Herwig/DipoleShower/Kinematics/FFLightKinematics:IRCutoff 1.0*GeV
+set /Herwig/DipoleShower/Kinematics/FILightKinematics:IRCutoff 1.0*GeV
+set /Herwig/DipoleShower/Kinematics/IFLightKinematics:IRCutoff 1.0*GeV
+set /Herwig/DipoleShower/Kinematics/IILightKinematics:IRCutoff 1.0*GeV
+
+cd /Herwig/Shower
+
+set QtoQGSudakov:pTmin 1.0*GeV
+set GtoGGSudakov:pTmin 1.0*GeV
+set GtoQQbarSudakov:pTmin 1.0*GeV
+set GtobbbarSudakov:pTmin 1.0*GeV
+set GtoccbarSudakov:pTmin 1.0*GeV
+set QtoGQSudakov:pTmin 1.0*GeV
+set utoGuSudakov:pTmin 1.0*GeV
+set dtoGdSudakov:pTmin 1.0*GeV
+
diff --git a/src/Merging/LEP-Merging.in b/src/Merging/LEP-Merging.in
--- a/src/Merging/LEP-Merging.in
+++ b/src/Merging/LEP-Merging.in
@@ -1,156 +1,155 @@
# -*- ThePEG-repository -*-
##################################################
## Herwig/Merging example input file
##################################################
##################################################
## Collider type
##################################################
read snippets/DipoleMerging.in
read snippets/EECollider.in
read snippets/MonacoSampler.in
##################################################
## Beam energy sqrt(s)
##################################################
cd /Herwig/EventHandlers
set EventHandler:LuminosityFunction:Energy 91.2*GeV
##################################################
## Process selection
##################################################
## Note that event generation may fail if no matching matrix element has
## been found. Coupling orders are with respect to the Born process,
## i.e. NLO QCD does not require an additional power of alphas.
## Model assumptions
read Matchbox/StandardModelLike.in
read Matchbox/DiagonalCKM.in
## Set the order of the couplings
cd /Herwig/Merging
set MergingFactory:OrderInAlphaS 0
set MergingFactory:OrderInAlphaEW 2
## Select the process
## You may use identifiers such as p, pbar, j, l, mu+, h0 etc.
do MergingFactory:Process e- e+ -> j j [ j j ]
set MergingFactory:NLOProcesses 2
set Merger:MergingScale 4.*GeV
set Merger:MergingScaleSmearing 0.1
cd /Herwig/MatrixElements/Matchbox/Utility
insert DiagramGenerator:ExcludeInternal 0 /Herwig/Particles/gamma
## Special settings required for on-shell production of unstable particles
## enable for on-shell top production
# read Matchbox/OnShellTopProduction.in
## enable for on-shell W, Z or h production
# read Matchbox/OnShellWProduction.in
# read Matchbox/OnShellZProduction.in
# read Matchbox/OnShellHProduction.in
##################################################
## Matrix element library selection
##################################################
## Select a generic tree/loop combination or a
## specialized NLO package
## As massive b-quarks are currently not supported by the
## build in ME an external ME-Provider is needed (e.g. MG+OL).
# read Matchbox/MadGraph-GoSam.in
# read Matchbox/MadGraph-MadGraph.in
# read Matchbox/MadGraph-NJet.in
read Matchbox/MadGraph-OpenLoops.in
##################################################
## Cut selection
## See the documentation for more options
##################################################
## cuts on additional jets
cd /Herwig/Cuts
# read Matchbox/DefaultEEJets.in
# set NJetsCut:NJetsMin 3
##################################################
## Scale choice
## See the documentation for more options
##################################################
cd /Herwig/MatrixElements/Matchbox/Scales/
set /Herwig/Merging/MergingFactory:ScaleChoice SHatScale
##################################################
## Scale uncertainties
##################################################
# read Matchbox/MuDown.in
# read Matchbox/MuUp.in
##################################################
## Shower scale uncertainties
##################################################
# read Matchbox/MuQDown.in
# read Matchbox/MuQUp.in
##################################################
## CMW - Scheme
##################################################
-
-read Merging/Merging-Dipole-FactorCMWSchemeTune.in
+read snippets/Dipole_AutoTune_prel.in
### Use factor in alpha_s argument: alpha_s(q) -> alpha_s(fac*q)
### with fac=exp(-(67-3pi^2-10/3*Nf)/(33-2Nf))
read Merging/FactorCMWScheme.in
### Linear CMW multiplication:
### alpha_s(q) -> alpha_s(q)(1+K_g*alpha_s(q)/2pi )
# read Merging/LinearCMWScheme.in
##################################################
## Analyses
##################################################
cd /Herwig/Analysis
## Write HepMC events. Modify the PrintEvent interface for your needs.
# insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 HepMCFile
## Setup the Rivet analysis:
#read snippets/Rivet.in
#insert Rivet:Analyses 0 XXX_2017_ABC123
## Here we collected a various Rivet analysis for LEP
## at the Z Mass. (The collection might not be complete.)
# read Merging/LEP91-Analysis.in
##################################################
## Do not apply profile scales for LEP as hard
## scale coincides with kinematic limit
##################################################
set /Herwig/Shower/ShowerHandler:HardScaleProfile NULL
set /Herwig/DipoleShower/DipoleShowerHandler:HardScaleProfile NULL
##################################################
## Save the generator
##################################################
do /Herwig/Merging/MergingFactory:ProductionMode
cd /Herwig/Generators
saverun LEP-Merging EventGenerator
diff --git a/src/Merging/LHC-H-Merging.in b/src/Merging/LHC-H-Merging.in
--- a/src/Merging/LHC-H-Merging.in
+++ b/src/Merging/LHC-H-Merging.in
@@ -1,194 +1,194 @@
# -*- ThePEG-repository -*-
##################################################
## Herwig/Merging example input file
##################################################
##################################################
## Collider type
##################################################
read snippets/DipoleMerging.in
read snippets/PPCollider.in
read snippets/MonacoSampler.in
##################################################
## Beam energy sqrt(s)
##################################################
cd /Herwig/EventHandlers
set EventHandler:LuminosityFunction:Energy 8000*GeV
##################################################
## Process selection
##################################################
## Note that event generation may fail if no matching matrix element has
## been found. Coupling orders are with respect to the Born process,
## i.e. NLO QCD does not require an additional power of alphas.
## Model assumptions
read Matchbox/StandardModelLike.in
read Matchbox/DiagonalCKM.in
## Set the order of the couplings
cd /Herwig/Merging
set MergingFactory:OrderInAlphaS 2
set MergingFactory:OrderInAlphaEW 1
## Select the process
## You may use identifiers such as p, pbar, j, l, mu+, h0 etc.
do MergingFactory:Process p p -> h0 [ j j ]
set MergingFactory:NLOProcesses 2
# Set the merging scale deviding the parton shower
# from the matrix element region in phase space.
set Merger:MergingScale 15.*GeV
set Merger:MergingScaleSmearing 0.1
# The following line clear a preweighter
# that is not working for Higgs as here
# pt and HT are 0 before the shower.
# See other merging files for more information.
clear MergingFactory:Preweighters
# The next line can switch of hadronization
# and MPI modelling. Use with care!!
# read Matchbox/PQCDLevel.in
## Special settings required for on-shell production of unstable particles
## enable for on-shell top production
# read Matchbox/OnShellTopProduction.in
## enable for on-shell W, Z or h production
# read Matchbox/OnShellWProduction.in
# read Matchbox/OnShellZProduction.in
read Matchbox/OnShellHProduction.in
set /Herwig/Particles/h0:Stable Stable
# Special settings for the VBF approximation
# read Matchbox/VBFDiagramsOnly.in
##################################################
## Matrix element library selection
##################################################
## Select a generic tree/loop combination or a
## specialized NLO package
# read Matchbox/MadGraph-GoSam.in
# read Matchbox/MadGraph-MadGraph.in
# read Matchbox/MadGraph-NJet.in
read Matchbox/MadGraph-OpenLoops.in
#read Matchbox/HJets.in
# read Matchbox/VBFNLO.in
## Uncomment this to use ggh effective couplings
## currently only supported by MadGraph-GoSam and
## MadGraph-Openloops
#read Matchbox/HiggsEffective.in
cd /Herwig/MatrixElements/Matchbox/Amplitudes
set OpenLoops:HiggsEff Yes
set MadGraph:Model heft
##################################################
## Cut selection
## See the documentation for more options
##################################################
cd /Herwig/Cuts/
set ChargedLeptonPairMassCut:MinMass 60*GeV
set ChargedLeptonPairMassCut:MaxMass 120*GeV
cd /Herwig/MatrixElements/Matchbox/Utility
insert DiagramGenerator:ExcludeInternal 0 /Herwig/Particles/gamma
## cuts on additional jets
cd /Herwig/Cuts/
# read Matchbox/DefaultPPJets.in
# insert JetCuts:JetRegions 0 FirstJet
# insert JetCuts:JetRegions 1 SecondJet
# insert JetCuts:JetRegions 2 ThirdJet
# insert JetCuts:JetRegions 3 FourthJet
##################################################
## Scale choice
## See the documentation for more options
##################################################
cd /Herwig/MatrixElements/Matchbox/Scales/
set /Herwig/Merging/MergingFactory:ScaleChoice FixedScale
set FixedScale:FixedScale 125.*GeV
##################################################
## Scale uncertainties
##################################################
# read Matchbox/MuDown.in
# read Matchbox/MuUp.in
##################################################
## Shower scale uncertainties
##################################################
# read Matchbox/MuQDown.in
# read Matchbox/MuQUp.in
##################################################
## CMW - Scheme
##################################################
-read Merging/Merging-Dipole-FactorCMWSchemeTune.in
+read snippets/Dipole_AutoTune_prel.in
### Use factor in alpha_s argument: alpha_s(q) -> alpha_s(fac*q)
### with fac=exp(-(67-3pi^2-10/3*Nf)/(33-2Nf))
read Merging/FactorCMWScheme.in
### Linear CMW multiplication:
### alpha_s(q) -> alpha_s(q)(1+K_g*alpha_s(q)/2pi )
# read Merging/LinearCMWScheme.in
##################################################
## PDF choice
##################################################
read Matchbox/FiveFlavourNoBMassScheme.in
read Matchbox/MMHT2014.in
##################################################
## Analyses
##################################################
cd /Herwig/Analysis
## Write HepMC events. Modify the PrintEvent interface for your needs.
# insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 HepMCFile
## Setup the Rivet analysis:
#read snippets/Rivet.in
#insert Rivet:Analyses 0 XXX_2017_ABC123
## Here we collected a various Rivet analysis for Higgs at LHC
## at the 8 TeV. (The collection might not be complete.)
# read Merging/LHC8-H-Analysis.in
##################################################
## Save the generator
##################################################
do /Herwig/Merging/MergingFactory:ProductionMode
set /Herwig/Generators/EventGenerator:IntermediateOutput Yes
cd /Herwig/Generators
saverun LHC-H-Merging EventGenerator
diff --git a/src/Merging/LHC-J-Merging.in b/src/Merging/LHC-J-Merging.in
--- a/src/Merging/LHC-J-Merging.in
+++ b/src/Merging/LHC-J-Merging.in
@@ -1,191 +1,191 @@
# -*- ThePEG-repository -*-
##################################################
## Herwig/Merging example input file
##################################################
##################################################
## Collider type
##################################################
read snippets/DipoleMerging.in
read snippets/PPCollider.in
read snippets/MonacoSampler.in
##################################################
## Beam energy sqrt(s)
##################################################
cd /Herwig/EventHandlers
set EventHandler:LuminosityFunction:Energy 7000*GeV
##################################################
## Process selection
##################################################
## Note that event generation may fail if no matching matrix element has
## been found. Coupling orders are with respect to the Born process,
## i.e. NLO QCD does not require an additional power of alphas.
## Model assumptions
read Matchbox/StandardModelLike.in
read Matchbox/DiagonalCKM.in
## Set the order of the couplings
cd /Herwig/Merging
set MergingFactory:OrderInAlphaS 2
set MergingFactory:OrderInAlphaEW 0
## Select the process
## You may use identifiers such as p, pbar, j, l, mu+, h0 etc.
do MergingFactory:Process p p -> j j [ j ]
set MergingFactory:NLOProcesses 1
# Set the merging scale deviding the parton shower
# from the matrix element region in phase space.
set Merger:MergingScale 20.*GeV
set Merger:MergingScaleSmearing 0.1
# The following lines control a preweighter,
# that can be used to force more events in higher
# HT or pt regions. The unweighted events are accepted
# with a enhanced probability W, that is divided fron the
# event weight once the event is accepted.
# W = ((HT/scale)^HTPower + (pt_max/scale)^MaxPTPower)
# with scale = MZ (can be changed)
# Note that the weights will therefore differ from "1"
# if the powers are not zero.
set MPreWeight:HTPower 0
set MPreWeight:MaxPTPower 0
set MPreWeight:OnlyColoured No
# The next line can switch of hadronization
# and MPI modelling. Use with care!!
# read Matchbox/PQCDLevel.in
## Special settings required for on-shell production of unstable particles
## enable for on-shell top production
# read Matchbox/OnShellTopProduction.in
## enable for on-shell W, Z or h production
# read Matchbox/OnShellWProduction.in
# read Matchbox/OnShellZProduction.in
# read Matchbox/OnShellHProduction.in
# Special settings for the VBF approximation
# read Matchbox/VBFDiagramsOnly.in
##################################################
## Matrix element library selection
##################################################
## Select a generic tree/loop combination or a
## specialized NLO package
# read Matchbox/MadGraph-GoSam.in
# read Matchbox/MadGraph-MadGraph.in
# read Matchbox/MadGraph-NJet.in
read Matchbox/MadGraph-OpenLoops.in
# read Matchbox/HJets.in
# read Matchbox/VBFNLO.in
## Uncomment this to use ggh effective couplings
## currently only supported by MadGraph-GoSam
## and MadGraph-OpenLoops
# read Matchbox/HiggsEffective.in
##################################################
## Cut selection
## See the documentation for more options
##################################################
cd /Herwig/Cuts/
set ChargedLeptonPairMassCut:MinMass 60*GeV
set ChargedLeptonPairMassCut:MaxMass 120*GeV
cd /Herwig/MatrixElements/Matchbox/Utility
insert DiagramGenerator:ExcludeInternal 0 /Herwig/Particles/gamma
## cuts on additional jets
cd /Herwig/Cuts/
read Matchbox/DefaultPPJets.in
insert JetCuts:JetRegions 0 FirstJet
# insert JetCuts:JetRegions 1 SecondJet
# insert JetCuts:JetRegions 2 ThirdJet
# insert JetCuts:JetRegions 3 FourthJet
##################################################
## Scale choice
## See the documentation for more options
##################################################
cd /Herwig/MatrixElements/Matchbox/Scales/
set /Herwig/Merging/MergingFactory:ScaleChoice MaxJetPtScale
##################################################
## Scale uncertainties
##################################################
# read Matchbox/MuDown.in
# read Matchbox/MuUp.in
##################################################
## Shower scale uncertainties
##################################################
# read Matchbox/MuQDown.in
# read Matchbox/MuQUp.in
##################################################
## CMW - Scheme
##################################################
-read Merging/Merging-Dipole-FactorCMWSchemeTune.in
+read snippets/Dipole_AutoTune_prel.in
### Use factor in alpha_s argument: alpha_s(q) -> alpha_s(fac*q)
### with fac=exp(-(67-3pi^2-10/3*Nf)/(33-2Nf))
read Merging/FactorCMWScheme.in
### Linear CMW multiplication:
### alpha_s(q) -> alpha_s(q)(1+K_g*alpha_s(q)/2pi )
# read Merging/LinearCMWScheme.in
##################################################
## PDF choice
##################################################
read Matchbox/FiveFlavourNoBMassScheme.in
read Matchbox/MMHT2014.in
##################################################
## Analyses
##################################################
cd /Herwig/Analysis
## Write HepMC events. Modify the PrintEvent interface for your needs.
# insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 HepMCFile
## Setup the Rivet analysis:
#read snippets/Rivet.in
#insert Rivet:Analyses 0 XXX_2017_ABC123
## Here we collected a various Rivet analysis for Jets at LHC
## at the 7 TeV. (The collection might not be complete.)
# read Merging/LHC7-J-Analysis.in
##################################################
## Save the generator
##################################################
do /Herwig/Merging/MergingFactory:ProductionMode
set /Herwig/Generators/EventGenerator:IntermediateOutput Yes
cd /Herwig/Generators
saverun LHC-J-Merging EventGenerator
diff --git a/src/Merging/LHC-T-Merging.in b/src/Merging/LHC-T-Merging.in
--- a/src/Merging/LHC-T-Merging.in
+++ b/src/Merging/LHC-T-Merging.in
@@ -1,193 +1,193 @@
# -*- ThePEG-repository -*-
##################################################
## Herwig/Merging example input file
##################################################
##################################################
## Collider type
##################################################
read snippets/DipoleMerging.in
read snippets/PPCollider.in
read snippets/MonacoSampler.in
##################################################
## Beam energy sqrt(s)
##################################################
cd /Herwig/EventHandlers
set EventHandler:LuminosityFunction:Energy 7000*GeV
##################################################
## Process selection
##################################################
## Note that event generation may fail if no matching matrix element has
## been found. Coupling orders are with respect to the Born process,
## i.e. NLO QCD does not require an additional power of alphas.
## Model assumptions
read Matchbox/StandardModelLike.in
read Matchbox/DiagonalCKM.in
## Set the order of the couplings
cd /Herwig/Merging
set MergingFactory:OrderInAlphaS 2
set MergingFactory:OrderInAlphaEW 0
## Select the process
## You may use identifiers such as p, pbar, j, l, mu+, h0 etc.
do MergingFactory:Process p p -> t tbar [ j]
set MergingFactory:NLOProcesses 1
# Set the merging scale deviding the parton shower
# from the matrix element region in phase space.
set Merger:MergingScale 20.*GeV
set Merger:MergingScaleSmearing 0.1
# The following lines control a preweighter,
# that can be used to force more events in higher
# HT or pt regions. The unweighted events are accepted
# with a enhanced probability W, that is divided fron the
# event weight once the event is accepted.
# W = ((HT/scale)^HTPower + (pt_max/scale)^MaxPTPower)
# with scale = MZ (can be changed)
# Note that the weights will therefore differ from "1"
# if the powers are not zero.
set MPreWeight:HTPower 0
set MPreWeight:MaxPTPower 0
set MPreWeight:OnlyColoured No
# The next line can switch of hadronization
# and MPI modelling. Use with care!!
# read Matchbox/PQCDLevel.in
## Special settings required for on-shell production of unstable particles
## enable for on-shell top production
read Matchbox/OnShellTopProduction.in
## enable for on-shell W, Z or h production
# read Matchbox/OnShellWProduction.in
# read Matchbox/OnShellZProduction.in
# read Matchbox/OnShellHProduction.in
# Special settings for the VBF approximation
# read Matchbox/VBFDiagramsOnly.in
##################################################
## Matrix element library selection
##################################################
## Select a generic tree/loop combination or a
## specialized NLO package
# read Matchbox/MadGraph-GoSam.in
# read Matchbox/MadGraph-MadGraph.in
# read Matchbox/MadGraph-NJet.in
read Matchbox/MadGraph-OpenLoops.in
# read Matchbox/HJets.in
# read Matchbox/VBFNLO.in
## Uncomment this to use ggh effective couplings
## currently only supported by MadGraph-GoSam and
## MadGraph-Openloops
# read Matchbox/HiggsEffective.in
##################################################
## Cut selection
## See the documentation for more options
##################################################
cd /Herwig/Cuts/
set ChargedLeptonPairMassCut:MinMass 60*GeV
set ChargedLeptonPairMassCut:MaxMass 120*GeV
cd /Herwig/MatrixElements/Matchbox/Utility
insert DiagramGenerator:ExcludeInternal 0 /Herwig/Particles/gamma
## cuts on additional jets
cd /Herwig/Cuts/
# read Matchbox/DefaultPPJets.in
# insert JetCuts:JetRegions 0 FirstJet
# insert JetCuts:JetRegions 1 SecondJet
# insert JetCuts:JetRegions 2 ThirdJet
# insert JetCuts:JetRegions 3 FourthJet
##################################################
## Scale choice
## See the documentation for more options
##################################################
cd /Herwig/MatrixElements/Matchbox/Scales/
set /Herwig/Merging/MergingFactory:ScaleChoice TopPairMassScale
##################################################
## Scale uncertainties
##################################################
# read Matchbox/MuDown.in
# read Matchbox/MuUp.in
##################################################
## Shower scale uncertainties
##################################################
# read Matchbox/MuQDown.in
# read Matchbox/MuQUp.in
##################################################
## CMW - Scheme
##################################################
-read Merging/Merging-Dipole-FactorCMWSchemeTune.in
+read snippets/Dipole_AutoTune_prel.in
### Use factor in alpha_s argument: alpha_s(q) -> alpha_s(fac*q)
### with fac=exp(-(67-3pi^2-10/3*Nf)/(33-2Nf))
read Merging/FactorCMWScheme.in
### Linear CMW multiplication:
### alpha_s(q) -> alpha_s(q)(1+K_g*alpha_s(q)/2pi )
# read Merging/LinearCMWScheme.in
##################################################
## PDF choice
##################################################
read Matchbox/FiveFlavourNoBMassScheme.in
read Matchbox/MMHT2014.in
##################################################
## Analyses
##################################################
cd /Herwig/Analysis
## Write HepMC events. Modify the PrintEvent interface for your needs.
# insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 HepMCFile
## Setup the Rivet analysis:
#read snippets/Rivet.in
#insert Rivet:Analyses 0 XXX_2017_ABC123
## Here we collected a various Rivet analysis for Tops at LHC
## at the 7 TeV. (The collection might not be complete.)
# read Merging/LHC7-T-Analysis.in
##################################################
## Save the generator
##################################################
do /Herwig/Merging/MergingFactory:ProductionMode
set /Herwig/Generators/EventGenerator:IntermediateOutput Yes
cd /Herwig/Generators
saverun LHC-T-Merging EventGenerator
diff --git a/src/Merging/LHC-W-Merging.in b/src/Merging/LHC-W-Merging.in
--- a/src/Merging/LHC-W-Merging.in
+++ b/src/Merging/LHC-W-Merging.in
@@ -1,194 +1,194 @@
# -*- ThePEG-repository -*-
##################################################
## Herwig/Merging example input file
##################################################
##################################################
## Collider type
##################################################
read snippets/DipoleMerging.in
read snippets/PPCollider.in
read snippets/MonacoSampler.in
##################################################
## Beam energy sqrt(s)
##################################################
cd /Herwig/EventHandlers
set EventHandler:LuminosityFunction:Energy 7000*GeV
##################################################
## Process selection
##################################################
## Note that event generation may fail if no matching matrix element has
## been found. Coupling orders are with respect to the Born process,
## i.e. NLO QCD does not require an additional power of alphas.
## Model assumptions
read Matchbox/StandardModelLike.in
read Matchbox/DiagonalCKM.in
## Set the order of the couplings
cd /Herwig/Merging
set MergingFactory:OrderInAlphaS 0
set MergingFactory:OrderInAlphaEW 2
## Select the process
## You may use identifiers such as p, pbar, j, l, mu+, h0 etc.
do MergingFactory:Process p p -> l nu [ j j ]
set MergingFactory:NLOProcesses 2
# Set the merging scale deviding the parton shower
# from the matrix element region in phase space.
set Merger:MergingScale 15.*GeV
set Merger:MergingScaleSmearing 0.1
# The following lines control a preweighter,
# that can be used to force more events in higher
# HT or pt regions. The unweighted events are accepted
# with a enhanced probability W, that is divided fron the
# event weight once the event is accepted.
# W = ((HT/scale)^HTPower + (pt_max/scale)^MaxPTPower)
# with scale = MZ (can be changed)
# Note that the weights will therefore differ from "1"
# if the powers are not zero.
set MPreWeight:HTPower 0
set MPreWeight:MaxPTPower 0
set MPreWeight:OnlyColoured No
# The next line can switch of hadronization
# and MPI modelling. Use with care!!
# read Matchbox/PQCDLevel.in
## Special settings required for on-shell production of unstable particles
## enable for on-shell top production
# read Matchbox/OnShellTopProduction.in
## enable for on-shell W, Z or h production
# read Matchbox/OnShellWProduction.in
# read Matchbox/OnShellZProduction.in
# read Matchbox/OnShellHProduction.in
# Special settings for the VBF approximation
# read Matchbox/VBFDiagramsOnly.in
##################################################
## Matrix element library selection
##################################################
## Select a generic tree/loop combination or a
## specialized NLO package
# read Matchbox/MadGraph-GoSam.in
# read Matchbox/MadGraph-MadGraph.in
# read Matchbox/MadGraph-NJet.in
# read Matchbox/MadGraph-OpenLoops.in
# read Matchbox/HJets.in
# read Matchbox/VBFNLO.in
## Uncomment this to use ggh effective couplings
## currently only supported by MadGraph-GoSam and
## MadGraph-Openloops
# read Matchbox/HiggsEffective.in
##################################################
## Cut selection
## See the documentation for more options
##################################################
cd /Herwig/Cuts/
set /Herwig/Cuts/LeptonPairMassCut:MinMass 60*GeV
set /Herwig/Cuts/LeptonPairMassCut:MaxMass 120*GeV
cd /Herwig/MatrixElements/Matchbox/Utility
insert DiagramGenerator:ExcludeInternal 0 /Herwig/Particles/gamma
## cuts on additional jets
cd /Herwig/Cuts/
# read Matchbox/DefaultPPJets.in
# insert JetCuts:JetRegions 0 FirstJet
# insert JetCuts:JetRegions 1 SecondJet
# insert JetCuts:JetRegions 2 ThirdJet
# insert JetCuts:JetRegions 3 FourthJet
##################################################
## Scale choice
## See the documentation for more options
##################################################
cd /Herwig/MatrixElements/Matchbox/Scales/
set /Herwig/Merging/MergingFactory:ScaleChoice LeptonPairMassScale
##################################################
## Scale uncertainties
##################################################
# read Matchbox/MuDown.in
# read Matchbox/MuUp.in
##################################################
## Shower scale uncertainties
##################################################
# read Matchbox/MuQDown.in
# read Matchbox/MuQUp.in
##################################################
## CMW - Scheme
##################################################
-read Merging/Merging-Dipole-FactorCMWSchemeTune.in
+read snippets/Dipole_AutoTune_prel.in
### Use factor in alpha_s argument: alpha_s(q) -> alpha_s(fac*q)
### with fac=exp(-(67-3pi^2-10/3*Nf)/(33-2Nf))
read Merging/FactorCMWScheme.in
### Linear CMW multiplication:
### alpha_s(q) -> alpha_s(q)(1+K_g*alpha_s(q)/2pi )
# read Merging/LinearCMWScheme.in
##################################################
## PDF choice
##################################################
read Matchbox/FiveFlavourNoBMassScheme.in
read Matchbox/MMHT2014.in
##################################################
## Analyses
##################################################
cd /Herwig/Analysis
## Write HepMC events. Modify the PrintEvent interface for your needs.
# insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 HepMCFile
## Setup the Rivet analysis:
#read snippets/Rivet.in
#insert Rivet:Analyses 0 XXX_2017_ABC123
## Here we collected a various Rivet analysis for Ws at LHC
## at the 7 TeV. (The collection might not be complete.)
# read Merging/LHC7-W-Analysis.in
##################################################
## Save the generator
##################################################
do /Herwig/Merging/MergingFactory:ProductionMode
set /Herwig/Generators/EventGenerator:IntermediateOutput Yes
cd /Herwig/Generators
saverun LHC-W-Merging EventGenerator
diff --git a/src/Merging/LHC-Z-Merging.in b/src/Merging/LHC-Z-Merging.in
--- a/src/Merging/LHC-Z-Merging.in
+++ b/src/Merging/LHC-Z-Merging.in
@@ -1,194 +1,194 @@
# -*- ThePEG-repository -*-
##################################################
## Herwig/Merging example input file
##################################################
##################################################
## Collider type
##################################################
read snippets/DipoleMerging.in
read snippets/PPCollider.in
read snippets/MonacoSampler.in
##################################################
## Beam energy sqrt(s)
##################################################
cd /Herwig/EventHandlers
set EventHandler:LuminosityFunction:Energy 7000*GeV
##################################################
## Process selection
##################################################
## Note that event generation may fail if no matching matrix element has
## been found. Coupling orders are with respect to the Born process,
## i.e. NLO QCD does not require an additional power of alphas.
## Model assumptions
read Matchbox/StandardModelLike.in
read Matchbox/DiagonalCKM.in
## Set the order of the couplings
cd /Herwig/Merging
set MergingFactory:OrderInAlphaS 0
set MergingFactory:OrderInAlphaEW 2
## Select the process
## You may use identifiers such as p, pbar, j, l, mu+, h0 etc.
do MergingFactory:Process p p -> e+ e- [ j j ]
set MergingFactory:NLOProcesses 2
# Set the merging scale deviding the parton shower
# from the matrix element region in phase space.
set Merger:MergingScale 15.*GeV
set Merger:MergingScaleSmearing 0.1
# The following lines control a preweighter,
# that can be used to force more events in higher
# HT or pt regions. The unweighted events are accepted
# with a enhanced probability W, that is divided fron the
# event weight once the event is accepted.
# W = ((HT/scale)^HTPower + (pt_max/scale)^MaxPTPower)
# with scale = MZ (can be changed)
# Note that the weights will therefore differ from "1"
# if the powers are not zero.
set MPreWeight:HTPower 0
set MPreWeight:MaxPTPower 0
set MPreWeight:OnlyColoured No
# The next line can switch of hadronization
# and MPI modelling. Use with care!!
# read Matchbox/PQCDLevel.in
## Special settings required for on-shell production of unstable particles
## enable for on-shell top production
# read Matchbox/OnShellTopProduction.in
## enable for on-shell W, Z or h production
# read Matchbox/OnShellWProduction.in
# read Matchbox/OnShellZProduction.in
# read Matchbox/OnShellHProduction.in
# Special settings for the VBF approximation
# read Matchbox/VBFDiagramsOnly.in
##################################################
## Matrix element library selection
##################################################
## Select a generic tree/loop combination or a
## specialized NLO package
# read Matchbox/MadGraph-GoSam.in
# read Matchbox/MadGraph-MadGraph.in
# read Matchbox/MadGraph-NJet.in
# read Matchbox/MadGraph-OpenLoops.in
# read Matchbox/HJets.in
# read Matchbox/VBFNLO.in
## Uncomment this to use ggh effective couplings
## currently only supported by MadGraph-GoSam and
## MadGraph-Openloops
# read Matchbox/HiggsEffective.in
##################################################
## Cut selection
## See the documentation for more options
##################################################
cd /Herwig/Cuts/
set ChargedLeptonPairMassCut:MinMass 60*GeV
set ChargedLeptonPairMassCut:MaxMass 120*GeV
cd /Herwig/MatrixElements/Matchbox/Utility
insert DiagramGenerator:ExcludeInternal 0 /Herwig/Particles/gamma
## cuts on additional jets
cd /Herwig/Cuts/
# read Matchbox/DefaultPPJets.in
# insert JetCuts:JetRegions 0 FirstJet
# insert JetCuts:JetRegions 1 SecondJet
# insert JetCuts:JetRegions 2 ThirdJet
# insert JetCuts:JetRegions 3 FourthJet
##################################################
## Scale choice
## See the documentation for more options
##################################################
cd /Herwig/MatrixElements/Matchbox/Scales/
set /Herwig/Merging/MergingFactory:ScaleChoice LeptonPairMassScale
##################################################
## Scale uncertainties
##################################################
# read Matchbox/MuDown.in
# read Matchbox/MuUp.in
##################################################
## Shower scale uncertainties
##################################################
# read Matchbox/MuQDown.in
# read Matchbox/MuQUp.in
##################################################
## CMW - Scheme
##################################################
-read Merging/Merging-Dipole-FactorCMWSchemeTune.in
+read snippets/Dipole_AutoTune_prel.in
### Use factor in alpha_s argument: alpha_s(q) -> alpha_s(fac*q)
### with fac=exp(-(67-3pi^2-10/3*Nf)/(33-2Nf))
read Merging/FactorCMWScheme.in
### Linear CMW multiplication:
### alpha_s(q) -> alpha_s(q)(1+K_g*alpha_s(q)/2pi )
# read Merging/LinearCMWScheme.in
##################################################
## PDF choice
##################################################
read Matchbox/FiveFlavourNoBMassScheme.in
read Matchbox/MMHT2014.in
##################################################
## Analyses
##################################################
cd /Herwig/Analysis
## Write HepMC events. Modify the PrintEvent interface for your needs.
# insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 HepMCFile
## Setup the Rivet analysis:
#read snippets/Rivet.in
#insert Rivet:Analyses 0 XXX_2017_ABC123
## Here we collected a various Rivet analysis for Zs at LHC
## at the 8 TeV. (The collection might not be complete.)
# read Merging/LHC7-Z-Analysis.in
##################################################
## Save the generator
##################################################
do /Herwig/Merging/MergingFactory:ProductionMode
set /Herwig/Generators/EventGenerator:IntermediateOutput Yes
cd /Herwig/Generators
saverun LHC-Z-Merging EventGenerator
diff --git a/src/defaults/Cuts.in b/src/defaults/Cuts.in
--- a/src/defaults/Cuts.in
+++ b/src/defaults/Cuts.in
@@ -1,113 +1,118 @@
# -*- ThePEG-repository -*-
###########################################################
# Default cuts (applied to the hard subprocess)
#
# Don't change values here, re-set them in your own input
# files using these as examples.
###########################################################
mkdir /Herwig/Matchers
cd /Herwig/Matchers
create ThePEG::Matcher<Lepton> Lepton
create ThePEG::Matcher<Neutrino> Neutrino
create ThePEG::Matcher<ChargedLepton> ChargedLepton
create ThePEG::Matcher<LightQuark> LightQuark
+create ThePEG::Matcher<LightParticle> LightParticle
create ThePEG::Matcher<LightAntiQuark> LightAntiQuark
create ThePEG::Matcher<StandardQCDParton> StandardQCDParton
create ThePEG::Matcher<Photon> Photon
create ThePEG::Matcher<Top> Top
create ThePEG::Matcher<Bottom> Bottom
create ThePEG::Matcher<WBoson> WBoson
create ThePEG::Matcher<ZBoson> ZBoson
create ThePEG::Matcher<HiggsBoson> HiggsBoson
mkdir /Herwig/Cuts
cd /Herwig/Cuts
# cut on jet pt
create ThePEG::SimpleKTCut JetKtCut SimpleKTCut.so
newdef JetKtCut:Matcher /Herwig/Matchers/StandardQCDParton
newdef JetKtCut:MinKT 20.0*GeV
# cut on photon
create ThePEG::SimpleKTCut PhotonKtCut SimpleKTCut.so
newdef PhotonKtCut:Matcher /Herwig/Matchers/Photon
newdef PhotonKtCut:MinKT 20.0*GeV
newdef PhotonKtCut:MinEta -3.
newdef PhotonKtCut:MaxEta 3.
# cut on leptons
create ThePEG::SimpleKTCut LeptonKtCut SimpleKTCut.so
newdef LeptonKtCut:Matcher /Herwig/Matchers/Lepton
newdef LeptonKtCut:MinKT 0.0*GeV
# cut on charged leptons
create ThePEG::SimpleKTCut ChargedLeptonKtCut SimpleKTCut.so
newdef ChargedLeptonKtCut:Matcher /Herwig/Matchers/ChargedLepton
newdef ChargedLeptonKtCut:MinKT 0.0*GeV
# cut on top quarks
create ThePEG::KTRapidityCut TopKtCut KTRapidityCut.so
newdef TopKtCut:Matcher /Herwig/Matchers/Top
newdef TopKtCut:MinKT 0.0*GeV
# cut on W bosons
create ThePEG::KTRapidityCut WBosonKtCut KTRapidityCut.so
newdef WBosonKtCut:Matcher /Herwig/Matchers/WBoson
newdef WBosonKtCut:MinKT 0.0*GeV
# cut on Z bosons
create ThePEG::KTRapidityCut ZBosonKtCut KTRapidityCut.so
newdef ZBosonKtCut:Matcher /Herwig/Matchers/ZBoson
newdef ZBosonKtCut:MinKT 0.0*GeV
# cut on Higgs bosons
create ThePEG::KTRapidityCut HiggsBosonKtCut KTRapidityCut.so
newdef HiggsBosonKtCut:Matcher /Herwig/Matchers/HiggsBoson
newdef HiggsBosonKtCut:MinKT 0.0*GeV
+# cut on Higgs bosons
+create ThePEG::KTRapidityCut LightParticleKtCut KTRapidityCut.so
+newdef LightParticleKtCut:Matcher /Herwig/Matchers/LightParticle
+newdef LightParticleKtCut:MinKT 0.0*GeV
# create a cut on the invariant mass of lepton pairs
create ThePEG::V2LeptonsCut MassCut V2LeptonsCut.so
newdef MassCut:Families All
newdef MassCut:CComb All
newdef MassCut:MinM 20.*GeV
newdef MassCut:MaxM 14000.*GeV
# create a cut on Q^2 for neutral current DIS
create ThePEG::SimpleDISCut NeutralCurrentCut SimpleDISCut.so
newdef NeutralCurrentCut:MinQ2 20.
newdef NeutralCurrentCut:Current Neutral
# create a cut on Q^2 for charged current DIS
create ThePEG::SimpleDISCut ChargedCurrentCut SimpleDISCut.so
newdef ChargedCurrentCut:MinQ2 20.
newdef ChargedCurrentCut:Current Charged
# create a cut of Q^2 for charged current DIS
# Default Cuts object
create ThePEG::Cuts Cuts
newdef /Herwig/Generators/EventGenerator:EventHandler:Cuts /Herwig/Cuts/Cuts
newdef Cuts:MHatMin 20.*GeV
# insert into hadron cuts (by defaults)
insert Cuts:OneCuts[0] JetKtCut
insert Cuts:OneCuts[1] PhotonKtCut
insert Cuts:OneCuts[2] LeptonKtCut
insert Cuts:OneCuts[3] TopKtCut
insert Cuts:OneCuts[4] WBosonKtCut
insert Cuts:OneCuts[5] ZBosonKtCut
insert Cuts:OneCuts[6] HiggsBosonKtCut
insert Cuts:OneCuts[7] ChargedLeptonKtCut
insert Cuts:MultiCuts[0] MassCut
# create diffrent cuts object for MinBias to avoid numerical problems
create ThePEG::Cuts MinBiasCuts
newdef MinBiasCuts:ScaleMin 2.0*GeV2
newdef MinBiasCuts:X1Min 0.055
newdef MinBiasCuts:X2Min 0.055
newdef MinBiasCuts:MHatMin 0.0*GeV
diff --git a/src/defaults/PDF.in.in b/src/defaults/PDF.in.in
--- a/src/defaults/PDF.in.in
+++ b/src/defaults/PDF.in.in
@@ -1,73 +1,77 @@
# -*- ThePEG-repository -*-
# PDF.in. Generated from PDF.in.in by Makefile.am
#####################################
# Default PDF set
#####################################
# Handle leptons
create ThePEG::LeptonLeptonPDF LeptonPDF LeptonLeptonPDF.so
newdef LeptonPDF:RemnantHandler LeptonRemnants
newdef /Herwig/Particles/e-:PDF LeptonPDF
newdef /Herwig/Particles/e+:PDF LeptonPDF
# Handle hadrons
# NEW DEFAULT for Hw 7
library ThePEGLHAPDF.so
create ThePEG::LHAPDF HardLOPDF
newdef HardLOPDF:RemnantHandler HadronRemnants
create ThePEG::LHAPDF HardNLOPDF
newdef HardNLOPDF:RemnantHandler HadronRemnants
create ThePEG::LHAPDF ShowerLOPDF
newdef ShowerLOPDF:RemnantHandler HadronRemnants
create ThePEG::LHAPDF ShowerNLOPDF
newdef ShowerNLOPDF:RemnantHandler HadronRemnants
create ThePEG::LHAPDF MPIPDF
newdef MPIPDF:RemnantHandler HadronRemnants
create ThePEG::LHAPDF RemnantPDF
newdef RemnantPDF:RemnantHandler HadronRemnants
newdef HardLOPDF:PDFName MMHT2014lo68cl
newdef HardNLOPDF:PDFName MMHT2014nlo68cl
newdef ShowerLOPDF:PDFName MMHT2014lo68cl
newdef ShowerNLOPDF:PDFName MMHT2014nlo68cl
newdef MPIPDF:PDFName MMHT2014lo68cl
newdef RemnantPDF:PDFName MMHT2014lo68cl
# set LO PDFS for hard process and can be changed later
newdef /Herwig/Particles/p+:PDF HardLOPDF
newdef /Herwig/Particles/pbar-:PDF HardLOPDF
# photons from leptons in WW approx
create ThePEG::WeizsackerWilliamsPDF WWPDF WeizsackerWilliamsPDF.so
create ThePEG::UnResolvedRemnant /Herwig/Partons/LeptonGammaRemnants
newdef /Herwig/Partons/WWPDF:RemnantHandler /Herwig/Partons/LeptonGammaRemnants
# photons from protons in Budnev approx
create ThePEG::BudnevPDF BudnevPDF BudnevPDF.so
create ThePEG::UnResolvedRemnant /Herwig/Partons/HadronGammaRemnants
newdef /Herwig/Partons/BudnevPDF:RemnantHandler /Herwig/Partons/HadronGammaRemnants
+# partons inside photons
+create Herwig::SaSPhotonPDF /Herwig/Partons/SaSPDF HwSaSPhotonPDF.so
+set /Herwig/Partons/SaSPDF:RemnantHandler /Herwig/Partons/HadronRemnants
+
# pomerons
create Herwig::PomeronFlux PomeronFlux HwPomeronFlux.so
newdef PomeronFlux:PDFFit Pomeron2006A
newdef PomeronFlux:Q2Max 1.
newdef PomeronFlux:Q2Min 1.0e-6
create ThePEG::UnResolvedRemnant /Herwig/Partons/ProtonRemnant UnResolvedRemnant.so
newdef /Herwig/Partons/PomeronFlux:RemnantHandler /Herwig/Partons/ProtonRemnant
create Herwig::PomeronPDF PomeronPDF HwPomeronPDF.so
newdef PomeronPDF:RemnantHandler HadronRemnants
newdef PomeronPDF:RootName @HERWIG_PDF_POMERON@
newdef /Herwig/Particles/pomeron:PDF PomeronPDF
newdef PomeronPDF:PDFFit 2006A
diff --git a/src/snippets/BaryonicReconnection.in b/src/snippets/BaryonicReconnection.in
new file mode 100644
--- /dev/null
+++ b/src/snippets/BaryonicReconnection.in
@@ -0,0 +1,17 @@
+# Set strange quark mass to 0.45 in order to allow alternative gluon splitting
+set /Herwig/Particles/s:ConstituentMass 0.45*GeV
+set /Herwig/Particles/sbar:ConstituentMass 0.45*GeV
+
+# Use Baryonic Colour Reconnection Model
+set /Herwig/Hadronization/ColourReconnector:Algorithm BaryonicReco
+
+# Allow alternative gluon splitting
+set /Herwig/Hadronization/PartonSplitter:Split uds
+
+# Parameters for the Baryonic Reconnection Model
+set /Herwig/Hadronization/ColourReconnector:ReconnectionProbability 0.772606
+set /Herwig/Hadronization/ColourReconnector:ReconnectionProbabilityBaryonic 0.477612
+set /Herwig/UnderlyingEvent/MPIHandler:pTmin0 3.053252
+set /Herwig/UnderlyingEvent/MPIHandler:InvRadius 1.282032
+set /Herwig/Hadronization/HadronSelector:PwtSquark 0.291717
+set /Herwig/Hadronization/PartonSplitter:SplitPwtSquark 0.824135
diff --git a/src/snippets/DipoleMerging.in b/src/snippets/DipoleMerging.in
--- a/src/snippets/DipoleMerging.in
+++ b/src/snippets/DipoleMerging.in
@@ -1,113 +1,102 @@
# -*- ThePEG-repository -*-
cd /Herwig/Cuts
# Set up cuts for Merging
set Cuts:Fuzzy FuzzyTheta
clear Cuts:OneCuts
insert Cuts:OneCuts[0] PhotonCut
insert Cuts:OneCuts[1] LeptonCut
insert Cuts:OneCuts[2] TopQuarkCut
insert Cuts:OneCuts[3] BottomQuarkCut
insert Cuts:OneCuts[4] WBosonCut
insert Cuts:OneCuts[5] ZBosonCut
insert Cuts:OneCuts[6] HiggsBosonCut
insert Cuts:OneCuts[7] ChargedLeptonCut
clear Cuts:TwoCuts
insert Cuts:TwoCuts[0] LeptonPairMassCut
insert Cuts:TwoCuts[1] ChargedLeptonPairMassCut
insert Cuts:TwoCuts[2] LeptonDeltaRCut
insert Cuts:TwoCuts[3] ChargedLeptonDeltaRCut
clear Cuts:MultiCuts
insert Cuts:MultiCuts[0] PhotonIsolationCut
insert Cuts:MultiCuts[1] MissingPtCut
set Cuts:MHatMin 0.0*GeV
set JetKtCut:MinKT 0.0*GeV
# Set up the alphas for merging
set /Herwig/Model:QCD/RunningAlphaS /Herwig/Couplings/NLOAlphaS
set /Herwig/DipoleShower/DipoleShowerHandler:GlobalAlphaS /Herwig/Couplings/NLOAlphaS
set /Herwig/Generators/EventGenerator:StandardModelParameters:QCD/RunningAlphaS /Herwig/Couplings/NLOAlphaS
cd /Herwig/Merging
set MergingFactory:Cuts /Herwig/Cuts/Cuts
set MergingFactory:MergingHelper Merger
set MergingFactory:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler
cd /Herwig/Generators
set EventGenerator:EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler
set /Herwig/DipoleShower/DipoleShowerHandler:MaxPtIsMuF Yes
cd /Herwig/EventHandlers
set EventHandler:Sampler /Herwig/Samplers/Sampler
set EventHandler:Weighted No
set EventHandler:CollisionCuts No
set EventHandler:SubProcessHandlers[0] /Herwig/Merging/MergingFactory
cd /Herwig/Particles
set d:NominalMass 0*GeV
set dbar:NominalMass 0*GeV
set u:NominalMass 0*GeV
set ubar:NominalMass 0*GeV
set s:NominalMass 0*GeV
set sbar:NominalMass 0*GeV
set c:NominalMass 0*GeV
set cbar:NominalMass 0*GeV
#set b:HardProcessMass 0*GeV
#set bbar:HardProcessMass 0*GeV
set e+:HardProcessMass 0*GeV
set e-:HardProcessMass 0*GeV
set mu+:HardProcessMass 0*GeV
set mu-:HardProcessMass 0*GeV
set nu_e:HardProcessMass 0*GeV
set nu_ebar:HardProcessMass 0*GeV
set nu_mu:HardProcessMass 0*GeV
set nu_mubar:HardProcessMass 0*GeV
set nu_tau:HardProcessMass 0*GeV
set nu_taubar:HardProcessMass 0*GeV
cd /Herwig/Partons
set /Herwig/Particles/p+:PDF HardNLOPDF
set /Herwig/Particles/pbar-:PDF HardNLOPDF
set /Herwig/Partons/PPExtractor:FirstPDF HardNLOPDF
set /Herwig/Partons/PPExtractor:SecondPDF HardNLOPDF
set /Herwig/Partons/EPExtractor:SecondPDF HardNLOPDF
set /Herwig/Shower/ShowerHandler:PDFA ShowerNLOPDF
set /Herwig/Shower/ShowerHandler:PDFB ShowerNLOPDF
set /Herwig/DipoleShower/DipoleShowerHandler:PDFA ShowerNLOPDF
set /Herwig/DipoleShower/DipoleShowerHandler:PDFB ShowerNLOPDF
-### Don't apply restrictions on the z-boundaries while clustering.
-set /Herwig/Merging/Merger:OpenZBoundaries DipoleScale
-
-cd /Herwig/DipoleShower/Kinematics
-set IFLightKinematics:OpenZBoundaries Hard
-set IILightKinematics:OpenZBoundaries Hard
-set FFLightKinematics:OpenZBoundaries Hard
-set FILightKinematics:OpenZBoundaries Hard
-set FIMassiveKinematics:OpenZBoundaries Hard
-set IFMassiveKinematics:OpenZBoundaries Hard
-set FFMassiveKinematics:OpenZBoundaries Hard
# Switch of the profiles of the Shower
set /Herwig/DipoleShower/DipoleShowerHandler:HardScaleProfile NULL
cd /Herwig/Merging
# Currently we do not splitt the hard process for merged processes.
set /Herwig/DipoleShower/DipoleShowerHandler:SplitHardProcess No
diff --git a/src/snippets/Dipole_AutoTune_prel.in b/src/snippets/Dipole_AutoTune_prel.in
new file mode 100644
--- /dev/null
+++ b/src/snippets/Dipole_AutoTune_prel.in
@@ -0,0 +1,139 @@
+# This is a preliminary Tune.
+# With this version (7.1.3) various changes to the dipole shower are done.
+# The dipole shower will be retuned for version 7.1.4.
+
+# Note: The gluon ConstituentMass is lower than the strange quark
+# threshold assumed in the BaryonicReconnection.
+# Using both snippets will produce no resonable results.
+
+set /Herwig/DipoleShower/NLOAlphaS:input_alpha_s 0.118
+set /Herwig/DipoleShower/NLOAlphaS:input_scale 91.18*GeV
+set /Herwig/Couplings/NLOAlphaS:input_alpha_s 0.118
+set /Herwig/Couplings/NLOAlphaS:input_scale 91.18*GeV
+
+set /Herwig/DipoleShower/Kinematics/FFMassiveKinematics:IRCutoff 0.80399886545
+set /Herwig/DipoleShower/Kinematics/FFLightKinematics:IRCutoff 0.80399886545
+set /Herwig/DipoleShower/Kinematics/FIMassiveKinematics:IRCutoff 0.80399886545
+set /Herwig/DipoleShower/Kinematics/FILightKinematics:IRCutoff 0.80399886545
+set /Herwig/DipoleShower/Kinematics/IFMassiveKinematics:IRCutoff 0.80399886545
+set /Herwig/DipoleShower/Kinematics/IFLightKinematics:IRCutoff 0.80399886545
+set /Herwig/DipoleShower/Kinematics/IILightKinematics:IRCutoff 0.80399886545
+
+set /Herwig/Particles/g:ConstituentMass 0.762996296601
+
+set /Herwig/Hadronization/ClusterDecayer:ClSmrLight 0.342544255421
+set /Herwig/Hadronization/ClusterDecayer:ClSmrCharm 0.237545842862
+set /Herwig/Hadronization/ClusterDecayer:ClSmrBottom 0.0620545338048
+
+set /Herwig/Hadronization/ClusterFissioner:ClPowLight 0.950949552153
+set /Herwig/Hadronization/ClusterFissioner:ClPowCharm 0.725163909065
+set /Herwig/Hadronization/ClusterFissioner:ClPowBottom 0.809774254452
+
+set /Herwig/Hadronization/ClusterFissioner:ClMaxLight 2.80478186219
+set /Herwig/Hadronization/ClusterFissioner:ClMaxCharm 3.13483791689
+set /Herwig/Hadronization/ClusterFissioner:ClMaxBottom 5.79181302131
+
+set /Herwig/Hadronization/ClusterFissioner:PSplitLight 0.995391682928
+set /Herwig/Hadronization/ClusterFissioner:PSplitCharm 0.769749617516
+set /Herwig/Hadronization/ClusterFissioner:PSplitBottom 0.479199412481
+
+set /Herwig/Hadronization/HadronSelector:SingleHadronLimitCharm 0.0485533655422
+set /Herwig/Hadronization/HadronSelector:SingleHadronLimitBottom 0.0968582906399
+
+set /Herwig/Hadronization/HadronSelector:PwtUquark 0.718641969264
+set /Herwig/Hadronization/HadronSelector:PwtDquark 0.674967529289
+set /Herwig/Hadronization/HadronSelector:PwtSquark 0.542042947191
+set /Herwig/Hadronization/HadronSelector:PwtCquark 0.251544496683
+set /Herwig/Hadronization/HadronSelector:PwtBquark 0.426714635544
+set /Herwig/Hadronization/HadronSelector:PwtDIquark 0.296781084091
+set /Herwig/Hadronization/HadronSelector:SngWt 0.541287379336
+set /Herwig/Hadronization/HadronSelector:DecWt 0.569933528697
+
+set /Herwig/Particles/b:NominalMass 5.38329996032
+set /Herwig/Particles/b:ConstituentMass 4.84231667563
+
+#######
+# CMW scheme:
+# Tune was done with CMW for all kernels, as merging currently only is consistent if applied to all.
+#######
+
+
+cd /Herwig/DipoleShower/Kernels
+set FFgx2ggxDipoleKernel:CMWScheme Factor
+set FFqx2qgxDipoleKernel:CMWScheme Factor
+set FFgx2ddxDipoleKernel:CMWScheme Factor
+set FFgx2uuxDipoleKernel:CMWScheme Factor
+set FFgx2ccxDipoleKernel:CMWScheme Factor
+set FFgx2ssxDipoleKernel:CMWScheme Factor
+set FFgx2bbxDipoleKernel:CMWScheme Factor
+set FFMgx2ggxDipoleKernel:CMWScheme Factor
+set FFMdx2dgxDipoleKernel:CMWScheme Factor
+set FFMux2ugxDipoleKernel:CMWScheme Factor
+set FFMcx2cgxDipoleKernel:CMWScheme Factor
+set FFMsx2sgxDipoleKernel:CMWScheme Factor
+set FFMbx2bgxDipoleKernel:CMWScheme Factor
+set FFMtx2tgxDipoleKernel:CMWScheme Factor
+set FFMgx2ddxDipoleKernel:CMWScheme Factor
+set FFMgx2uuxDipoleKernel:CMWScheme Factor
+set FFMgx2ccxDipoleKernel:CMWScheme Factor
+set FFMgx2ssxDipoleKernel:CMWScheme Factor
+set FFMgx2bbxDipoleKernel:CMWScheme Factor
+set FIgx2ggxDipoleKernel:CMWScheme Factor
+set FIqx2qgxDipoleKernel:CMWScheme Factor
+set FIgx2ddxDipoleKernel:CMWScheme Factor
+set FIgx2uuxDipoleKernel:CMWScheme Factor
+set FIgx2ccxDipoleKernel:CMWScheme Factor
+set FIgx2ssxDipoleKernel:CMWScheme Factor
+set FIgx2bbxDipoleKernel:CMWScheme Factor
+set FIMdx2dgxDipoleKernel:CMWScheme Factor
+set FIMux2ugxDipoleKernel:CMWScheme Factor
+set FIMcx2cgxDipoleKernel:CMWScheme Factor
+set FIMsx2sgxDipoleKernel:CMWScheme Factor
+set FIMbx2bgxDipoleKernel:CMWScheme Factor
+set FIMtx2tgxDipoleKernel:CMWScheme Factor
+set FIMgx2ddxDipoleKernel:CMWScheme Factor
+set FIMgx2uuxDipoleKernel:CMWScheme Factor
+set FIMgx2ccxDipoleKernel:CMWScheme Factor
+set FIMgx2ssxDipoleKernel:CMWScheme Factor
+set FIMgx2bbxDipoleKernel:CMWScheme Factor
+#set FIMgx2ttxDipoleKernel:CMWScheme Factor
+set IFgx2ggxDipoleKernel:CMWScheme Factor
+set IFqx2qgxDipoleKernel:CMWScheme Factor
+set IFqx2gqxDipoleKernel:CMWScheme Factor
+set IFgx2ddbarxDipoleKernel:CMWScheme Factor
+set IFgx2dbardxDipoleKernel:CMWScheme Factor
+set IFgx2uubarxDipoleKernel:CMWScheme Factor
+set IFgx2ubaruxDipoleKernel:CMWScheme Factor
+set IFgx2ccbarxDipoleKernel:CMWScheme Factor
+set IFgx2cbarcxDipoleKernel:CMWScheme Factor
+set IFgx2ssbarxDipoleKernel:CMWScheme Factor
+set IFgx2sbarsxDipoleKernel:CMWScheme Factor
+set IFMgx2ggxDipoleKernel:CMWScheme Factor
+set IFMqx2qgxDipoleKernel:CMWScheme Factor
+set IFMqx2gqxDipoleKernel:CMWScheme Factor
+set IFMgx2ddbarxDipoleKernel:CMWScheme Factor
+set IFMgx2dbardxDipoleKernel:CMWScheme Factor
+set IFMgx2uubarxDipoleKernel:CMWScheme Factor
+set IFMgx2ubaruxDipoleKernel:CMWScheme Factor
+set IFMgx2ccbarxDipoleKernel:CMWScheme Factor
+set IFMgx2cbarcxDipoleKernel:CMWScheme Factor
+set IFMgx2ssbarxDipoleKernel:CMWScheme Factor
+set IFMgx2sbarsxDipoleKernel:CMWScheme Factor
+set IIgx2ggxDipoleKernel:CMWScheme Factor
+set IIqx2qgxDipoleKernel:CMWScheme Factor
+set IIqx2gqxDipoleKernel:CMWScheme Factor
+set IIgx2ddbarxDipoleKernel:CMWScheme Factor
+set IIgx2dbardxDipoleKernel:CMWScheme Factor
+set IIgx2uubarxDipoleKernel:CMWScheme Factor
+set IIgx2ubaruxDipoleKernel:CMWScheme Factor
+set IIgx2ccbarxDipoleKernel:CMWScheme Factor
+set IIgx2cbarcxDipoleKernel:CMWScheme Factor
+set IIgx2ssbarxDipoleKernel:CMWScheme Factor
+set IIgx2sbarsxDipoleKernel:CMWScheme Factor
+set IFgx2bbbarxDipoleKernel:CMWScheme Factor
+set IFgx2bbarbxDipoleKernel:CMWScheme Factor
+set IFMgx2bbbarxDipoleKernel:CMWScheme Factor
+set IFMgx2bbarbxDipoleKernel:CMWScheme Factor
+set IIgx2bbbarxDipoleKernel:CMWScheme Factor
+set IIgx2bbarbxDipoleKernel:CMWScheme Factor
+
diff --git a/src/snippets/Makefile.am b/src/snippets/Makefile.am
--- a/src/snippets/Makefile.am
+++ b/src/snippets/Makefile.am
@@ -1,40 +1,41 @@
BUILT_SOURCES = done-all-links
snippetsdir = ${pkgdatadir}/snippets
INPUTFILES = \
CellGridSampler.in \
Diffraction.in \
DipoleMerging.in \
DipoleShowerFiveFlavours.in \
DipoleShowerFourFlavours.in \
EECollider.in \
EPCollider.in \
HepMCFixedOrder.in \
HepMC.in \
Matchbox.in \
MB-DipoleShower.in \
MB.in \
MonacoSampler.in \
Particles-SetLonglivedParticlesStable.in \
PDF-CT10.in \
PDF-NNPDF30NLO.in \
PPCollider.in \
RivetFixedOrder.in \
Rivet.in \
SoftModel.in \
SoftTune.in \
+YFS.in \
+BaryonicReconnection.in \
CMWinQtiledShower.in \
-YFS.in
-
+Dipole_AutoTune_prel.in
dist_snippets_DATA = $(INPUTFILES)
CLEANFILES = done-all-links
done-all-links: $(INPUTFILES)
@echo "Linking input files"
@for i in $(INPUTFILES); do \
if test -f $(srcdir)/$$i -a ! -e $$i; then \
$(LN_S) -f $(srcdir)/$$i; fi; done
@touch done-all-links
diff --git a/src/snippets/Matchbox.in b/src/snippets/Matchbox.in
--- a/src/snippets/Matchbox.in
+++ b/src/snippets/Matchbox.in
@@ -1,76 +1,79 @@
# -*- ThePEG-repository -*-
cd /Herwig/Cuts
set Cuts:Fuzzy FuzzyTheta
clear Cuts:OneCuts
insert Cuts:OneCuts[0] PhotonCut
insert Cuts:OneCuts[1] LeptonCut
insert Cuts:OneCuts[2] TopQuarkCut
insert Cuts:OneCuts[3] BottomQuarkCut
insert Cuts:OneCuts[4] WBosonCut
insert Cuts:OneCuts[5] ZBosonCut
insert Cuts:OneCuts[6] HiggsBosonCut
insert Cuts:OneCuts[7] ChargedLeptonCut
clear Cuts:TwoCuts
insert Cuts:TwoCuts[0] LeptonPairMassCut
insert Cuts:TwoCuts[1] ChargedLeptonPairMassCut
insert Cuts:TwoCuts[2] LeptonDeltaRCut
insert Cuts:TwoCuts[3] ChargedLeptonDeltaRCut
clear Cuts:MultiCuts
insert Cuts:MultiCuts[0] PhotonIsolationCut
insert Cuts:MultiCuts[1] MissingPtCut
set Cuts:MHatMin 0.0*GeV
cd /Herwig/MatrixElements/Matchbox
set Factory:Cuts /Herwig/Cuts/Cuts
cd /Herwig/EventHandlers
set EventHandler:Sampler /Herwig/Samplers/Sampler
set EventHandler:Weighted No
set EventHandler:CollisionCuts No
set EventHandler:SubProcessHandlers[0] /Herwig/MatrixElements/Matchbox/Factory
cd /Herwig/Particles
set d:NominalMass 0*GeV
set dbar:NominalMass 0*GeV
set u:NominalMass 0*GeV
set ubar:NominalMass 0*GeV
set s:NominalMass 0*GeV
set sbar:NominalMass 0*GeV
set c:HardProcessMass 0*GeV
set cbar:HardProcessMass 0*GeV
set b:HardProcessMass 0*GeV
set bbar:HardProcessMass 0*GeV
set e+:HardProcessMass 0*GeV
set e-:HardProcessMass 0*GeV
set mu+:HardProcessMass 0*GeV
set mu-:HardProcessMass 0*GeV
set nu_e:HardProcessMass 0*GeV
set nu_ebar:HardProcessMass 0*GeV
set nu_mu:HardProcessMass 0*GeV
set nu_mubar:HardProcessMass 0*GeV
set nu_tau:HardProcessMass 0*GeV
set nu_taubar:HardProcessMass 0*GeV
cd /Herwig/Partons
set /Herwig/Particles/p+:PDF HardNLOPDF
set /Herwig/Particles/pbar-:PDF HardNLOPDF
set /Herwig/Partons/PPExtractor:FirstPDF HardNLOPDF
set /Herwig/Partons/PPExtractor:SecondPDF HardNLOPDF
set /Herwig/Partons/EPExtractor:SecondPDF HardNLOPDF
set /Herwig/Shower/ShowerHandler:PDFA ShowerNLOPDF
set /Herwig/Shower/ShowerHandler:PDFB ShowerNLOPDF
set /Herwig/DipoleShower/DipoleShowerHandler:PDFA ShowerNLOPDF
set /Herwig/DipoleShower/DipoleShowerHandler:PDFB ShowerNLOPDF
set /Herwig/Generators/EventGenerator:StandardModelParameters:QCD/RunningAlphaS /Herwig/Couplings/NLOAlphaS
+
+set /Herwig/Shower/ShowerHandler:SplitHardProcess No
+set /Herwig/DipoleShower/DipoleShowerHandler:SplitHardProcess No
diff --git a/src/snippets/RivetFixedOrder.in b/src/snippets/RivetFixedOrder.in
--- a/src/snippets/RivetFixedOrder.in
+++ b/src/snippets/RivetFixedOrder.in
@@ -1,7 +1,7 @@
## snippet to set up a rivet analysis hook
## this snippet is for fixed order ie NO shower
create ThePEG::NLORivetAnalysis /Herwig/Analysis/RivetFixedOrder RivetAnalysis.so
-insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 /Herwig/Analysis/RivetFixexOrder
+insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 /Herwig/Analysis/RivetFixedOrder

File Metadata

Mime Type
application/octet-stream
Expires
Sat, May 11, 10:41 PM (1 d, 23 h)
Storage Engine
chunks
Storage Format
Chunks
Storage Handle
sqtHKX9NNTkD
Default Alt Text
(4 MB)

Event Timeline