Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/Shower/Base/Evolver.cc b/Shower/Base/Evolver.cc
--- a/Shower/Base/Evolver.cc
+++ b/Shower/Base/Evolver.cc
@@ -1,3184 +1,3332 @@
// -*- C++ -*-
//
// Evolver.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the Evolver class.
//
#include "Evolver.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Reference.h"
#include "ThePEG/Interface/RefVector.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "ThePEG/Utilities/EnumIO.h"
#include "ShowerKinematics.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Repository/EventGenerator.h"
#include "ThePEG/Handlers/EventHandler.h"
#include "ThePEG/Utilities/Throw.h"
#include "ShowerTree.h"
#include "ShowerProgenitor.h"
#include "KinematicsReconstructor.h"
#include "PartnerFinder.h"
#include "ThePEG/Handlers/StandardXComb.h"
#include "ThePEG/PDT/DecayMode.h"
#include "Herwig/Shower/ShowerHandler.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ShowerVertex.h"
#include "ThePEG/Repository/CurrentGenerator.h"
#include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h"
#include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h"
#include "ThePEG/Handlers/StandardXComb.h"
using namespace Herwig;
namespace {
/**
* A struct to order the particles in the same way as in the DecayMode's
*/
struct ParticleOrdering {
/**
* Operator for the ordering
* @param p1 The first ParticleData object
* @param p2 The second ParticleData object
*/
bool operator() (tcPDPtr p1, tcPDPtr p2) {
return abs(p1->id()) > abs(p2->id()) ||
( abs(p1->id()) == abs(p2->id()) && p1->id() > p2->id() ) ||
( p1->id() == p2->id() && p1->fullName() > p2->fullName() );
}
};
typedef multiset<tcPDPtr,ParticleOrdering> OrderedParticles;
/**
* Cached lookup of decay modes.
* Generator::findDecayMode() is not efficient.
*/
tDMPtr findDecayMode(const string & tag) {
static map<string,DMPtr> cache;
map<string,DMPtr>::const_iterator pos = cache.find(tag);
if ( pos != cache.end() )
return pos->second;
tDMPtr dm = CurrentGenerator::current().findDecayMode(tag);
cache[tag] = dm;
return dm;
}
}
DescribeClass<Evolver,Interfaced>
describeEvolver ("Herwig::Evolver","HwShower.so");
bool Evolver::_hardEmissionModeWarn = true;
bool Evolver::_missingTruncWarn = true;
IBPtr Evolver::clone() const {
return new_ptr(*this);
}
IBPtr Evolver::fullclone() const {
return new_ptr(*this);
}
void Evolver::persistentOutput(PersistentOStream & os) const {
os << _model << _splittingGenerator << _maxtry
<< _meCorrMode << _hardVetoMode << _hardVetoRead << _hardVetoReadOption
<< _limitEmissions << _spinOpt << _softOpt << _hardPOWHEG
<< ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV)
<< _vetoes << _trunc_Mode << _hardEmissionMode << _reconOpt
- << _massVetoOption << isMCatNLOSEvent << isMCatNLOHEvent
+ << isMCatNLOSEvent << isMCatNLOHEvent
<< isPowhegSEvent << isPowhegHEvent
<< theFactorizationScaleFactor << theRenormalizationScaleFactor
<< interaction_<< interactions_.size();
for(unsigned int ix=0;ix<interactions_.size();++ix)
os << oenum(interactions_[ix]);
}
void Evolver::persistentInput(PersistentIStream & is, int) {
unsigned int isize;
is >> _model >> _splittingGenerator >> _maxtry
>> _meCorrMode >> _hardVetoMode >> _hardVetoRead >> _hardVetoReadOption
>> _limitEmissions >> _spinOpt >> _softOpt >> _hardPOWHEG
>> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV)
>> _vetoes >> _trunc_Mode >> _hardEmissionMode >> _reconOpt
- >> _massVetoOption >> isMCatNLOSEvent >> isMCatNLOHEvent
+ >> isMCatNLOSEvent >> isMCatNLOHEvent
>> isPowhegSEvent >> isPowhegHEvent
>> theFactorizationScaleFactor >> theRenormalizationScaleFactor
>> interaction_ >> isize;
interactions_.resize(isize);
for(unsigned int ix=0;ix<interactions_.size();++ix)
is >> ienum(interactions_[ix]);
}
void Evolver::doinit() {
Interfaced::doinit();
// interactions may have been changed through a setup file so we
// clear it up here
interactions_.clear();
if(interaction_==0) {
interactions_.push_back(ShowerInteraction::QCD);
interactions_.push_back(ShowerInteraction::QED);
}
else if(interaction_==1) {
interactions_.push_back(ShowerInteraction::QCD);
}
else if(interaction_==2) {
interactions_.push_back(ShowerInteraction::QED);
interactions_.push_back(ShowerInteraction::QCD);
}
else if(interaction_==3) {
interactions_.push_back(ShowerInteraction::QED);
}
else if(interaction_==4) {
interactions_.push_back(ShowerInteraction::Both);
}
}
void Evolver::Init() {
static ClassDocumentation<Evolver> documentation
("This class is responsible for carrying out the showering,",
"including the kinematics reconstruction, in a given scale range,"
"including the option of the POWHEG approach to simulated next-to-leading order"
" radiation\\cite{Nason:2004rx}.",
"%\\cite{Nason:2004rx}\n"
"\\bibitem{Nason:2004rx}\n"
" P.~Nason,\n"
" ``A new method for combining NLO QCD with shower Monte Carlo algorithms,''\n"
" JHEP {\\bf 0411} (2004) 040\n"
" [arXiv:hep-ph/0409146].\n"
" %%CITATION = JHEPA,0411,040;%%\n");
static Reference<Evolver,SplittingGenerator>
interfaceSplitGen("SplittingGenerator",
"A reference to the SplittingGenerator object",
&Herwig::Evolver::_splittingGenerator,
false, false, true, false);
static Reference<Evolver,ShowerModel> interfaceShowerModel
("ShowerModel",
"The pointer to the object which defines the shower evolution model.",
&Evolver::_model, false, false, true, false, false);
static Parameter<Evolver,unsigned int> interfaceMaxTry
("MaxTry",
"The maximum number of attempts to generate the shower from a"
" particular ShowerTree",
&Evolver::_maxtry, 100, 1, 1000,
false, false, Interface::limited);
static Switch<Evolver, unsigned int> ifaceMECorrMode
("MECorrMode",
"Choice of the ME Correction Mode",
&Evolver::_meCorrMode, 1, false, false);
static SwitchOption off
(ifaceMECorrMode,"No","MECorrections off", 0);
static SwitchOption on
(ifaceMECorrMode,"Yes","hard+soft on", 1);
static SwitchOption hard
(ifaceMECorrMode,"Hard","only hard on", 2);
static SwitchOption soft
(ifaceMECorrMode,"Soft","only soft on", 3);
static Switch<Evolver, unsigned int> ifaceHardVetoMode
("HardVetoMode",
"Choice of the Hard Veto Mode",
&Evolver::_hardVetoMode, 1, false, false);
static SwitchOption HVoff
(ifaceHardVetoMode,"No","hard vetos off", 0);
static SwitchOption HVon
(ifaceHardVetoMode,"Yes","hard vetos on", 1);
static SwitchOption HVIS
(ifaceHardVetoMode,"Initial", "only IS emissions vetoed", 2);
static SwitchOption HVFS
(ifaceHardVetoMode,"Final","only FS emissions vetoed", 3);
static Switch<Evolver, unsigned int> ifaceHardVetoRead
("HardVetoScaleSource",
"If hard veto scale is to be read",
&Evolver::_hardVetoRead, 0, false, false);
static SwitchOption HVRcalc
(ifaceHardVetoRead,"Calculate","Calculate from hard process", 0);
static SwitchOption HVRread
(ifaceHardVetoRead,"Read","Read from XComb->lastScale", 1);
static Switch<Evolver, bool> ifaceHardVetoReadOption
("HardVetoReadOption",
"Apply read-in scale veto to all collisions or just the primary one?",
&Evolver::_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<Evolver, Energy> ifaceiptrms
("IntrinsicPtGaussian",
"RMS of intrinsic pT of Gaussian distribution:\n"
"2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)",
&Evolver::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV,
false, false, Interface::limited);
static Parameter<Evolver, double> ifacebeta
("IntrinsicPtBeta",
"Proportion of inverse quadratic distribution in generating intrinsic pT.\n"
"(1-Beta) is the proportion of Gaussian distribution",
&Evolver::_beta, 0, 0, 1,
false, false, Interface::limited);
static Parameter<Evolver, Energy> ifacegamma
("IntrinsicPtGamma",
"Parameter for inverse quadratic:\n"
"2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))",
&Evolver::_gamma,GeV, ZERO, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static Parameter<Evolver, Energy> ifaceiptmax
("IntrinsicPtIptmax",
"Upper bound on intrinsic pT for inverse quadratic",
&Evolver::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV,
false, false, Interface::limited);
static RefVector<Evolver,ShowerVeto> ifaceVetoes
("Vetoes",
"The vetoes to be checked during showering",
&Evolver::_vetoes, -1,
false,false,true,true,false);
static Switch<Evolver,unsigned int> interfaceLimitEmissions
("LimitEmissions",
"Limit the number and type of emissions for testing",
&Evolver::_limitEmissions, 0, false, false);
static SwitchOption interfaceLimitEmissionsNoLimit
(interfaceLimitEmissions,
"NoLimit",
"Allow an arbitrary number of emissions",
0);
static SwitchOption interfaceLimitEmissionsOneInitialStateEmission
(interfaceLimitEmissions,
"OneInitialStateEmission",
"Allow one emission in the initial state and none in the final state",
1);
static SwitchOption interfaceLimitEmissionsOneFinalStateEmission
(interfaceLimitEmissions,
"OneFinalStateEmission",
"Allow one emission in the final state and none in the initial state",
2);
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<Evolver,bool> interfaceTruncMode
("TruncatedShower", "Include the truncated shower?",
&Evolver::_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<Evolver,int> interfaceHardEmissionMode
("HardEmissionMode",
"Whether to use ME corrections or POWHEG for the hardest emission",
&Evolver::_hardEmissionMode, 0, false, false);
static SwitchOption interfaceHardEmissionModeDecayMECorrection
(interfaceHardEmissionMode,
"DecayMECorrection",
"Old fashioned ME correction for decays only",
-1);
static SwitchOption interfaceHardEmissionModeMECorrection
(interfaceHardEmissionMode,
"MECorrection",
"Old fashioned ME correction",
0);
static SwitchOption interfaceHardEmissionModePOWHEG
(interfaceHardEmissionMode,
"POWHEG",
"Powheg style hard emission using internal matrix elements",
1);
static SwitchOption interfaceHardEmissionModeMatchboxPOWHEG
(interfaceHardEmissionMode,
"MatchboxPOWHEG",
"Powheg style emission for the hard process using Matchbox",
2);
static SwitchOption interfaceHardEmissionModeFullPOWHEG
(interfaceHardEmissionMode,
"FullPOWHEG",
"Powheg style emission for the hard process using Matchbox "
"and decays using internal matrix elements",
3);
static Switch<Evolver,unsigned int > interfaceInteractions
("Interactions",
"The interactions to be used in the shower",
&Evolver::interaction_, 1, false, false);
static SwitchOption interfaceInteractionsQCDFirst
(interfaceInteractions,
"QCDFirst",
"QCD first then QED",
0);
static SwitchOption interfaceInteractionsQCDOnly
(interfaceInteractions,
"QCDOnly",
"Only QCD",
1);
static SwitchOption interfaceInteractionsQEDFirst
(interfaceInteractions,
"QEDFirst",
"QED first then QCD",
2);
static SwitchOption interfaceInteractionsQEDOnly
(interfaceInteractions,
"QEDOnly",
"Only QED",
3);
static SwitchOption interfaceInteractionsBothAtOnce
(interfaceInteractions,
"BothAtOnce",
"Generate both at the same time",
4);
static Switch<Evolver,unsigned int> interfaceReconstructionOption
("ReconstructionOption",
"Treatment of the reconstruction of the transverse momentum of "
"a branching from the evolution scale.",
&Evolver::_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",
+ "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 but only locally for each branching",
+ "Use the off-shell masses in the calculation veto the emissions from the children."
+ " no veto in generation of emissions from children",
2);
-
- static Switch<Evolver,unsigned int> interfaceMassVetoOption
- ("MassVetoOption",
- "Option for the handling of the mass vetos",
- &Evolver::_massVetoOption, 1, false, false);
- static SwitchOption interfaceMassVetoOptionReset
- (interfaceMassVetoOption,
- "Reset",
- "Try another branching without resetting the starting scale",
- 0);
- static SwitchOption interfaceMassVetoOptionInclude
- (interfaceMassVetoOption,
- "Include",
- "Include the veto in the scale generation via the veto algorithm",
- 1);
-
+ 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",
+ "Use the off-shell masses in the calculation veto the emissions from the children."
+ " veto in generation of emissions from children using virtual mass for second parton",
+ 4);
static Switch<Evolver,unsigned int> interfaceSpinCorrelations
("SpinCorrelations",
"Treatment of spin correlations in the parton shower",
&Evolver::_spinOpt, 1, false, false);
static SwitchOption interfaceSpinCorrelationsOff
(interfaceSpinCorrelations,
"No",
"No spin correlations",
0);
static SwitchOption interfaceSpinCorrelationsSpin
(interfaceSpinCorrelations,
"Yes",
"Include the azimuthal spin correlations only",
1);
static Switch<Evolver,unsigned int> interfaceSoftCorrelations
("SoftCorrelations",
"Option for the treatment of soft correlations in the parton shower",
&Evolver::_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<Evolver,bool> interfaceHardPOWHEG
("HardPOWHEG",
"Treatment of powheg emissions which are too hard to have a shower interpretation",
&Evolver::_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);
}
void Evolver::generateIntrinsicpT(vector<ShowerProgenitorPtr> particlesToShower) {
_intrinsic.clear();
if ( !ipTon() || !isISRadiationON() ) return;
// don't do anything for the moment for secondary scatters
if( !ShowerHandler::currentHandler()->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 Evolver::setupMaximumScales(const vector<ShowerProgenitorPtr> & p,
XCPtr xcomb) {
// let POWHEG events radiate freely
if(_hardEmissionMode>0&&hardTree()) {
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy);
return;
}
// return if no vetos
if (!hardVetoOn()) 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 (!hardVetoXComb()||
(hardVetoReadOption()&&
!ShowerHandler::currentHandler()->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(hardVetoXComb()&&hardVetoReadOption()&&
!ShowerHandler::currentHandler()->firstInteraction()) {
ptmax=min(ptmax,sqrt(xcomb->lastCentralScale()));
}
}
// 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->lastCentralScale() );
}
else {
ptmax = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
}
ptmax *= ShowerHandler::currentHandler()->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 Evolver::setupHardScales(const vector<ShowerProgenitorPtr> & p,
XCPtr xcomb) {
if ( hardVetoXComb() &&
(!hardVetoReadOption() ||
ShowerHandler::currentHandler()->firstInteraction()) ) {
Energy hardScale = ZERO;
if(currentTree()->isHard()) {
assert(xcomb);
hardScale = sqrt( xcomb->lastCentralScale() );
}
else {
hardScale = currentTree()->incomingLines().begin()->first
->progenitor()->momentum().mass();
}
hardScale *= ShowerHandler::currentHandler()->hardScaleFactor();
vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin();
for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale);
}
}
void Evolver::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) {
isMCatNLOSEvent = false;
isMCatNLOHEvent = false;
isPowhegSEvent = false;
isPowhegHEvent = false;
Ptr<SubtractedME>::tptr subme;
Ptr<MatchboxMEBase>::tptr me;
Ptr<SubtractionDipole>::tptr dipme;
Ptr<StandardXComb>::ptr sxc = dynamic_ptr_cast<Ptr<StandardXComb>::ptr>(xcomb);
if ( sxc ) {
subme = dynamic_ptr_cast<Ptr<SubtractedME>::tptr>(sxc->matrixElement());
me = dynamic_ptr_cast<Ptr<MatchboxMEBase>::tptr>(sxc->matrixElement());
dipme = dynamic_ptr_cast<Ptr<SubtractionDipole>::tptr>(sxc->matrixElement());
}
if ( subme ) {
if ( subme->showerApproximation() ) {
theShowerApproximation = subme->showerApproximation();
// separate MCatNLO and POWHEG-type corrections
if ( !subme->showerApproximation()->needsSplittingGenerator() ) {
if ( subme->realShowerSubtraction() )
isMCatNLOHEvent = true;
else if ( subme->virtualShowerSubtraction() )
isMCatNLOSEvent = true;
}
else {
if ( subme->realShowerSubtraction() )
isPowhegHEvent = true;
else if ( subme->virtualShowerSubtraction() || subme->loopSimSubtraction() )
isPowhegSEvent = true;
}
}
} else if ( me ) {
if ( me->factory()->showerApproximation() ) {
theShowerApproximation = me->factory()->showerApproximation();
if ( !me->factory()->showerApproximation()->needsSplittingGenerator() )
isMCatNLOSEvent = true;
else
isPowhegSEvent = true;
}
}
string error = "Inconsistent hard emission set-up in Evolver::showerHardProcess(). ";
if ( ( isMCatNLOSEvent || isMCatNLOHEvent ) ){
if (_hardEmissionMode > 1)
throw Exception() << error
<< "Cannot generate POWHEG matching with MC@NLO shower "
<< "approximation. Add 'set Evolver:HardEmissionMode 0' to input file."
<< Exception::runerror;
if ( ShowerHandler::currentHandler()->canHandleMatchboxTrunc())
throw Exception() << error
<< "Cannot use truncated qtilde shower with MC@NLO shower "
<< "approximation. Set LHCGenerator:EventHandler"
<< ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or "
<< "'/Herwig/DipoleShower/DipoleShowerHandler'."
<< Exception::runerror;
}
else if ( ((isPowhegSEvent || isPowhegHEvent) || dipme) &&
_hardEmissionMode < 2){
if ( ShowerHandler::currentHandler()->canHandleMatchboxTrunc())
throw Exception() << error
<< "Unmatched events requested for POWHEG shower "
<< "approximation. Set Evolver:HardEmissionMode to "
<< "'MatchboxPOWHEG' or 'FullPOWHEG'."
<< Exception::runerror;
else if (_hardEmissionModeWarn){
_hardEmissionModeWarn = false;
_hardEmissionMode+=2;
throw Exception() << error
<< "Unmatched events requested for POWHEG shower "
<< "approximation. Changing Evolver:HardEmissionMode from "
<< _hardEmissionMode-2 << " to " << _hardEmissionMode
<< Exception::warning;
}
}
if ( isPowhegSEvent || isPowhegHEvent) {
if (theShowerApproximation->needsTruncatedShower() &&
!ShowerHandler::currentHandler()->canHandleMatchboxTrunc() )
throw Exception() << error
<< "Current shower handler cannot generate truncated shower. "
<< "Set Generator:EventHandler:CascadeHandler to "
<< "'/Herwig/Shower/PowhegShowerHandler'."
<< Exception::runerror;
}
else if ( dipme && _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 &&
ShowerHandler::currentHandler()->firstInteraction())
throw Exception() << error
<< "POWHEG matching requested for LO events. Include "
<< "'set Factory:ShowerApproximation MEMatching' in input file."
<< Exception::runerror;
_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());
// number of attempts if more than one interaction switched on
unsigned int interactionTry=0;
do {
try {
// generate the showering
doShowering(true,xcomb);
// if no vetos return
return;
}
catch (InteractionVeto) {
currentTree()->clear();
++interactionTry;
}
}
while(interactionTry<=5);
throw Exception() << "Too many tries for shower in "
<< "Evolver::showerHardProcess()"
<< Exception::eventerror;
}
void Evolver::hardMatrixElementCorrection(bool hard) {
// set the initial enhancement factors for the soft correction
_initialenhance = 1.;
_finalenhance = 1.;
// if hard matrix element switched off return
if(!MECOn(hard)) return;
// see if we can get the correction from the matrix element
// or decayer
if(hard) {
if(_hardme&&_hardme->hasMECorrection()) {
_hardme->initializeMECorrection(_currenttree,
_initialenhance,_finalenhance);
if(hardMEC(hard))
_hardme->applyHardMatrixElementCorrection(_currenttree);
}
}
else {
if(_decayme&&_decayme->hasMECorrection()) {
_decayme->initializeMECorrection(_currenttree,
_initialenhance,_finalenhance);
if(hardMEC(hard))
_decayme->applyHardMatrixElementCorrection(_currenttree);
}
}
}
Branching Evolver::selectTimeLikeBranching(tShowerParticlePtr particle,
ShowerInteraction::Type type) {
Branching fb;
while (true) {
fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type);
// no emission return
if(!fb.kinematics) return fb;
// if emission OK break
if(!timeLikeVetoed(fb,particle)) break;
// otherwise reset scale and continue - SO IS involved in veto algorithm
particle->vetoEmission(fb.type,fb.kinematics->scale());
if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
}
return fb;
}
ShowerParticleVector Evolver::createTimeLikeChildren(tShowerParticlePtr particle, 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
tcPDPtr pdata[2];
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(ids[ix+1]);
if(particle->id()!=ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
ShowerParticleVector children;
for(unsigned int ix=0;ix<2;++ix) {
children.push_back(new_ptr(ShowerParticle(pdata[ix],true)));
if(children[ix]->id()==_progenitor->id()&&!pdata[ix]->stable())
children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass()));
else
children[ix]->set5Momentum(Lorentz5Momentum(pdata[ix]->mass()));
}
return children;
}
bool Evolver::timeLikeShower(tShowerParticlePtr particle,
ShowerInteraction::Type type,
Branching fb, bool first) {
// don't do anything if not needed
if(_limitEmissions == 1 || hardOnly() ||
( _limitEmissions == 2 && _nfs != 0) ||
( _limitEmissions == 4 && _nfs + _nis != 0) ) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return false;
}
ShowerParticleVector children;
int ntry=0;
+ // generate the emission
+ if(!fb.kinematics)
+ fb = selectTimeLikeBranching(particle,type);
+ // no emission, return
+ if(!fb.kinematics) {
+ if(particle->spinInfo()) particle->spinInfo()->develop();
+ return false;
+ }
+ Branching fc[2];
+ bool setupChildren = true;
while (ntry<50) {
++ntry;
- // generate the emission
- if(!fb.kinematics)
- fb = selectTimeLikeBranching(particle,type);
- // no emission, return
- if(!fb.kinematics) {
- if(particle->spinInfo()) particle->spinInfo()->develop();
- return false;
- }
+ assert(fb.kinematics);
// has emitted
// Assign the shower kinematics to the emitting particle.
- particle->showerKinematics(fb.kinematics);
- // generate phi
- fb.kinematics->phi(fb.sudakov->generatePhiForward(*particle,fb.ids,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);
- // 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;
+ if(setupChildren) {
+ particle->showerKinematics(fb.kinematics);
+ // generate phi
+ fb.kinematics->phi(fb.sudakov->generatePhiForward(*particle,fb.ids,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);
+ // \todo check this
+ // 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
- Branching fc[2] = {selectTimeLikeBranching(children[0],type),
- selectTimeLikeBranching(children[1],type)};
- // old recon option
+ if(UseRandom::rndbool()) {
+ fc[0] = selectTimeLikeBranching(children[0],type);
+ if(_reconOpt==4) {
+ 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]!=ParticleID::g) q2 += sqr(vm[0]);
+ masses[ix+1] = sqrt(q2);
+ }
+ else {
+ masses[ix+1] = virtualMasses[ix+1];
+ }
+ }
+ masses[0] = fb.ids[0]!=ParticleID::g ? virtualMasses[0] : ZERO;
+ double z = fb.kinematics->z();
+ children[1]->scales().Max_Q2 = (1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0])-sqr(masses[1])/z);
+ }
+ fc[1] = selectTimeLikeBranching(children[1],type);
+ }
+ else {
+ fc[1] = selectTimeLikeBranching(children[1],type);
+ if(_reconOpt==4) {
+ 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]!=ParticleID::g) q2 += sqr(vm[0]);
+ masses[ix+1] = sqrt(q2);
+ }
+ else {
+ masses[ix+1] = virtualMasses[ix+1];
+ }
+ }
+ masses[0] = fb.ids[0]!=ParticleID::g ? virtualMasses[0] : ZERO;
+ double z = fb.kinematics->z();
+ children[0]->scales().Max_Q2 = (1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0])-sqr(masses[2])/(1.-z));
+ }
+ fc[0] = selectTimeLikeBranching(children[0],type);
+ }
+ // old default
if(_reconOpt==0) {
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
+ break;
}
+ // Herwig default
else if(_reconOpt==1) {
// shower the first particle
if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
// shower the second particle
if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
// branching has happened
- particle->showerKinematics()->
- updateParent(particle, children,fb.type);
+ 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());
- if(_massVetoOption==1) particle->vetoEmission(fb.type,fb.kinematics->scale());
- fb = Branching();
+ 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);
+ // no emission, return
+ if(!fb.kinematics) {
+ if(particle->spinInfo()) particle->spinInfo()->develop();
+ return false;
+ }
+ setupChildren = true;
continue;
}
+ else
+ break;
}
- else if(_reconOpt==2) {
+ // veto children
+ else if(_reconOpt>=2) {
// cut-off masses for the branching
const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids);
// compute the masses of the children
Energy masses[3];
for(unsigned int ix=0;ix<2;++ix) {
- if(fc[ix].kinematics) {
- const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids);
- Energy2 q2 =
- fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale());
- if(fc[ix].ids[0]!=ParticleID::g) q2 += sqr(vm[0]);
- masses[ix+1] = sqrt(q2);
- }
- else {
- masses[ix+1] = virtualMasses[ix+1];
- }
+ 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]!=ParticleID::g) q2 += sqr(vm[0]);
+ masses[ix+1] = sqrt(q2);
+ }
+ else {
+ masses[ix+1] = virtualMasses[ix+1];
+ }
}
masses[0] = fb.ids[0]!=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;
+ 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) {
- // branching has happened
- particle->showerKinematics()->
- updateParent(particle, children,fb.type);
- // shower the first particle
- if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
- if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
- // shower the second particle
- if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
- if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
+ break;
}
else {
- particle->showerKinematics(ShoKinPtr());
- for(unsigned int ix=0;ix<children.size();++ix)
- particle->abandonChild(children[ix]);
- children.clear();
- if(_massVetoOption==1) particle->vetoEmission(fb.type,fb.kinematics->scale());
- if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
- fb = Branching();
- continue;
+ // 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);
+ }
}
}
- break;
};
+
+
+
+
+
+
+
+
+
+ // // generate the emission
+ // if(!fb.kinematics)
+ // fb = selectTimeLikeBranching(particle,type);
+ // // no emission, return
+ // if(!fb.kinematics) {
+ // if(particle->spinInfo()) particle->spinInfo()->develop();
+ // return false;
+ // }
+
+
+
+
+
+
+
+
+
+ // // old recon option
+
+
+
+ // 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]!=ParticleID::g) q2 += sqr(vm[0]);
+ // masses[ix+1] = sqrt(q2);
+ // }
+ // else {
+ // masses[ix+1] = virtualMasses[ix+1];
+ // }
+ // }
+ // masses[0] = fb.ids[0]!=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) {
+ // // branching has happened
+ // particle->showerKinematics()->
+ // updateParent(particle, children,fb.type);
+ // // 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();
+ // }
+ // else {
+ // particle->showerKinematics(ShoKinPtr());
+ // for(unsigned int ix=0;ix<children.size();++ix)
+ // particle->abandonChild(children[ix]);
+ // children.clear();
+ // if(_massVetoOption==1) particle->vetoEmission(fb.type,fb.kinematics->scale());
+ // if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr());
+ // fb = Branching();
+ // continue;
+ // }
+ // }
+ // break;
+ // };
+
+
+ // // shower the first particle
+ // if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false);
+ // if(children[0]->spinInfo()) children[0]->spinInfo()->develop();
+ // // shower the second particle
+ // if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false);
+ // if(children[1]->spinInfo()) children[1]->spinInfo()->develop();
+ // // branching has happened
+ // if(_reconOpt!=0)
+ // 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
Evolver::spaceLikeShower(tShowerParticlePtr particle, PPtr beam,
ShowerInteraction::Type type) {
//using the pdf's associated with the ShowerHandler assures, that
//modified pdf's are used for the secondary interactions via
//CascadeHandler::resetPDFs(...)
tcPDFPtr pdf;
if(ShowerHandler::currentHandler()->firstPDF().particle() == _beam)
pdf = ShowerHandler::currentHandler()->firstPDF().pdf();
if(ShowerHandler::currentHandler()->secondPDF().particle() == _beam)
pdf = ShowerHandler::currentHandler()->secondPDF().pdf();
Energy freeze = ShowerHandler::currentHandler()->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]={getParticleData(bb.ids[0]),
getParticleData(bb.ids[2])};
if(particle->id()!=bb.ids[1]) {
if(part[0]->CC()) part[0]=part[0]->CC();
if(part[1]->CC()) part[1]=part[1]->CC();
}
// Now create the actual particles, make the otherChild a final state
// particle, while the newParent is not
ShowerParticlePtr newParent=new_ptr(ShowerParticle(part[0],false));
ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true));
ShowerParticleVector theChildren;
theChildren.push_back(particle);
theChildren.push_back(otherChild);
//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));
}
}
+ // \todo check this
particle->showerKinematics()->
- updateChildren(newParent, theChildren,bb.type);
+ updateChildren(newParent, theChildren,bb.type,false);
if(_limitEmissions!=0) {
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
// perform the shower of the final-state particle
timeLikeShower(otherChild,type,Branching(),true);
updateHistory(otherChild);
if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop();
// return the emitted
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
void Evolver::showerDecay(ShowerTreePtr decay) {
_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());
unsigned int interactionTry=0;
do {
try {
// 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();
}
// and then return
return;
}
catch (InteractionVeto) {
currentTree()->clear();
++interactionTry;
}
}
while(interactionTry<=5);
throw Exception() << "Too many tries for QED shower in Evolver::showerDecay()"
<< Exception::eventerror;
}
bool Evolver::spaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass,ShowerInteraction::Type type) {
Branching fb;
while (true) {
fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass,
_initialenhance,type);
// return if no radiation
if(!fb.kinematics) return false;
// if not vetoed break
if(!spaceLikeDecayVetoed(fb,particle)) break;
// otherwise reset scale and continue
particle->vetoEmission(fb.type,fb.kinematics->scale());
}
// has emitted
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// For the time being we are considering only 1->2 branching
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
tcPDPtr pdata[2];
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]);
if(particle->id()!=fb.ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
ShowerParticleVector theChildren;
for(unsigned int ix=0;ix<2;++ix) {
theChildren.push_back(new_ptr(ShowerParticle(pdata[ix],true)));
if(theChildren[ix]->id()==_progenitor->id()&&!pdata[ix]->stable())
theChildren[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass()));
else
theChildren[ix]->set5Momentum(Lorentz5Momentum(pdata[ix]->mass()));
}
// some code moved to updateChildren
+ // \todo check this
particle->showerKinematics()->
- updateChildren(particle, theChildren, fb.type);
+ updateChildren(particle, theChildren, fb.type,false);
// In the case of splittings which involves coloured particles,
// set properly the colour flow of the branching.
// update the history if needed
_currenttree->updateInitialStateShowerProduct(_progenitor,theChildren[0]);
_currenttree->addInitialStateBranching(particle,theChildren[0],theChildren[1]);
// shower the first particle
spaceLikeDecayShower(theChildren[0],maxScales,minmass,type);
// shower the second particle
timeLikeShower(theChildren[1],type,Branching(),true);
updateHistory(theChildren[1]);
// branching has happened
return true;
}
vector<ShowerProgenitorPtr> Evolver::setupShower(bool hard) {
// generate POWHEG hard emission if needed
if(_hardEmissionMode>0) hardestEmission(hard);
ShowerInteraction::Type inter = interactions_[0];
if(_hardtree&&inter!=ShowerInteraction::Both) {
inter = _hardtree->interaction();
}
// set the initial colour partners
setEvolutionPartners(hard,inter,false);
// generate hard me if needed
if(_hardEmissionMode==0 ||
(!hard && _hardEmissionMode==-1)) hardMatrixElementCorrection(hard);
// get the particles to be showered
vector<ShowerProgenitorPtr> particlesToShower =
currentTree()->extractProgenitors();
// remake the colour partners if needed
if(_currenttree->hardMatrixElementCorrection()) {
setEvolutionPartners(hard,interactions_[0],true);
_currenttree->resetShowerProducts();
}
// return the answer
return particlesToShower;
}
void Evolver::setEvolutionPartners(bool hard,ShowerInteraction::Type type,
bool clear) {
// match the particles in the ShowerTree and hardTree
if(hardTree() && !hardTree()->connect(currentTree()))
throw Exception() << "Can't match trees in "
<< "Evolver::setEvolutionPartners()"
<< Exception::eventerror;
// extract the progenitors
vector<ShowerParticlePtr> particles =
currentTree()->extractProgenitorParticles();
// clear the partners if needed
if(clear) {
for(unsigned int ix=0;ix<particles.size();++ix) {
particles[ix]->partner(ShowerParticlePtr());
particles[ix]->clearPartners();
}
}
// sort out the colour partners
if(hardTree()) {
// find the partner
for(unsigned int ix=0;ix<particles.size();++ix) {
tHardBranchingPtr partner =
hardTree()->particles()[particles[ix]]->colourPartner();
if(!partner) continue;
for(map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
it=hardTree()->particles().begin();
it!=hardTree()->particles().end();++it) {
if(it->second==partner) particles[ix]->partner(it->first);
}
if(!particles[ix]->partner())
throw Exception() << "Can't match partners in "
<< "Evolver::setEvolutionPartners()"
<< Exception::eventerror;
}
}
// Set the initial evolution scales
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,type,!_hardtree);
if(hardTree() && _hardPOWHEG) {
bool tooHard=false;
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end();
for(unsigned int ix=0;ix<particles.size();++ix) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(particles[ix]);
Energy hardScale(ZERO);
ShowerPartnerType::Type type(ShowerPartnerType::Undefined);
// final-state
if(particles[ix]->isFinalState()) {
if(mit!= eit && !mit->second->children().empty()) {
hardScale = mit->second->scale();
type = mit->second->type();
}
}
// initial-state
else {
if(mit!= eit && mit->second->parent()) {
hardScale = mit->second->parent()->scale();
type = mit->second->parent()->type();
}
}
if(type!=ShowerPartnerType::Undefined) {
if(type==ShowerPartnerType::QED) {
tooHard |= particles[ix]->scales().QED_noAO<hardScale;
}
else if(type==ShowerPartnerType::QCDColourLine) {
tooHard |= particles[ix]->scales().QCD_c_noAO<hardScale;
}
else if(type==ShowerPartnerType::QCDAntiColourLine) {
tooHard |= particles[ix]->scales().QCD_ac_noAO<hardScale;
}
}
}
if(tooHard) convertHardTree(hard,type);
}
}
void Evolver::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 Evolver::startTimeLikeShower(ShowerInteraction::Type type) {
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,true);
if(output) updateHistory(progenitor()->progenitor());
return output;
}
}
bool output = hardOnly() ? false :
timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ;
if(output) updateHistory(progenitor()->progenitor());
return output;
}
bool Evolver::startSpaceLikeShower(PPtr parent, ShowerInteraction::Type type) {
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 );
}
}
return hardOnly() ? false :
spaceLikeShower(progenitor()->progenitor(),parent,type);
}
bool Evolver::
startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass,ShowerInteraction::Type type) {
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);
}
}
return hardOnly() ? false :
spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type);
}
bool Evolver::timeLikeVetoed(const Branching & fb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = fb.type==ShowerPartnerType::QED ?
ShowerInteraction::QED : ShowerInteraction::QCD;
// check whether emission was harder than largest pt of hard subprocess
if ( hardVetoFS() && fb.kinematics->pT() > _progenitor->maxHardPt() )
return true;
// soft matrix element correction veto
if( softMEC()) {
if(_hardme && _hardme->hasMECorrection()) {
if(_hardme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
else if(_decayme && _decayme->hasMECorrection()) {
if(_decayme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
}
// veto on maximum pt
if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true;
// general vetos
if (fb.kinematics && !_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoTimeLike(_progenitor,particle,fb);
switch((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
}
if(vetoed) return true;
}
if ( ShowerHandler::currentHandler()->firstInteraction() &&
ShowerHandler::currentHandler()->profileScales() ) {
double weight =
ShowerHandler::currentHandler()->profileScales()->
hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT());
if ( UseRandom::rnd() > weight )
return true;
}
return false;
}
bool Evolver::spaceLikeVetoed(const Branching & bb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = bb.type==ShowerPartnerType::QED ?
ShowerInteraction::QED : ShowerInteraction::QCD;
// check whether emission was harder than largest pt of hard subprocess
if (hardVetoIS() && bb.kinematics->pT() > _progenitor->maxHardPt())
return true;
// apply the soft correction
if( softMEC() && _hardme && _hardme->hasMECorrection() ) {
if(_hardme->softMatrixElementVeto(_progenitor,particle,bb))
return true;
}
// the more general vetos
// check vs max pt for the shower
if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true;
if (!_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoSpaceLike(_progenitor,particle,bb);
switch ((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
}
if (vetoed) return true;
}
if ( ShowerHandler::currentHandler()->firstInteraction() &&
ShowerHandler::currentHandler()->profileScales() ) {
double weight =
ShowerHandler::currentHandler()->profileScales()->
hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT());
if ( UseRandom::rnd() > weight )
return true;
}
return false;
}
bool Evolver::spaceLikeDecayVetoed( const Branching & fb,
ShowerParticlePtr particle) {
// work out type of interaction
ShowerInteraction::Type type = fb.type==ShowerPartnerType::QED ?
ShowerInteraction::QED : ShowerInteraction::QCD;
// apply the soft correction
if( softMEC() && _decayme && _decayme->hasMECorrection() ) {
if(_decayme->softMatrixElementVeto(_progenitor,particle,fb))
return true;
}
// veto on hardest pt in the shower
if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true;
// general vetos
if (!_vetoes.empty()) {
bool vetoed=false;
for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin();
v != _vetoes.end(); ++v) {
bool test = (**v).vetoSpaceLike(_progenitor,particle,fb);
switch((**v).vetoType()) {
case ShowerVeto::Emission:
vetoed |= test;
break;
case ShowerVeto::Shower:
if(test) throw VetoShower();
break;
case ShowerVeto::Event:
if(test) throw Veto();
break;
}
if (vetoed) return true;
}
}
return false;
}
void Evolver::hardestEmission(bool hard) {
HardTreePtr ISRTree;
if( ( _hardme && _hardme->hasPOWHEGCorrection()!=0 && _hardEmissionMode< 2) ||
( _decayme && _decayme->hasPOWHEGCorrection()!=0 && _hardEmissionMode!=2) ) {
if(_hardme) {
assert(hard);
if(interaction_==4) {
vector<ShowerInteraction::Type> inter(2);
inter[0] = ShowerInteraction::QCD;
inter[1] = ShowerInteraction::QED;
_hardtree = _hardme->generateHardest( currentTree(),inter );
}
else {
_hardtree = _hardme->generateHardest( currentTree(),interactions_ );
}
}
else {
assert(!hard);
_hardtree = _decayme->generateHardest( currentTree() );
}
// store initial state POWHEG radiation
if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1)
ISRTree=_hardtree;
}
else if (_hardEmissionMode>1 && hard) {
// Get minimum pT cutoff used in shower approximation
Energy maxpt = 1.*GeV;
int colouredIn = 0;
int colouredOut = 0;
for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it
= currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if( it->second->coloured() ) colouredOut+=1;
}
for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it
= currentTree()->incomingLines().begin();
it != currentTree()->incomingLines().end(); ++it ) {
if( ! it->second->coloured() ) colouredIn+=1;
}
if ( theShowerApproximation ){
if ( theShowerApproximation->ffPtCut() == theShowerApproximation->fiPtCut() &&
theShowerApproximation->ffPtCut() == theShowerApproximation->iiPtCut() )
maxpt = theShowerApproximation->ffPtCut();
else if ( colouredIn == 2 && colouredOut == 0 )
maxpt = theShowerApproximation->iiPtCut();
else if ( colouredIn == 0 && colouredOut > 1 )
maxpt = theShowerApproximation->ffPtCut();
else if ( colouredIn == 2 && colouredOut == 1 )
maxpt = min(theShowerApproximation->iiPtCut(), theShowerApproximation->fiPtCut());
else if ( colouredIn == 1 && colouredOut > 1 )
maxpt = min(theShowerApproximation->ffPtCut(), theShowerApproximation->fiPtCut());
else
maxpt = min(min(theShowerApproximation->iiPtCut(), theShowerApproximation->fiPtCut()),
theShowerApproximation->ffPtCut());
}
// Generate hardtree from born and real emission subprocesses
_hardtree = ShowerHandler::currentHandler()->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(ShowerHandler::currentHandler()->lastXCombPtr()->lastCentralScale()),maxpt);
// Set maxpt to pT of emission when showering POWHEG real-emission subprocesses
if (!isPowhegSEvent && !isPowhegHEvent){
vector<int> outGluon;
vector<int> outQuark;
map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it;
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6) outQuark.push_back(it->second->id());
if ( it->second->id()==21 ) outGluon.push_back(it->second->id());
}
if (outGluon.size() + outQuark.size() == 1){
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6 || it->second->id()==21 )
maxpt = it->second->momentum().perp();
}
}
else if (outGluon.size() + outQuark.size() > 1){
// assume qqbar pair from a Z/gamma
if (outGluon.size()==1 && outQuark.size() == 2 && outQuark[0]==-outQuark[1]){
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( it->second->id()==21 )
maxpt = it->second->momentum().perp();
}
}
// otherwise take the lowest pT avoiding born DY events
else {
maxpt = generator()->maximumCMEnergy();
for( it = currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if ( abs(it->second->id())< 6 || it->second->id()==21 )
maxpt = min(maxpt,it->second->momentum().perp());
}
}
}
}
// set maximum pT for subsequent emissions from S events
if ( isPowhegSEvent || (!isPowhegSEvent && !isPowhegHEvent)){
for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it
= currentTree()->outgoingLines().begin();
it != currentTree()->outgoingLines().end(); ++it ) {
if( ! it->second->coloured() ) continue;
it->first->maximumpT(maxpt, ShowerInteraction::QCD );
}
for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it
= currentTree()->incomingLines().begin();
it != currentTree()->incomingLines().end(); ++it ) {
if( ! it->second->coloured() ) continue;
it->first->maximumpT(maxpt, ShowerInteraction::QCD );
}
}
}
else
_hardtree = ShowerHandler::currentHandler()->generateCKKW(currentTree());
// if hard me doesn't have a FSR powheg
// correction use decay powheg correction
if (_hardme && _hardme->hasPOWHEGCorrection()<2) {
// check for intermediate colour singlet resonance
const ParticleVector inter = _hardme->subProcess()->intermediates();
if (inter.size()!=1 ||
inter[0]->momentum().m2()/GeV2 < 0 ||
inter[0]->dataPtr()->iColour()!=PDT::Colour0){
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
map<ShowerProgenitorPtr, tShowerParticlePtr > out = currentTree()->outgoingLines();
// ignore cases where outgoing particles are not coloured
if (out.size()!=2 ||
out. begin()->second->dataPtr()->iColour()==PDT::Colour0 ||
out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) {
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// look up decay mode
tDMPtr dm;
string tag;
string inParticle = inter[0]->dataPtr()->name() + "->";
vector<string> outParticles;
outParticles.push_back(out.begin ()->first->progenitor()->dataPtr()->name());
outParticles.push_back(out.rbegin()->first->progenitor()->dataPtr()->name());
for (int it=0; it<2; ++it){
tag = inParticle + outParticles[it] + "," + outParticles[(it+1)%2] + ";";
dm = generator()->findDecayMode(tag);
if(dm) break;
}
// get the decayer
HwDecayerBasePtr decayer;
if(dm) decayer = dynamic_ptr_cast<HwDecayerBasePtr>(dm->decayer());
// check if decayer has a FSR POWHEG correction
if (!decayer || decayer->hasPOWHEGCorrection()<2){
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// generate the hardest emission
ShowerDecayMap decay;
PPtr in = new_ptr(*inter[0]);
ShowerTreePtr decayTree = new_ptr(ShowerTree(in, decay));
HardTreePtr FSRTree = decayer->generateHardest(decayTree);
if (!FSRTree) {
if(_hardtree) connectTrees(currentTree(),_hardtree,hard);
return;
}
// if there is no ISRTree make _hardtree from FSRTree
if (!ISRTree){
vector<HardBranchingPtr> inBranch,hardBranch;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit =currentTree()->incomingLines().begin();
cit!=currentTree()->incomingLines().end();++cit ) {
inBranch.push_back(new_ptr(HardBranching(cit->second,SudakovPtr(),
HardBranchingPtr(),
HardBranching::Incoming)));
inBranch.back()->beam(cit->first->original()->parents()[0]);
hardBranch.push_back(inBranch.back());
}
if(inBranch[0]->branchingParticle()->dataPtr()->coloured()) {
inBranch[0]->colourPartner(inBranch[1]);
inBranch[1]->colourPartner(inBranch[0]);
}
for(set<HardBranchingPtr>::iterator it=FSRTree->branchings().begin();
it!=FSRTree->branchings().end();++it) {
if((**it).branchingParticle()->id()!=in->id())
hardBranch.push_back(*it);
}
hardBranch[2]->colourPartner(hardBranch[3]);
hardBranch[3]->colourPartner(hardBranch[2]);
HardTreePtr newTree = new_ptr(HardTree(hardBranch,inBranch,
ShowerInteraction::QCD));
_hardtree = newTree;
}
// Otherwise modify the ISRTree to include the emission in FSRTree
else {
vector<tShowerParticlePtr> FSROut, ISROut;
set<HardBranchingPtr>::iterator itFSR, itISR;
// get outgoing particles
for(itFSR =FSRTree->branchings().begin();
itFSR!=FSRTree->branchings().end();++itFSR){
if ((**itFSR).status()==HardBranching::Outgoing)
FSROut.push_back((*itFSR)->branchingParticle());
}
for(itISR =ISRTree->branchings().begin();
itISR!=ISRTree->branchings().end();++itISR){
if ((**itISR).status()==HardBranching::Outgoing)
ISROut.push_back((*itISR)->branchingParticle());
}
// find COM frame formed by outgoing particles
LorentzRotation eventFrameFSR, eventFrameISR;
eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM());
eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM());
// find rotation between ISR and FSR frames
int j=0;
if (ISROut[0]->id()!=FSROut[0]->id()) j=1;
eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()-
(eventFrameISR*ISROut[j]->momentum()).phi() );
eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()-
(eventFrameISR*ISROut[j]->momentum()).theta() );
eventFrameISR.invert();
for (itFSR=FSRTree->branchings().begin();
itFSR!=FSRTree->branchings().end();++itFSR){
if ((**itFSR).branchingParticle()->id()==in->id()) continue;
for (itISR =ISRTree->branchings().begin();
itISR!=ISRTree->branchings().end();++itISR){
if ((**itISR).status()==HardBranching::Incoming) continue;
if ((**itFSR).branchingParticle()->id()==
(**itISR).branchingParticle()->id()){
// rotate FSRTree particle to ISRTree event frame
(**itISR).branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).branchingParticle()->momentum());
(**itISR).branchingParticle()->rescaleMass();
// add the children of the FSRTree particles to the ISRTree
if(!(**itFSR).children().empty()){
(**itISR).addChild((**itFSR).children()[0]);
(**itISR).addChild((**itFSR).children()[1]);
// rotate momenta to ISRTree event frame
(**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).children()[0]->branchingParticle()->momentum());
(**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR*
eventFrameFSR*
(**itFSR).children()[1]->branchingParticle()->momentum());
}
}
}
}
_hardtree = ISRTree;
}
}
if(_hardtree){
connectTrees(currentTree(),_hardtree,hard);
}
}
bool Evolver::truncatedTimeLikeShower(tShowerParticlePtr particle,
HardBranchingPtr branch,
ShowerInteraction::Type type,bool first) {
int ntry=0;
do {
++ntry;
Branching fb;
unsigned int iout=0;
tcPDPtr pdata[2];
while (true) {
// no truncated shower break
if(!isTruncatedShowerON()||hardOnly()) break;
// generate emission
fb=splittingGenerator()->chooseForwardBranching(*particle,1.,type);
// no emission break
if(!fb.kinematics) break;
// check haven't evolved too far
if(fb.kinematics->scale() < branch->scale()) {
fb=Branching();
break;
}
// get the particle data objects
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]);
if(particle->id()!=fb.ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
// find the truncated line
iout=0;
if(pdata[0]->id()!=pdata[1]->id()) {
if(pdata[0]->id()==particle->id()) iout=1;
else if (pdata[1]->id()==particle->id()) iout=2;
}
else if(pdata[0]->id()==particle->id()) {
if(fb.kinematics->z()>0.5) iout=1;
else iout=2;
}
// apply the vetos for the truncated shower
// no flavour changing branchings
if(iout==0) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z();
// only if same interaction for forced branching
ShowerInteraction::Type type2 = fb.type==ShowerPartnerType::QED ?
ShowerInteraction::QED : ShowerInteraction::QCD;
// 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;
}
// should do base class vetos as well
if(timeLikeVetoed(fb,particle)) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
break;
}
// if no branching force truncated emission
if(!fb.kinematics) {
// construct the kinematics for the hard emission
ShoKinPtr showerKin=
branch->sudakov()->createFinalStateBranching(branch->scale(),
branch->children()[0]->z(),
branch->phi(),
branch->children()[0]->pT());
showerKin->initialize( *particle,PPtr() );
IdList idlist(3);
idlist[0] = particle->id();
idlist[1] = branch->children()[0]->branchingParticle()->id();
idlist[2] = branch->children()[1]->branchingParticle()->id();
fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() );
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics( fb.kinematics );
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// Assign the splitting function to the emitting particle.
// For the time being we are considering only 1->2 branching
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
ShowerParticleVector theChildren;
for(unsigned int ix=0;ix<2;++ix) {
theChildren.push_back(new_ptr(ShowerParticle(branch->children()[ix]->
branchingParticle()->dataPtr(),true)));
if(theChildren[ix]->id()==_progenitor->id()&&!theChildren[ix]->dataPtr()->stable())
theChildren[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass()));
else
theChildren[ix]->set5Momentum(Lorentz5Momentum(theChildren[ix]->dataPtr()->mass()));
}
+ // \todo check this
particle->showerKinematics()->
- updateChildren(particle, theChildren,fb.type);
+ updateChildren(particle, theChildren,fb.type,false);
for(unsigned int ix=0;ix<2;++ix) {
theChildren[ix]->scales().QED = min(theChildren[ix]->scales().QED ,particle->scales().QED );
theChildren[ix]->scales().QED_noAO = min(theChildren[ix]->scales().QED_noAO ,particle->scales().QED_noAO );
theChildren[ix]->scales().QCD_c = min(theChildren[ix]->scales().QCD_c ,particle->scales().QCD_c );
theChildren[ix]->scales().QCD_c_noAO = min(theChildren[ix]->scales().QCD_c_noAO ,particle->scales().QCD_c_noAO );
theChildren[ix]->scales().QCD_ac = min(theChildren[ix]->scales().QCD_ac ,particle->scales().QCD_ac );
theChildren[ix]->scales().QCD_ac_noAO = min(theChildren[ix]->scales().QCD_ac_noAO,particle->scales().QCD_ac_noAO);
}
// shower the first particle
if( branch->children()[0]->children().empty() ) {
if( ! hardOnly() )
timeLikeShower(theChildren[0],type,Branching(),false);
}
else {
truncatedTimeLikeShower( theChildren[0],branch->children()[0],type,false);
}
// shower the second particle
if( branch->children()[1]->children().empty() ) {
if( ! hardOnly() )
timeLikeShower( theChildren[1] , type,Branching(),false);
}
else {
truncatedTimeLikeShower( theChildren[1],branch->children()[1] ,type,false);
}
// that's if for old approach
if(_reconOpt==0) return true;
// branching has happened
particle->showerKinematics()->updateParent(particle, theChildren,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<theChildren.size();++ix)
particle->abandonChild(theChildren[ix]);
theChildren.clear();
continue;
}
else {
if(first&&!theChildren.empty())
particle->showerKinematics()->resetChildren(particle,theChildren);
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
}
// has emitted
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// Assign the splitting function to the emitting particle.
// For the time being we are considering only 1->2 branching
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
ShowerParticleVector theChildren;
for(unsigned int ix=0;ix<2;++ix) {
theChildren.push_back( new_ptr( ShowerParticle( pdata[ix], true ) ) );
if(theChildren[ix]->id()==_progenitor->id()&&!pdata[ix]->stable())
theChildren[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass()));
else
theChildren[ix]->set5Momentum(Lorentz5Momentum(pdata[ix]->mass()));
}
+ // \todo check this
particle->showerKinematics()->
- updateChildren( particle, theChildren , fb.type);
+ updateChildren( particle, theChildren , fb.type,false);
// shower the first particle
if( iout == 1 ) truncatedTimeLikeShower( theChildren[0], branch , type ,false);
else timeLikeShower( theChildren[0] , type,Branching(),false);
// shower the second particle
if( iout == 2 ) truncatedTimeLikeShower( theChildren[1], branch , type ,false);
else timeLikeShower( theChildren[1] , type,Branching(),false);
// that's if for old approach
if(_reconOpt==0) return true;
// branching has happened
particle->showerKinematics()->updateParent(particle, theChildren,fb.type);
// clean up the vetoed emission
if(particle->virtualMass()==ZERO) {
particle->showerKinematics(ShoKinPtr());
for(unsigned int ix=0;ix<theChildren.size();++ix)
particle->abandonChild(theChildren[ix]);
theChildren.clear();
}
else {
if(first&&!theChildren.empty())
particle->showerKinematics()->resetChildren(particle,theChildren);
if(particle->spinInfo()) particle->spinInfo()->develop();
return true;
}
}
while(ntry<50);
return false;
}
bool Evolver::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam,
HardBranchingPtr branch,
ShowerInteraction::Type type) {
tcPDFPtr pdf;
if(ShowerHandler::currentHandler()->firstPDF().particle() == beamParticle())
pdf = ShowerHandler::currentHandler()->firstPDF().pdf();
if(ShowerHandler::currentHandler()->secondPDF().particle() == beamParticle())
pdf = ShowerHandler::currentHandler()->secondPDF().pdf();
Energy freeze = ShowerHandler::currentHandler()->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] = getParticleData( bb.ids[0] );
part[1] = getParticleData( bb.ids[2] );
//is emitter anti-particle
if( particle->id() != bb.ids[1]) {
if( part[0]->CC() ) part[0] = part[0]->CC();
if( part[1]->CC() ) part[1] = part[1]->CC();
}
double zsplit = bb.kinematics->z();
// apply the vetos for the truncated shower
// if doesn't carry most of momentum
ShowerInteraction::Type type2 = bb.type==ShowerPartnerType::QED ?
ShowerInteraction::QED : ShowerInteraction::QCD;
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() );
kinematics->initialize( *particle, beam );
// 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 ) );
}
}
+ // \todo
particle->showerKinematics()->
- updateChildren( newParent, theChildren,bb.type);
+ 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,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 ) );
}
}
+ // \todo
particle->showerKinematics()->
- updateChildren( newParent, theChildren, bb.type);
+ 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 Evolver::
truncatedSpaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minmass, HardBranchingPtr branch,
ShowerInteraction::Type type) {
Branching fb;
unsigned int iout=0;
tcPDPtr pdata[2];
while (true) {
// no truncated shower break
if(!isTruncatedShowerON()||hardOnly()) break;
fb=splittingGenerator()->chooseDecayBranching(*particle,maxScales,minmass,1.,type);
// return if no radiation
if(!fb.kinematics) break;
// check haven't evolved too far
if(fb.kinematics->scale() < branch->scale()) {
fb=Branching();
break;
}
// get the particle data objects
for(unsigned int ix=0;ix<2;++ix) pdata[ix]=getParticleData(fb.ids[ix+1]);
if(particle->id()!=fb.ids[0]) {
for(unsigned int ix=0;ix<2;++ix) {
tPDPtr cc(pdata[ix]->CC());
if(cc) pdata[ix]=cc;
}
}
// find the truncated line
iout=0;
if(pdata[0]->id()!=pdata[1]->id()) {
if(pdata[0]->id()==particle->id()) iout=1;
else if (pdata[1]->id()==particle->id()) iout=2;
}
else if(pdata[0]->id()==particle->id()) {
if(fb.kinematics->z()>0.5) iout=1;
else iout=2;
}
// apply the vetos for the truncated shower
// no flavour changing branchings
if(iout==0) {
particle->vetoEmission(fb.type,fb.kinematics->scale());
continue;
}
ShowerInteraction::Type type2 = fb.type==ShowerPartnerType::QED ?
ShowerInteraction::QED : ShowerInteraction::QCD;
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;
}
// should do base class vetos as well
// if not vetoed break
if(!spaceLikeDecayVetoed(fb,particle)) break;
// otherwise reset scale and continue
particle->vetoEmission(fb.type,fb.kinematics->scale());
}
// this may not be currently used but in principle could be
// and should be included
if (!fb.kinematics) {
// construct the kinematics for the hard emission
ShoKinPtr showerKin=
branch->sudakov()->createDecayBranching(branch->scale(),
branch->children()[0]->z(),
branch->phi(),
branch->children()[0]->pT());
showerKin->initialize( *particle,PPtr() );
IdList idlist(3);
idlist[0] = particle->id();
idlist[1] = branch->children()[0]->branchingParticle()->id();
idlist[2] = branch->children()[1]->branchingParticle()->id();
// create the branching
fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine );
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics( fb.kinematics );
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// Assign the splitting function to the emitting particle.
// For the time being we are considering only 1->2 branching
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
ShowerParticleVector theChildren;
theChildren.push_back(new_ptr(ShowerParticle(branch->children()[0]->
branchingParticle()->dataPtr(),true)));
theChildren.push_back(new_ptr(ShowerParticle(branch->children()[1]->
branchingParticle()->dataPtr(),true)));
+ // \todo
particle->showerKinematics()->
- updateChildren(particle, theChildren,fb.type);
+ updateChildren(particle, theChildren,fb.type,false);
if(theChildren[0]->id()==particle->id()) {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),theChildren[0]);
currentTree()->addInitialStateBranching(particle,theChildren[0],theChildren[1]);
// shower the space-like particle
if( branch->children()[0]->children().empty() ) {
if( ! hardOnly() ) spaceLikeDecayShower(theChildren[0],maxScales,minmass,type);
}
else {
truncatedSpaceLikeDecayShower( theChildren[0],maxScales,minmass,
branch->children()[0],type);
}
// shower the second particle
if( branch->children()[1]->children().empty() ) {
if( ! hardOnly() ) timeLikeShower( theChildren[1] , type,Branching(), true);
}
else {
truncatedTimeLikeShower( theChildren[1],branch->children()[1] ,type,true);
}
updateHistory(theChildren[1]);
}
else {
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),theChildren[1]);
currentTree()->addInitialStateBranching(particle,theChildren[0],theChildren[1]);
// shower the space-like particle
if( branch->children()[1]->children().empty() ) {
if( ! hardOnly() ) spaceLikeDecayShower(theChildren[1],maxScales,minmass,type);
}
else {
truncatedSpaceLikeDecayShower( theChildren[1],maxScales,minmass,
branch->children()[1],type);
}
// shower the second particle
if( branch->children()[0]->children().empty() ) {
if( ! hardOnly() ) timeLikeShower( theChildren[0] , type, Branching(),true);
}
else {
truncatedTimeLikeShower( theChildren[0],branch->children()[0] ,type,true);
}
updateHistory(theChildren[0]);
}
return true;
}
// has emitted
// Assign the shower kinematics to the emitting particle.
particle->showerKinematics(fb.kinematics);
if(fb.kinematics->pT()>progenitor()->highestpT())
progenitor()->highestpT(fb.kinematics->pT());
// For the time being we are considering only 1->2 branching
// Create the ShowerParticle objects for the two children of
// the emitting particle; set the parent/child relationship
// if same as definition create particles, otherwise create cc
ShowerParticleVector theChildren;
theChildren.push_back(new_ptr(ShowerParticle(pdata[0],true)));
theChildren.push_back(new_ptr(ShowerParticle(pdata[1],true)));
- particle->showerKinematics()->updateChildren(particle, theChildren,fb.type);
+ // \todo
+ particle->showerKinematics()->updateChildren(particle, theChildren,fb.type,false);
// In the case of splittings which involves coloured particles,
// set properly the colour flow of the branching.
// update the history if needed
currentTree()->updateInitialStateShowerProduct(progenitor(),theChildren[0]);
currentTree()->addInitialStateBranching(particle,theChildren[0],theChildren[1]);
// shower the first particle
truncatedSpaceLikeDecayShower(theChildren[0],maxScales,minmass,branch,type);
// shower the second particle
timeLikeShower(theChildren[1],type,Branching(),true);
updateHistory(theChildren[1]);
// branching has happened
return true;
}
bool Evolver::constructDecayTree(vector<ShowerProgenitorPtr> & particlesToShower,
ShowerInteraction::Type inter) {
Energy ptmax(-GeV);
// get the maximum pt is all ready a hard tree
if(hardTree()) {
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(particlesToShower[ix]->maximumpT(inter)>ptmax&&
particlesToShower[ix]->progenitor()->isFinalState())
ptmax = particlesToShower[ix]->maximumpT(inter);
}
}
vector<HardBranchingPtr> spaceBranchings,allBranchings;
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(particlesToShower[ix]->progenitor()->isFinalState()) {
HardBranchingPtr newBranch;
if(particlesToShower[ix]->hasEmitted()) {
newBranch =
new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
particlesToShower[ix]->progenitor()->
showerKinematics()->SudakovFormFactor(),
HardBranchingPtr(),HardBranching::Outgoing));
constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor());
}
else {
newBranch =
new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
SudakovPtr(),HardBranchingPtr(),
HardBranching::Outgoing));
}
allBranchings.push_back(newBranch);
}
else {
HardBranchingPtr newBranch;
if(particlesToShower[ix]->hasEmitted()) {
newBranch =
new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
particlesToShower[ix]->progenitor()->
showerKinematics()->SudakovFormFactor(),
HardBranchingPtr(),HardBranching::Decay));
constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor());
HardBranchingPtr last=newBranch;
do {
for(unsigned int ix=0;ix<last->children().size();++ix) {
if(last->children()[ix]->branchingParticle()->id()==
particlesToShower[ix]->id()) {
last = last->children()[ix];
continue;
}
}
}
while(!last->children().empty());
last->status(HardBranching::Incoming);
spaceBranchings.push_back(newBranch);
allBranchings .push_back(last);
}
else {
newBranch =
new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
SudakovPtr(),HardBranchingPtr(),
HardBranching::Incoming));
spaceBranchings.push_back(newBranch);
allBranchings .push_back(newBranch);
}
}
}
HardTreePtr QCDTree = new_ptr(HardTree(allBranchings,spaceBranchings,inter));
// set the charge partners
ShowerParticleVector particles;
particles.push_back(spaceBranchings.back()->branchingParticle());
for(set<HardBranchingPtr>::iterator cit=QCDTree->branchings().begin();
cit!=QCDTree->branchings().end();++cit) {
if((*cit)->status()==HardBranching::Outgoing)
particles.push_back((*cit)->branchingParticle());
}
// get the partners
showerModel()->partnerFinder()->setInitialEvolutionScales(particles,true,inter,true);
// do the inverse recon
if(!showerModel()->kinematicsReconstructor()->
deconstructDecayJets(QCDTree,this,inter)) {
return false;
}
// clear the old shower
currentTree()->clear();
// set the hard tree
hardTree(QCDTree);
// set the charge partners
setEvolutionPartners(false,inter,false);
// get the particles to be showered
map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit;
map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt;
particlesToShower.clear();
// incoming particles
for(cit=currentTree()->incomingLines().begin();
cit!=currentTree()->incomingLines().end();++cit)
particlesToShower.push_back(((*cit).first));
assert(particlesToShower.size()==1);
// outgoing particles
for(cjt=currentTree()->outgoingLines().begin();
cjt!=currentTree()->outgoingLines().end();++cjt) {
particlesToShower.push_back(((*cjt).first));
if(ptmax>ZERO) particlesToShower.back()->maximumpT(ptmax,inter);
}
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end(),
mit = hardTree()->particles().find(particlesToShower[ix]->progenitor());
if( mit != eit) {
if(mit->second->status()==HardBranching::Outgoing)
particlesToShower[ix]->progenitor()->set5Momentum(mit->second->pVector());
}
}
return true;
}
bool Evolver::constructHardTree(vector<ShowerProgenitorPtr> & particlesToShower,
ShowerInteraction::Type inter) {
bool noEmission = true;
vector<HardBranchingPtr> spaceBranchings,allBranchings;
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(particlesToShower[ix]->progenitor()->isFinalState()) {
HardBranchingPtr newBranch;
if(particlesToShower[ix]->hasEmitted()) {
noEmission = false;
newBranch =
new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
particlesToShower[ix]->progenitor()->
showerKinematics()->SudakovFormFactor(),
HardBranchingPtr(),HardBranching::Outgoing));
constructTimeLikeLine(newBranch,particlesToShower[ix]->progenitor());
}
else {
newBranch =
new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
SudakovPtr(),HardBranchingPtr(),
HardBranching::Outgoing));
}
allBranchings.push_back(newBranch);
}
else {
HardBranchingPtr first,last;
if(!particlesToShower[ix]->progenitor()->parents().empty()) {
noEmission = false;
constructSpaceLikeLine(particlesToShower[ix]->progenitor(),
first,last,SudakovPtr(),
particlesToShower[ix]->original()->parents()[0]);
}
else {
first = new_ptr(HardBranching(particlesToShower[ix]->progenitor(),
SudakovPtr(),HardBranchingPtr(),
HardBranching::Incoming));
if(particlesToShower[ix]->original()->parents().empty())
first->beam(particlesToShower[ix]->original());
else
first->beam(particlesToShower[ix]->original()->parents()[0]);
last = first;
}
spaceBranchings.push_back(first);
allBranchings.push_back(last);
}
}
if(!noEmission) {
HardTreePtr QCDTree = new_ptr(HardTree(allBranchings,spaceBranchings,
inter));
// set the charge partners
ShowerParticleVector particles;
for(set<HardBranchingPtr>::iterator cit=QCDTree->branchings().begin();
cit!=QCDTree->branchings().end();++cit) {
particles.push_back((*cit)->branchingParticle());
}
// get the partners
showerModel()->partnerFinder()->setInitialEvolutionScales(particles,false,
inter,true);
// do the inverse recon
if(!showerModel()->kinematicsReconstructor()->
deconstructHardJets(QCDTree,this,inter))
throw Exception() << "Can't to shower deconstruction for QED shower in"
<< "QEDEvolver::showerHard" << Exception::eventerror;
// set the hard tree
hardTree(QCDTree);
}
// clear the old shower
currentTree()->clear();
// set the charge partners
setEvolutionPartners(true,inter,false);
// get the particles to be showered
particlesToShower = currentTree()->extractProgenitors();
// reset momenta
if(hardTree()) {
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
eit=hardTree()->particles().end(),
mit = hardTree()->particles().find(particlesToShower[ix]->progenitor());
if( mit != eit) {
particlesToShower[ix]->progenitor()->set5Momentum(mit->second->showerMomentum());
}
}
}
return true;
}
void Evolver::constructTimeLikeLine(tHardBranchingPtr branch,
tShowerParticlePtr particle) {
for(unsigned int ix=0;ix<particle->children().size();++ix) {
HardBranching::Status status = branch->status();
tShowerParticlePtr child =
dynamic_ptr_cast<ShowerParticlePtr>(particle->children()[ix]);
if(child->children().empty()) {
HardBranchingPtr newBranch =
new_ptr(HardBranching(child,SudakovPtr(),branch,status));
branch->addChild(newBranch);
}
else {
HardBranchingPtr newBranch =
new_ptr(HardBranching(child,child->showerKinematics()->SudakovFormFactor(),
branch,status));
constructTimeLikeLine(newBranch,child);
branch->addChild(newBranch);
}
}
// sort out the type of interaction
if(!branch->children().empty()) {
if(branch->branchingParticle()->id()==ParticleID::gamma ||
branch->children()[0]->branchingParticle()->id()==ParticleID::gamma ||
branch->children()[1]->branchingParticle()->id()==ParticleID::gamma)
branch->type(ShowerPartnerType::QED);
else {
if(branch->branchingParticle()->id()==
branch->children()[0]->branchingParticle()->id()) {
if(branch->branchingParticle()->dataPtr()->iColour()==PDT::Colour8) {
tShowerParticlePtr emittor =
branch->branchingParticle()->showerKinematics()->z()>0.5 ?
branch->children()[0]->branchingParticle() :
branch->children()[1]->branchingParticle();
if(branch->branchingParticle()->colourLine()==emittor->colourLine())
branch->type(ShowerPartnerType::QCDAntiColourLine);
else if(branch->branchingParticle()->antiColourLine()==emittor->antiColourLine())
branch->type(ShowerPartnerType::QCDColourLine);
else
assert(false);
}
else if(branch->branchingParticle()->colourLine()) {
branch->type(ShowerPartnerType::QCDColourLine);
}
else if(branch->branchingParticle()->antiColourLine()) {
branch->type(ShowerPartnerType::QCDAntiColourLine);
}
else
assert(false);
}
else if(branch->branchingParticle()->id()==ParticleID::g &&
branch->children()[0]->branchingParticle()->id()==
-branch->children()[1]->branchingParticle()->id()) {
if(branch->branchingParticle()->showerKinematics()->z()>0.5)
branch->type(ShowerPartnerType::QCDAntiColourLine);
else
branch->type(ShowerPartnerType::QCDColourLine);
}
else
assert(false);
}
}
}
void Evolver::constructSpaceLikeLine(tShowerParticlePtr particle,
HardBranchingPtr & first,
HardBranchingPtr & last,
SudakovPtr sud,PPtr beam) {
if(!particle) return;
if(!particle->parents().empty()) {
tShowerParticlePtr parent =
dynamic_ptr_cast<ShowerParticlePtr>(particle->parents()[0]);
SudakovPtr newSud=particle->showerKinematics()->SudakovFormFactor();
constructSpaceLikeLine(parent,first,last,newSud,beam);
}
HardBranchingPtr newBranch =
new_ptr(HardBranching(particle,sud,last,HardBranching::Incoming));
newBranch->beam(beam);
if(!first) {
first=newBranch;
last =newBranch;
return;
}
last->addChild(newBranch);
tShowerParticlePtr timeChild =
dynamic_ptr_cast<ShowerParticlePtr>(particle->parents()[0]->children()[1]);
HardBranchingPtr timeBranch;
if(!timeChild->children().empty()) {
timeBranch =
new_ptr(HardBranching(timeChild,
timeChild->showerKinematics()->SudakovFormFactor(),
last,HardBranching::Outgoing));
constructTimeLikeLine(timeBranch,timeChild);
}
else {
timeBranch =
new_ptr(HardBranching(timeChild,SudakovPtr(),last,HardBranching::Outgoing));
}
last->addChild(timeBranch);
// sort out the type
if(last->branchingParticle() ->id() == ParticleID::gamma ||
newBranch->branchingParticle() ->id() == ParticleID::gamma ||
timeBranch->branchingParticle()->id() == ParticleID::gamma) {
last->type(ShowerPartnerType::QED);
}
else if(last->branchingParticle()->id()==newBranch->branchingParticle()->id()) {
if(last->branchingParticle()->id()==ParticleID::g) {
if(last->branchingParticle()->colourLine()==
newBranch->branchingParticle()->colourLine()) {
last->type(ShowerPartnerType::QCDAntiColourLine);
}
else {
last->type(ShowerPartnerType::QCDColourLine);
}
}
else if(last->branchingParticle()->hasColour()) {
last->type(ShowerPartnerType::QCDColourLine);
}
else if(last->branchingParticle()->hasAntiColour()) {
last->type(ShowerPartnerType::QCDAntiColourLine);
}
else
assert(false);
}
else if(newBranch->branchingParticle()->id()==ParticleID::g) {
if(last->branchingParticle()->hasColour()) {
last->type(ShowerPartnerType::QCDAntiColourLine);
}
else if(last->branchingParticle()->hasAntiColour()) {
last->type(ShowerPartnerType::QCDColourLine);
}
else
assert(false);
}
else if(newBranch->branchingParticle()->hasColour()) {
last->type(ShowerPartnerType::QCDColourLine);
}
else if(newBranch->branchingParticle()->hasAntiColour()) {
last->type(ShowerPartnerType::QCDAntiColourLine);
}
else {
assert(false);
}
last=newBranch;
}
void Evolver::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;
IdList br(3);
br[0] = (**cit).parent()->branchingParticle()->id();
br[1] = (**cit). branchingParticle()->id();
br[2] = (**cit).parent()->children()[0]==*cit ?
(**cit).parent()->children()[1]->branchingParticle()->id() :
(**cit).parent()->children()[0]->branchingParticle()->id();
BranchingList branchings = splittingGenerator()->initialStateBranchings();
if(br[1]<0&&br[0]==br[1]) {
br[0] = abs(br[0]);
br[1] = abs(br[1]);
}
else if(br[1]<0) {
br[1] = -br[1];
br[2] = -br[2];
}
long index = abs(br[1]);
SudakovPtr sudakov;
for(BranchingList::const_iterator cjt = branchings.lower_bound(index);
cjt != branchings.upper_bound(index); ++cjt ) {
IdList ids = cjt->second.second;
if(ids[0]==br[0]&&ids[1]==br[1]&&ids[2]==br[2]) {
sudakov=cjt->second.first;
break;
}
}
if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in "
<< "Evolver::connectTrees() for ISR"
<< Exception::runerror;
(**cit).parent()->sudakov(sudakov);
}
// Sudakovs for FSR
else if(!(**cit).children().empty()) {
++_nfs;
IdList br(3);
br[0] = (**cit) .branchingParticle()->id();
br[1] = (**cit).children()[0]->branchingParticle()->id();
br[2] = (**cit).children()[1]->branchingParticle()->id();
BranchingList branchings = splittingGenerator()->finalStateBranchings();
if(br[0]<0) {
br[0] = abs(br[0]);
br[1] = abs(br[1]);
br[2] = abs(br[2]);
}
long index = br[0];
SudakovPtr sudakov;
for(BranchingList::const_iterator cjt = branchings.lower_bound(index);
cjt != branchings.upper_bound(index); ++cjt ) {
IdList ids = cjt->second.second;
if(ids[0]==br[0]&&ids[1]==br[1]&&ids[2]==br[2]) {
sudakov=cjt->second.first;
break;
}
}
if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in "
<< "Evolver::connectTrees()"
<< Exception::runerror;
(**cit).sudakov(sudakov);
}
}
// calculate the evolution scale
for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin();
cit!=hardTree->branchings().end();++cit) {
particles.push_back((*cit)->branchingParticle());
}
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,hardTree->interaction(),
!hardTree->partnersSet());
hardTree->partnersSet(true);
// inverse reconstruction
if(hard) {
showerModel()->kinematicsReconstructor()->
deconstructHardJets(hardTree,ShowerHandler::currentHandler()->evolver(),
hardTree->interaction());
}
else
showerModel()->kinematicsReconstructor()->
deconstructDecayJets(hardTree,ShowerHandler::currentHandler()->evolver(),
hardTree->interaction());
// now reset the momenta of the showering particles
vector<ShowerProgenitorPtr> particlesToShower;
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=showerTree->incomingLines().begin();
cit!=showerTree->incomingLines().end();++cit )
particlesToShower.push_back(cit->first);
// extract the showering particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=showerTree->outgoingLines().begin();
cit!=showerTree->outgoingLines().end();++cit )
particlesToShower.push_back(cit->first);
// match them
map<ShowerProgenitorPtr,HardBranchingPtr> partners;
for(set<HardBranchingPtr>::const_iterator bit=hardTree->branchings().begin();
bit!=hardTree->branchings().end();++bit) {
Energy2 dmin( 1e30*GeV2 );
ShowerProgenitorPtr partner;
for(vector<ShowerProgenitorPtr>::const_iterator pit=particlesToShower.begin();
pit!=particlesToShower.end();++pit) {
if(partners.find(*pit)!=partners.end()) continue;
if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue;
if( (**bit).branchingParticle()->isFinalState() !=
(**pit).progenitor()->isFinalState() ) continue;
if( (**pit).progenitor()->isFinalState() ) {
Energy2 dtest =
sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) +
sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) +
sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) +
sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() );
// add mass difference for identical particles (e.g. Z0 Z0 production)
dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m());
if( dtest < dmin ) {
partner = *pit;
dmin = dtest;
}
}
else {
// ensure directions are right
if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) {
partner = *pit;
break;
}
}
}
if(!partner) throw Exception() << "Failed to match shower and hard trees in Evolver::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 Evolver::doShowering(bool hard,XCPtr xcomb) {
// order of the interactions
bool showerOrder(true);
// zero number of emissions
_nis = _nfs = 0;
// if MC@NLO H event and limited emissions
// indicate both final and initial state emission
if ( isMCatNLOHEvent && _limitEmissions != 0 ) {
_nis = _nfs = 1;
}
// extract particles to shower
vector<ShowerProgenitorPtr> particlesToShower(setupShower(hard));
// setup the maximum scales for the shower
if (hardVetoOn()) setupMaximumScales(particlesToShower,xcomb);
// set the hard scales for the profiles
setupHardScales(particlesToShower,xcomb);
// specific stuff for hard processes and decays
Energy minmass(ZERO), mIn(ZERO);
// hard process generate the intrinsic p_T once and for all
if(hard) {
generateIntrinsicpT(particlesToShower);
}
// decay compute the minimum mass of the final-state
else {
for(unsigned int ix=0;ix<particlesToShower.size();++ix) {
if(particlesToShower[ix]->progenitor()->isFinalState()) {
if(particlesToShower[ix]->progenitor()->dataPtr()->stable())
minmass += particlesToShower[ix]->progenitor()->dataPtr()->constituentMass();
else
minmass += particlesToShower[ix]->progenitor()->mass();
}
else {
mIn = particlesToShower[ix]->progenitor()->mass();
}
}
// throw exception if decay can't happen
if ( minmass > mIn ) {
throw Exception() << "Evolver.cc: Mass of decaying particle is "
<< "below constituent masses of decay products."
<< Exception::eventerror;
}
}
// check if interactions in right order
if(hardTree() && interaction_!=4 &&
hardTree()->interaction()!=interactions_[0]) {
assert(interactions_.size()==2);
showerOrder = false;
swap(interactions_[0],interactions_[1]);
}
// loop over possible interactions
for(unsigned int inter=0;inter<interactions_.size();++inter) {
// set up for second pass if required
if(inter!=0) {
// zero intrinsic pt so only added first time round
intrinsicpT().clear();
// construct the tree and throw veto if not possible
if(!(hard ?
constructHardTree (particlesToShower,interactions_[inter]) :
constructDecayTree(particlesToShower,interactions_[inter])))
throw InteractionVeto();
}
// 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,interactions_[inter],true);
_nis = _nfs = 0;
// if MC@NLO H event and limited emissions
// indicate both final and initial state emission
if ( 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(!isFSRadiationON()) continue;
// perform shower
progenitor()->hasEmitted(startTimeLikeShower(interactions_[inter]));
}
// initial-state radiation
else {
if(!isISRadiationON()) continue;
// hard process
if(hard) {
// get the PDF
setBeamParticle(_progenitor->beam());
assert(beamParticle());
// perform the shower
// set the beam particle
tPPtr beamparticle=progenitor()->original();
if(!beamparticle->parents().empty())
beamparticle=beamparticle->parents()[0];
// generate the shower
progenitor()->hasEmitted(startSpaceLikeShower(beamparticle,
interactions_[inter]));
}
// 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,
interactions_[inter]));
}
}
}
// do the kinematic reconstruction, checking if it worked
reconstructed = hard ?
showerModel()->kinematicsReconstructor()->
reconstructHardJets (currentTree(),intrinsicpT(),interactions_[inter],
switchRecon && ntry>maximumTries()/2) :
showerModel()->kinematicsReconstructor()->
reconstructDecayJets(currentTree(),interactions_[inter]);
}
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 Evolver::showerDecay()"
<< Exception::eventerror;
}
}
// tree has now showered
_currenttree->hasShowered(true);
if(!showerOrder) swap(interactions_[0],interactions_[1]);
hardTree(HardTreePtr());
}
void Evolver:: convertHardTree(bool hard,ShowerInteraction::Type type) {
map<ColinePtr,ColinePtr> cmap;
// incoming particles
for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator
cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) {
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(cit->first->progenitor());
// put the colour lines in the map
ShowerParticlePtr oldParticle = cit->first->progenitor();
ShowerParticlePtr newParticle = mit->second->branchingParticle();
ColinePtr cLine = oldParticle-> colourLine();
ColinePtr aLine = oldParticle->antiColourLine();
if(newParticle->colourLine() &&
cmap.find(newParticle-> colourLine())==cmap.end())
cmap[newParticle-> colourLine()] = cLine;
if(newParticle->antiColourLine() &&
cmap.find(newParticle->antiColourLine())==cmap.end())
cmap[newParticle->antiColourLine()] = aLine;
// check whether or not particle emits
bool emission = mit->second->parent();
if(emission) {
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
}
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
}
newParticle = mit->second->parent()->branchingParticle();
}
// get the new colour lines
ColinePtr newCLine,newALine;
// sort out colour lines
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newCLine = cmap[ctemp];
}
else {
newCLine = new_ptr(ColourLine());
cmap[ctemp] = newCLine;
}
}
// and anticolour lines
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newALine = cmap[ctemp];
}
else {
newALine = new_ptr(ColourLine());
cmap[ctemp] = newALine;
}
}
// remove colour lines from old particle
if(aLine) {
aLine->removeAntiColoured(cit->first->copy());
aLine->removeAntiColoured(cit->first->progenitor());
}
if(cLine) {
cLine->removeColoured(cit->first->copy());
cLine->removeColoured(cit->first->progenitor());
}
// add particle to colour lines
if(newCLine) newCLine->addColoured (newParticle);
if(newALine) newALine->addAntiColoured(newParticle);
// insert new particles
cit->first->copy(newParticle);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,false)));
cit->first->progenitor(sp);
currentTree()->incomingLines()[cit->first]=sp;
cit->first->perturbative(!emission);
// and the emitted particle if needed
if(emission) {
ShowerParticlePtr newOut = mit->second->parent()->children()[1]->branchingParticle();
if(newOut->colourLine()) {
ColinePtr ctemp = newOut-> colourLine();
ctemp->removeColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addColoured (newOut);
}
if(newOut->antiColourLine()) {
ColinePtr ctemp = newOut->antiColourLine();
ctemp->removeAntiColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addAntiColoured(newOut);
}
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout));
out->perturbative(false);
currentTree()->outgoingLines().insert(make_pair(out,sout));
}
if(hard) {
// sort out the value of x
if(mit->second->beam()->momentum().z()>ZERO) {
sp->x(newParticle->momentum(). plus()/mit->second->beam()->momentum(). plus());
}
else {
sp->x(newParticle->momentum().minus()/mit->second->beam()->momentum().minus());
}
}
}
// outgoing particles
for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator
cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) {
map<tShowerTreePtr,pair<tShowerProgenitorPtr,
tShowerParticlePtr> >::const_iterator tit;
for(tit = currentTree()->treelinks().begin();
tit != currentTree()->treelinks().end();++tit) {
if(tit->second.first && tit->second.second==cit->first->progenitor())
break;
}
map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator
mit = hardTree()->particles().find(cit->first->progenitor());
if(mit==hardTree()->particles().end()) continue;
// put the colour lines in the map
ShowerParticlePtr oldParticle = cit->first->progenitor();
ShowerParticlePtr newParticle = mit->second->branchingParticle();
ShowerParticlePtr newOut;
ColinePtr cLine = oldParticle-> colourLine();
ColinePtr aLine = oldParticle->antiColourLine();
if(newParticle->colourLine() &&
cmap.find(newParticle-> colourLine())==cmap.end())
cmap[newParticle-> colourLine()] = cLine;
if(newParticle->antiColourLine() &&
cmap.find(newParticle->antiColourLine())==cmap.end())
cmap[newParticle->antiColourLine()] = aLine;
// check whether or not particle emits
bool emission = !mit->second->children().empty();
if(emission) {
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
}
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
}
newParticle = mit->second->children()[0]->branchingParticle();
newOut = mit->second->children()[1]->branchingParticle();
if(newParticle->id()!=oldParticle->id()&&newParticle->id()==newOut->id())
swap(newParticle,newOut);
}
// get the new colour lines
ColinePtr newCLine,newALine;
// sort out colour lines
if(newParticle->colourLine()) {
ColinePtr ctemp = newParticle-> colourLine();
ctemp->removeColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newCLine = cmap[ctemp];
}
else {
newCLine = new_ptr(ColourLine());
cmap[ctemp] = newCLine;
}
}
// and anticolour lines
if(newParticle->antiColourLine()) {
ColinePtr ctemp = newParticle->antiColourLine();
ctemp->removeAntiColoured(newParticle);
if(cmap.find(ctemp)!=cmap.end()) {
newALine = cmap[ctemp];
}
else {
newALine = new_ptr(ColourLine());
cmap[ctemp] = newALine;
}
}
// remove colour lines from old particle
if(aLine) {
aLine->removeAntiColoured(cit->first->copy());
aLine->removeAntiColoured(cit->first->progenitor());
}
if(cLine) {
cLine->removeColoured(cit->first->copy());
cLine->removeColoured(cit->first->progenitor());
}
// special for unstable particles
if(newParticle->id()==oldParticle->id() &&
(tit!=currentTree()->treelinks().end()||!oldParticle->dataPtr()->stable())) {
Lorentz5Momentum oldMomentum = oldParticle->momentum();
Lorentz5Momentum newMomentum = newParticle->momentum();
LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass());
if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false);
oldParticle->transform(boost);
boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass());
oldParticle->transform(boost);
if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false);
newParticle=oldParticle;
}
// add particle to colour lines
if(newCLine) newCLine->addColoured (newParticle);
if(newALine) newALine->addAntiColoured(newParticle);
// insert new particles
cit->first->copy(newParticle);
ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,true)));
cit->first->progenitor(sp);
currentTree()->outgoingLines()[cit->first]=sp;
cit->first->perturbative(!emission);
// and the emitted particle if needed
if(emission) {
if(newOut->colourLine()) {
ColinePtr ctemp = newOut-> colourLine();
ctemp->removeColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addColoured (newOut);
}
if(newOut->antiColourLine()) {
ColinePtr ctemp = newOut->antiColourLine();
ctemp->removeAntiColoured(newOut);
assert(cmap.find(ctemp)!=cmap.end());
cmap[ctemp]->addAntiColoured(newOut);
}
ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true));
ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout));
out->perturbative(false);
currentTree()->outgoingLines().insert(make_pair(out,sout));
}
// update any decay products
if(tit!=currentTree()->treelinks().end())
currentTree()->updateLink(tit->first,make_pair(cit->first,sp));
}
// reset the tree
currentTree()->resetShowerProducts();
// reextract the particles and set the colour partners
vector<ShowerParticlePtr> particles =
currentTree()->extractProgenitorParticles();
// clear the partners
for(unsigned int ix=0;ix<particles.size();++ix) {
particles[ix]->partner(ShowerParticlePtr());
particles[ix]->clearPartners();
}
// clear the tree
hardTree(HardTreePtr());
// Set the initial evolution scales
showerModel()->partnerFinder()->
setInitialEvolutionScales(particles,!hard,type,!_hardtree);
}
diff --git a/Shower/Base/Evolver.h b/Shower/Base/Evolver.h
--- a/Shower/Base/Evolver.h
+++ b/Shower/Base/Evolver.h
@@ -1,908 +1,903 @@
// -*- C++ -*-
//
// Evolver.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_Evolver_H
#define HERWIG_Evolver_H
//
// This is the declaration of the Evolver class.
//
#include "ThePEG/Interface/Interfaced.h"
#include "Herwig/Shower/SplittingFunctions/SplittingGenerator.h"
#include "ShowerModel.h"
#include "ThePEG/PDF/BeamParticleData.h"
#include "ShowerTree.h"
#include "ShowerProgenitor.fh"
#include "Herwig/Shower/ShowerHandler.fh"
#include "Branching.h"
#include "ShowerVeto.h"
#include "HardTree.h"
#include "ThePEG/Handlers/XComb.h"
#include "Evolver.fh"
#include "Herwig/MatrixElement/HwMEBase.h"
#include "Herwig/Decay/HwDecayerBase.h"
#include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h"
namespace Herwig {
using namespace ThePEG;
/**\ingroup Shower
* Exception class
* used to communicate failure of QED shower
*/
struct InteractionVeto {};
/** \ingroup Shower
* The Evolver class class performs the sohwer evolution of hard scattering
* and decay processes in Herwig.
*
* @see \ref EvolverInterfaces "The interfaces"
* defined for Evolver.
*/
class Evolver: public Interfaced {
/**
* The ShowerHandler is a friend to set some parameters at initialisation
*/
friend class ShowerHandler;
public:
/**
* Pointer to an XComb object
*/
typedef Ptr<XComb>::pointer XCPtr;
public:
/**
* Default Constructor
*/
Evolver() : _maxtry(100), _meCorrMode(1), _hardVetoMode(1),
_hardVetoRead(0), _reconOpt(0),
- _massVetoOption(1), _hardVetoReadOption(false),
+ _hardVetoReadOption(false),
_iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(),
_limitEmissions(0), _initialenhance(1.), _finalenhance(1.),
interaction_(1), _trunc_Mode(true), _hardEmissionMode(0),
_spinOpt(1), _softOpt(2), _hardPOWHEG(false),
theFactorizationScaleFactor(1.0),
theRenormalizationScaleFactor(1.0)
{}
/**
* Members to perform the shower
*/
//@{
/**
* Perform the shower of the hard process
*/
virtual void showerHardProcess(ShowerTreePtr,XCPtr);
/**
* Perform the shower of a decay
*/
virtual void showerDecay(ShowerTreePtr);
//@}
/**
* Access to the flags and shower variables
*/
//@{
/**
* Is there any showering switched on
*/
bool showeringON() const { return isISRadiationON() || isFSRadiationON(); }
/**
* It returns true/false if the initial-state radiation is on/off.
*/
bool isISRadiationON() const { return _splittingGenerator->isISRadiationON(); }
/**
* It returns true/false if the final-state radiation is on/off.
*/
bool isFSRadiationON() const { return _splittingGenerator->isFSRadiationON(); }
/**
* Get the ShowerModel
*/
ShowerModelPtr showerModel() const {return _model;}
/**
* Get the SplittingGenerator
*/
tSplittingGeneratorPtr splittingGenerator() const { return _splittingGenerator; }
/**
* Mode for hard emissions
*/
int hardEmissionMode() const {return _hardEmissionMode;}
/**
* Switch on or off hard vetoes
*/
void restrictPhasespace(bool yes) {
if ( yes )
_hardVetoMode = 1;
else
_hardVetoMode = 0;
}
/**
* Switch on or off hard veto scale from muF
*/
void hardScaleIsMuF(bool yes) {
if ( yes )
_hardVetoRead = 1;
else
_hardVetoRead = 0;
}
//@}
/**
* Connect the Hard and Shower trees
*/
virtual void connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard );
/**
* Access to switches for spin correlations
*/
//@{
/**
* Spin Correlations
*/
unsigned int spinCorrelations() const {
return _spinOpt;
}
/**
* Soft correlations
*/
unsigned int softCorrelations() const {
return _softOpt;
}
/**
* Any correlations
*/
bool correlations() const {
return _spinOpt!=0||_softOpt!=0;
}
//@}
/**
* Set the factorization scale factor
*/
void factorizationScaleFactor(double f) {
if ( f == theFactorizationScaleFactor )
return;
theFactorizationScaleFactor = f;
splittingGenerator()->factorizationScaleFactor(f);
}
/**
* Set the renormalization scale factor
*/
void renormalizationScaleFactor(double f) {
if ( f == theRenormalizationScaleFactor )
return;
theRenormalizationScaleFactor = f;
splittingGenerator()->renormalizationScaleFactor(f);
}
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:
/**
* Perform the shower
*/
void doShowering(bool hard,XCPtr);
/**
* Generate the hard matrix element correction
*/
virtual void hardMatrixElementCorrection(bool);
/**
* Generate the hardest emission
*/
virtual void hardestEmission(bool hard);
/**
* Extract the particles to be showered, set the evolution scales
* and apply the hard matrix element correction
* @param hard Whether this is a hard process or decay
* @return The particles to be showered
*/
virtual vector<ShowerProgenitorPtr> setupShower(bool hard);
/**
* set the colour partners
*/
virtual void setEvolutionPartners(bool hard,ShowerInteraction::Type,
bool clear);
/**
* Methods to perform the evolution of an individual particle, including
* recursive calling on the products
*/
//@{
/**
* It does the forward evolution of the time-like input particle
* (and recursively for all its radiation products).
* accepting only emissions which conforms to the showerVariables
* and soft matrix element correction.
* If at least one emission has occurred then the method returns true.
* @param particle The particle to be showered
*/
virtual bool timeLikeShower(tShowerParticlePtr particle, ShowerInteraction::Type,
Branching fb, bool first);
/**
* It does the backward evolution of the space-like input particle
* (and recursively for all its time-like radiation products).
* accepting only emissions which conforms to the showerVariables.
* If at least one emission has occurred then the method returns true
* @param particle The particle to be showered
* @param beam The beam particle
*/
virtual bool spaceLikeShower(tShowerParticlePtr particle,PPtr beam,
ShowerInteraction::Type);
/**
* If does the forward evolution of the input on-shell particle
* involved in a decay
* (and recursively for all its time-like radiation products).
* accepting only emissions which conforms to the showerVariables.
* @param particle The particle to be showered
* @param maxscale The maximum scale for the shower.
* @param minimumMass The minimum mass of the final-state system
*/
virtual bool
spaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass,ShowerInteraction::Type);
/**
* Truncated shower from a time-like particle
*/
virtual bool truncatedTimeLikeShower(tShowerParticlePtr particle,
HardBranchingPtr branch,
ShowerInteraction::Type type, bool first);
/**
* Truncated shower from a space-like particle
*/
virtual bool truncatedSpaceLikeShower(tShowerParticlePtr particle,PPtr beam,
HardBranchingPtr branch,
ShowerInteraction::Type type);
/**
* Truncated shower from a time-like particle
*/
virtual bool truncatedSpaceLikeDecayShower(tShowerParticlePtr particle,
const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass, HardBranchingPtr branch,
ShowerInteraction::Type type);
//@}
/**
* Switches for matrix element corrections
*/
//@{
/**
* Any ME correction?
*/
bool MECOn(bool hard) const {
return ( _hardEmissionMode == 0 ||
(!hard && _hardEmissionMode ==-1) ) &&
_meCorrMode > 0;
}
/**
* Any hard ME correction?
*/
bool hardMEC(bool hard) const {
return ( _hardEmissionMode == 0 ||
(!hard && _hardEmissionMode ==-1) ) &&
(_meCorrMode == 1 || _meCorrMode == 2);
}
/**
* Any soft ME correction?
*/
bool softMEC() const {
return ( _hardEmissionMode == 0 ||
(_currenttree->isDecay() && _hardEmissionMode ==-1) ) &&
(_meCorrMode == 1 || _meCorrMode > 2);
}
//@}
/**
* Is the truncated shower on?
*/
bool isTruncatedShowerON() const {return _trunc_Mode;}
/**
* Switch for intrinsic pT
*/
//@{
/**
* Any intrinsic pT?
*/
bool ipTon() const {
return _iptrms != ZERO || ( _beta == 1.0 && _gamma != ZERO && _iptmax !=ZERO );
}
//@}
/**@name Additional shower vetoes */
//@{
/**
* Insert a veto.
*/
void addVeto (ShowerVetoPtr v) { _vetoes.push_back(v); }
/**
* Remove a veto.
*/
void removeVeto (ShowerVetoPtr v) {
vector<ShowerVetoPtr>::iterator vit = find(_vetoes.begin(),_vetoes.end(),v);
if (vit != _vetoes.end())
_vetoes.erase(vit);
}
//@}
/**
* Switches for vetoing hard emissions
*/
//@{
/**
* Vetos on?
*/
bool hardVetoOn() const { return _hardVetoMode > 0; }
/**
* veto hard emissions in IS shower?
*/
bool hardVetoIS() const { return _hardVetoMode == 1 || _hardVetoMode == 2; }
/**
* veto hard emissions in FS shower?
*/
bool hardVetoFS() const { return _hardVetoMode == 1 || _hardVetoMode > 2; }
/**
* veto hard emissions according to lastScale from XComb?
*/
bool hardVetoXComb() const {return (_hardVetoRead == 1);}
/**
* Returns true if the hard veto read-in is to be applied to only
* the primary collision and false otherwise.
*/
bool hardVetoReadOption() const {return _hardVetoReadOption;}
//@}
/**
* Enhancement factors for radiation needed to generate the soft matrix
* element correction.
*/
//@{
/**
* Access the enhancement factor for initial-state radiation
*/
double initialStateRadiationEnhancementFactor() const { return _initialenhance; }
/**
* Access the enhancement factor for final-state radiation
*/
double finalStateRadiationEnhancementFactor() const { return _finalenhance; }
/**
* Set the enhancement factor for initial-state radiation
*/
void initialStateRadiationEnhancementFactor(double in) { _initialenhance=in; }
/**
* Set the enhancement factor for final-state radiation
*/
void finalStateRadiationEnhancementFactor(double in) { _finalenhance=in; }
//@}
/**
* Access to set/get the HardTree currently beinging showered
*/
//@{
/**
* The HardTree currently being showered
*/
tHardTreePtr hardTree() {return _hardtree;}
/**
* The HardTree currently being showered
*/
void hardTree(tHardTreePtr in) {_hardtree = in;}
//@}
/**
* Access/set the beam particle for the current initial-state shower
*/
//@{
/**
* Get the beam particle data
*/
Ptr<BeamParticleData>::const_pointer beamParticle() const { return _beam; }
/**
* Set the beam particle data
*/
void setBeamParticle(Ptr<BeamParticleData>::const_pointer in) { _beam=in; }
//@}
/**
* Set/Get the current tree being evolverd for inheriting classes
*/
//@{
/**
* Get the tree
*/
tShowerTreePtr currentTree() { return _currenttree; }
/**
* Set the tree
*/
void currentTree(tShowerTreePtr tree) { _currenttree=tree; }
//@}
/**
* Access the maximum number of attempts to generate the shower
*/
unsigned int maximumTries() const { return _maxtry; }
/**
* Set/Get the ShowerProgenitor for the current shower
*/
//@{
/**
* Access the progenitor
*/
ShowerProgenitorPtr progenitor() { return _progenitor; }
/**
* Set the progenitor
*/
void progenitor(ShowerProgenitorPtr in) { _progenitor=in; }
//@}
/**
* Calculate the intrinsic \f$p_T\f$.
*/
virtual void generateIntrinsicpT(vector<ShowerProgenitorPtr>);
/**
* Access to the intrinsic \f$p_T\f$ for inheriting classes
*/
map<tShowerProgenitorPtr,pair<Energy,double> > & intrinsicpT() { return _intrinsic; }
/**
* find the maximally allowed pt acc to the hard process.
*/
void setupMaximumScales(const vector<ShowerProgenitorPtr> &,XCPtr);
/**
* find the relevant hard scales for profile scales.
*/
void setupHardScales(const vector<ShowerProgenitorPtr> &,XCPtr);
/**
* Convert the HardTree into an extra shower emission
*/
void convertHardTree(bool hard,ShowerInteraction::Type type);
protected:
/**
* Start the shower of a timelike particle
*/
virtual bool startTimeLikeShower(ShowerInteraction::Type);
/**
* Update of the time-like stuff
*/
void updateHistory(tShowerParticlePtr particle);
/**
* Start the shower of a spacelike particle
*/
virtual bool startSpaceLikeShower(PPtr,ShowerInteraction::Type);
/**
* Start the shower of a spacelike particle
*/
virtual bool
startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales,
Energy minimumMass,ShowerInteraction::Type);
/**
* Select the branching for the next time-like emission
*/
Branching selectTimeLikeBranching(tShowerParticlePtr particle,
ShowerInteraction::Type type);
/**
* Create the timelike child of a branching
*/
ShowerParticleVector createTimeLikeChildren(tShowerParticlePtr particle,
IdList ids);
/**
* Vetos for the timelike shower
*/
virtual bool timeLikeVetoed(const Branching &,ShowerParticlePtr);
/**
* Vetos for the spacelike shower
*/
virtual bool spaceLikeVetoed(const Branching &,ShowerParticlePtr);
/**
* Vetos for the spacelike shower
*/
virtual bool spaceLikeDecayVetoed(const Branching &,ShowerParticlePtr);
/**
* Only generate the hard emission, for testing only.
*/
bool hardOnly() const {return _limitEmissions==3;}
/**
* Members to construct the HardTree from the shower if needed
*/
//@{
/**
* Construct the tree for a scattering process
*/
bool constructHardTree(vector<ShowerProgenitorPtr> & particlesToShower,
ShowerInteraction::Type inter);
/**
* Construct the tree for a decay process
*/
bool constructDecayTree(vector<ShowerProgenitorPtr> & particlesToShower,
ShowerInteraction::Type inter);
/**
* Construct a time-like line
*/
void constructTimeLikeLine(tHardBranchingPtr branch,tShowerParticlePtr particle);
/**
* Construct a space-like line
*/
void constructSpaceLikeLine(tShowerParticlePtr particle,
HardBranchingPtr & first, HardBranchingPtr & last,
SudakovPtr sud,PPtr beam);
//@}
public:
/** @name MC@NLO diagnostics */
//@{
/**
* True, if Matchbox MC@NLO S-event
*/
bool wasMCatNLOSEvent() const { return isMCatNLOSEvent; }
/**
* True, if matchbox MC@NLO H-event
*/
bool wasMCatNLOHEvent() const { return isMCatNLOHEvent; }
//@}
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.
*/
Evolver & operator=(const Evolver &);
private:
/**
* Pointer to the model for the shower evolution model
*/
ShowerModelPtr _model;
/**
* Pointer to the splitting generator
*/
SplittingGeneratorPtr _splittingGenerator;
/**
* Maximum number of tries to generate the shower of a particular tree
*/
unsigned int _maxtry;
/**
* Matrix element correction switch
*/
unsigned int _meCorrMode;
/**
* Hard emission veto switch
*/
unsigned int _hardVetoMode;
/**
* Hard veto to be read switch
*/
unsigned int _hardVetoRead;
/**
* Control of the reconstruction option
*/
unsigned int _reconOpt;
/**
- * Option for inclusion of mass veto
- */
- unsigned int _massVetoOption;
-
- /**
* If hard veto pT scale is being read-in this determines
* whether the read-in value is applied to primary and
* secondary (MPI) scatters or just the primary one, with
* the usual computation of the veto being performed for
* the secondary (MPI) scatters.
*/
bool _hardVetoReadOption;
/**
* rms intrinsic pT of Gaussian distribution
*/
Energy _iptrms;
/**
* Proportion of inverse quadratic intrinsic pT distribution
*/
double _beta;
/**
* Parameter for inverse quadratic: 2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))
*/
Energy _gamma;
/**
* Upper bound on intrinsic pT for inverse quadratic
*/
Energy _iptmax;
/**
* Limit the number of emissions for testing
*/
unsigned int _limitEmissions;
/**
* The progenitor of the current shower
*/
ShowerProgenitorPtr _progenitor;
/**
* Matrix element
*/
HwMEBasePtr _hardme;
/**
* Decayer
*/
HwDecayerBasePtr _decayme;
/**
* The ShowerTree currently being showered
*/
ShowerTreePtr _currenttree;
/**
* The HardTree currently being showered
*/
HardTreePtr _hardtree;
/**
* Radiation enhancement factors for use with the veto algorithm
* if needed by the soft matrix element correction
*/
//@{
/**
* Enhancement factor for initial-state radiation
*/
double _initialenhance;
/**
* Enhancement factor for final-state radiation
*/
double _finalenhance;
//@}
/**
* The beam particle data for the current initial-state shower
*/
Ptr<BeamParticleData>::const_pointer _beam;
/**
* Storage of the intrinsic \f$p_t\f$ of the particles
*/
map<tShowerProgenitorPtr,pair<Energy,double> > _intrinsic;
/**
* Vetoes
*/
vector<ShowerVetoPtr> _vetoes;
/**
* number of IS emissions
*/
unsigned int _nis;
/**
* Number of FS emissions
*/
unsigned int _nfs;
/**
* The option for wqhich interactions to use
*/
unsigned int interaction_;
/**
* Interactions allowed in the shower
*/
vector<ShowerInteraction::Type> interactions_;
/**
* Truncated shower switch
*/
bool _trunc_Mode;
/**
* Count of the number of truncated emissions
*/
unsigned int _truncEmissions;
/**
* Mode for the hard emissions
*/
int _hardEmissionMode;
/**
* Option to include spin correlations
*/
unsigned int _spinOpt;
/**
* Option for the kernal for soft correlations
*/
unsigned int _softOpt;
/**
* Option for hard radiation in POWHEG events
*/
bool _hardPOWHEG;
/**
* True, if Matchbox MC@NLO S-event
*/
bool isMCatNLOSEvent;
/**
* True, if matchbox MC@NLO H-event
*/
bool isMCatNLOHEvent;
/**
* True, if Matchbox Powheg S-event
*/
bool isPowhegSEvent;
/**
* True, if matchbox Powheg H-event
*/
bool isPowhegHEvent;
/**
* The shower approximation to provide the hard scale profile
*/
Ptr<ShowerApproximation>::tptr theShowerApproximation;
/**
* The factorization scale factor.
*/
double theFactorizationScaleFactor;
/**
* The renormalization scale factor.
*/
double theRenormalizationScaleFactor;
/**
* True if no warnings about incorrect hard emission
* mode setting have been issued yet
*/
static bool _hardEmissionModeWarn;
/**
* True if no warnings about missing truncated shower
* have been issued yet
*/
static bool _missingTruncWarn;
};
}
#endif /* HERWIG_Evolver_H */
diff --git a/Shower/Base/ShowerKinematics.cc b/Shower/Base/ShowerKinematics.cc
--- a/Shower/Base/ShowerKinematics.cc
+++ b/Shower/Base/ShowerKinematics.cc
@@ -1,75 +1,75 @@
// -*- C++ -*-
//
// ShowerKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the ShowerKinematics class.
//
#include "ShowerKinematics.h"
using namespace Herwig;
void ShowerKinematics::updateChildren(const tShowerParticlePtr,
const ShowerParticleVector &,
- ShowerPartnerType::Type) const {
+ ShowerPartnerType::Type,bool) const {
throw Exception() << "Base class ShowerKinematics::updateChildren called,"
<< " should have been overriden in an inheriting class"
<< Exception::runerror;
}
void ShowerKinematics::resetChildren(const tShowerParticlePtr,
const ShowerParticleVector &) const {
throw Exception() << "Base class ShowerKinematics::resetChildren called,"
<< " should have been overriden in an inheriting class"
<< Exception::runerror;
}
void ShowerKinematics::updateParent(const tShowerParticlePtr,
const ShowerParticleVector &,
ShowerPartnerType::Type) const {
throw Exception() << "Base class ShowerKinematics::updateParent called,"
<< " should have been overriden in an inheriting class"
<< Exception::runerror;
}
void ShowerKinematics::reconstructChildren(const tShowerParticlePtr,
const ShowerParticleVector &) const {
throw Exception() << "Base class ShowerKinematics::reconstructChildren called,"
<< " should have been overriden in an inheriting class"
<< Exception::runerror;
}
void ShowerKinematics::reconstructParent(const tShowerParticlePtr,
const ParticleVector &) const {
throw Exception() << "Base class ShowerKinematics::reconstructParent called,"
<< " should have been overriden in an inheriting class"
<< Exception::runerror;
}
void ShowerKinematics::reconstructLast(const tShowerParticlePtr,
Energy) const {
throw Exception() << "Base class ShowerKinematics::reconstructLast called,"
<< " should have been overriden in an inheriting class"
<< Exception::runerror;
}
void ShowerKinematics::updateLast(const tShowerParticlePtr,
Energy,Energy) const {
throw Exception() << "Base class ShowerKinematics::updatetLast called,"
<< " should have been overriden in an inheriting class"
<< Exception::runerror;
}
void ShowerKinematics::initialize(ShowerParticle &,PPtr) {
throw Exception() << "Base class ShowerKinematics::initialize called "
<< Exception::runerror;
}
void ShowerKinematics::transform(const LorentzRotation & ) {
throw Exception() << "Base class ShowerKinematics::transform called "
<< Exception::runerror;
}
diff --git a/Shower/Base/ShowerKinematics.h b/Shower/Base/ShowerKinematics.h
--- a/Shower/Base/ShowerKinematics.h
+++ b/Shower/Base/ShowerKinematics.h
@@ -1,347 +1,348 @@
// -*- C++ -*-
//
// ShowerKinematics.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_ShowerKinematics_H
#define HERWIG_ShowerKinematics_H
//
// This is the declaration of the ShowerKinematics class.
//
#include "Herwig/Shower/ShowerConfig.h"
#include "ThePEG/Config/ThePEG.h"
#include "Herwig/Shower/Base/SudakovFormFactor.h"
#include "ShowerKinematics.fh"
namespace Herwig {
using namespace ThePEG;
/**\ingroup Shower
*
* This is the abstract base class from which all other shower
* kinematics classes derive. The main purpose of the
* shower kinematics classes is to allow the reconstruction
* of jet masses, at the end of the showering (indeed, for
* multi-scale showering, at the end of each scale-range evolution).
* This is necessary for the kinematics reshuffling
* in order to compensate the recoil of the emissions.
* The KinematicsReconstructor class is in
* charge of this job, and which is the main "user" of
* ShowerKinematics and its derived classes.
* How this is done depends on the choice of kinematics variables
* and whether the jet is time-like (forward evolved) or
* space-like (backward evolved), whereas the class ShowerKinematics
* describes only the common features which are independent by them.
*
* In general there are a number of methods specific to a shower approach
*
* @see KinematicsReconstructor
*/
class ShowerKinematics: public Base {
public:
/**
* enum for the frame definition
*/
enum Frame {BackToBack,Rest};
public:
/**
* The default constructor.
*/
ShowerKinematics() : Base(), _isTheJetStartingPoint( false ),
_scale(), _z( 0.0 ), _phi( 0.0 ), _pt(),
_sudakov() {}
/**
* The updateChildren and updateParent
* members to update the values of the \f$\alpha\f$ and
* \f$p_\perp\f$ variables during the shower evolution.
*/
//@{
/**
* Along with the showering evolution --- going forward for
* time-like (forward) evolution, and going backward for space-like
* (backward) evolution --- the kinematical variables of the
* branching products are calculated and updated from the knowledge
* of the parent kinematics.
* @param parent The parent
* @param children The children
* @param partnerType The type of evolution partner
*/
virtual void updateChildren(const tShowerParticlePtr parent,
const ShowerParticleVector & children,
- ShowerPartnerType::Type partnerType) const;
+ ShowerPartnerType::Type partnerType,
+ bool massVeto ) const;
virtual void resetChildren( const tShowerParticlePtr parent,
const ShowerParticleVector & children) const;
/**
* Update the parent Kinematics from the knowledge of the kinematics
* of the children. This method will be used by the KinematicsReconstructor.
* @param parent The parent
* @param children The children
* @param partnerType The type of evolution partner
*/
virtual void updateParent(const tShowerParticlePtr parent,
const ShowerParticleVector & children,
ShowerPartnerType::Type partnerType) const;
/**
* Update the kinematical data of a particle when a reconstruction
* fixpoint was found. This will highly depend on the kind of
* kinematics chosen and will be defined in the inherited concrete
* classes. This method will be used by the KinematicsReconstructor.
* @param last The particle.
* @param px The \f$x\f$ component of the \f$p_T\f$.
* @param py The \f$y\f$ component of the \f$p_T\f$.
*/
virtual void updateLast(const tShowerParticlePtr last,
Energy px, Energy py) const;
//@}
/**
* The reconstructLast, reconstructChildren and reconstructParent members
* are used during the reconstruction
*/
//@{
/**
* Along with the showering evolution --- going forward for
* time-like (forward) evolution, and going backward for space-like
* (backward) evolution --- the kinematical variables of the
* branching products are calculated and updated from the knowledge
* of the parent kinematics.
* @param parent The parent
* @param children The children
*/
virtual void reconstructChildren(const tShowerParticlePtr parent,
const ShowerParticleVector & children) const;
/**
* Reconstruct the parent Kinematics from the knowledge of the kinematics
* of the children. This method will be used by the KinematicsReconstructor.
* @param parent The parent
* @param children The children
*/
virtual void reconstructParent(const tShowerParticlePtr parent,
const ParticleVector & children) const;
/**
* Update the kinematical data of a particle when a reconstruction
* fixpoint was found. This will highly depend on the kind of
* kinematics chosen and will be defined in the inherited concrete
* classes. This method will be used by the KinematicsReconstructor.
* @param last The particle.
* @param mass The mass to be used, if less than zero on-shell
*/
virtual void reconstructLast(const tShowerParticlePtr last, Energy mass=-1.*GeV) const;
/**
* Perform any initial calculations needed after the branching has been selected
* @param particle The branching particle
* @param parent The bema particle for the jet if needed
*/
virtual void initialize(ShowerParticle & particle,PPtr parent);
//@}
public:
/**
* Set/access the flag that tells whether or not this ShowerKinematics
* object is associated to the starting particle of the jet: only in this
* case it is sensible to use the two main virtual methods below.
*/
//@{
/**
* Set the starting point flag
*/
void isTheJetStartingPoint(const bool );
/**
* Get the starting point flag
*/
bool isTheJetStartingPoint() const;
//@}
/**
* Virtual function to return a set of basis vectors, specific to
* the type of evolution. This function will be used by the
* ForwardShowerEvolver in order to access \f$p\f$ and \f$n\f$,
* which in turn are members of the concrete class QTildeShowerKinematics1to2.
*/
virtual vector<Lorentz5Momentum> getBasis() const = 0;
/**
* Access to the frame definition
*/
Frame frame() const {return _frame;}
/**
* Set/Get methods for the kinematic variables
*/
//@{
/**
* Access the scale of the splitting.
*/
Energy scale() const { return _scale; }
/**
* Set the scale of the splitting.
*/
void scale(const Energy in) { _scale=in; }
/**
* Access the energy fraction, \f$z\f$.
*/
double z() const { return _z; }
/**
* Set the energy fraction, \f$z\f$.
*/
void z(const double in) { _z=in; }
/**
* Access the azimuthal angle, \f$\phi\f$.
*/
double phi() const { return _phi; }
/**
* Set the azimuthal angle, \f$\phi\f$.
*/
void phi(const double in) { _phi=in; }
/**
* Access the relative \f$p_T\f$ for the branching
*/
Energy pT() const { return _pt; }
/**
* Set the relative \f$p_T\f$ for the branching
*/
void pT(const Energy in) const { _pt=in; }
//@}
/**
* Set and get methods for the SplittingFunction object
*/
//@{
/**
* Access the SplittingFunction object responsible of the
* eventual branching of this particle.
*/
tSplittingFnPtr splittingFn() const { return _sudakov-> splittingFn(); }
//@}
/**
* Set and get methods for the SudakovFormFactor object
*/
/**
* Access the SudakovFormFactor object responsible of the
* eventual branching of this particle.
*/
tSudakovPtr SudakovFormFactor() const { return _sudakov; }
/**
* Set the SudakovFormFactor object responsible of the
* eventual branching of this particle.
*/
void SudakovFormFactor(const tSudakovPtr sud) { _sudakov=sud; }
//@}
/**
* Transform the shower kinematics (usually the reference vectors)
*/
virtual void transform(const LorentzRotation & r);
protected:
/**
* Set the frame definition
*/
void frame(Frame frame) {_frame = frame;}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
ShowerKinematics & operator=(const ShowerKinematics &);
private:
/**
* Is this the starting point of the jet
*/
bool _isTheJetStartingPoint;
/**
* The \f$\tilde{q}\f$ evolution variable.
*/
Energy _scale;
/**
* The energy fraction, \f$z\f$
*/
double _z;
/**
* The azimuthal angle, \f$\phi\f$.
*/
double _phi;
/**
* The relative \f$p_T\f$
*/
mutable Energy _pt;
/**
* The splitting function for the branching of the particle
*/
tSudakovPtr _sudakov;
/**
* The frame in which the basis vectors are defined
*/
Frame _frame;
};
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of ShowerKinematics. */
template <>
struct BaseClassTrait<Herwig::ShowerKinematics,1> {
/** Typedef of the first base class of ShowerKinematics. */
typedef Base NthBase;
};
/** This template specialization informs ThePEG about the name of
* the ShowerKinematics class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::ShowerKinematics>
: public ClassTraitsBase<Herwig::ShowerKinematics> {
/** Return a platform-independent class name */
static string className() { return "Herwig::ShowerKinematics"; }
};
/** @endcond */
}
#endif /* HERWIG_ShowerKinematics_H */
diff --git a/Shower/Base/ShowerParticle.h b/Shower/Base/ShowerParticle.h
--- a/Shower/Base/ShowerParticle.h
+++ b/Shower/Base/ShowerParticle.h
@@ -1,452 +1,457 @@
// -*- C++ -*-
//
// ShowerParticle.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_ShowerParticle_H
#define HERWIG_ShowerParticle_H
//
// This is the declaration of the ShowerParticle class.
//
#include "ThePEG/EventRecord/Particle.h"
#include "Herwig/Shower/SplittingFunctions/SplittingFunction.fh"
#include "Herwig/Shower/ShowerConfig.h"
#include "ShowerKinematics.h"
#include "ShowerParticle.fh"
#include <iosfwd>
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
* This class represents a particle in the showering process.
* It inherits from the Particle class of ThePEG and has some
* specifics information useful only during the showering process.
*
* Notice that:
* - for forward evolution, it is clear what is meant by parent/child;
* for backward evolution, however, it depends whether we want
* to keep a physical picture or a Monte-Carlo effective one.
* In the former case, an incoming particle (emitting particle)
* splits into an emitted particle and the emitting particle after
* the emission: the latter two are then children of the
* emitting particle, the parent. In the Monte-Carlo effective
* picture, we have that the particle close to the hard subprocess,
* with higher (space-like) virtuality, splits into an emitted particle
* and the emitting particle at lower virtuality: the latter two are,
* in this case, the children of the first one, the parent. However we
* choose a more physical picture where the new emitting particle is the
* parented of the emitted final-state particle and the original emitting
* particle.
* - the pointer to a SplitFun object is set only in the case
* that the particle has undergone a shower emission. This is similar to
* the case of the decay of a normal Particle where
* the pointer to a Decayer object is set only in the case
* that the particle has undergone to a decay.
* In the case of particle connected directly to the hard subprocess,
* there is no pointer to the hard subprocess, but there is a method
* isFromHardSubprocess() which returns true only in this case.
*
* @see Particle
* @see ShowerConfig
* @see ShowerKinematics
*/
class ShowerParticle: public Particle {
public:
/**
* Struct for all the info on an evolution partner
*/
struct EvolutionPartner {
/**
* Constructor
*/
EvolutionPartner(tShowerParticlePtr p,double w, ShowerPartnerType::Type t,
Energy s) : partner(p), weight(w), type(t), scale(s)
{}
/**
* The partner
*/
tShowerParticlePtr partner;
/**
* Weight
*/
double weight;
/**
* Type
*/
ShowerPartnerType::Type type;
/**
* The assoicated evolution scale
*/
Energy scale;
};
/**
* Struct to store the evolution scales
*/
struct EvolutionScales {
/**
* Constructor
*/
EvolutionScales() : QED(),QCD_c(),QCD_ac(),
- QED_noAO(),QCD_c_noAO(),QCD_ac_noAO()
+ QED_noAO(),QCD_c_noAO(),QCD_ac_noAO(),
+ Max_Q2(Constants::MaxEnergy2)
{}
/**
* QED scale
*/
Energy QED;
/**
* QCD colour scale
*/
Energy QCD_c;
/**
* QCD anticolour scale
*/
Energy QCD_ac;
/**
* QED scale
*/
Energy QED_noAO;
/**
* QCD colour scale
*/
Energy QCD_c_noAO;
/**
* QCD anticolour scale
*/
Energy QCD_ac_noAO;
+ /**
+ * Maximum allowed virtuality of the particle
+ */
+ Energy2 Max_Q2;
};
/** @name Construction and descruction functions. */
//@{
/**
* Standard Constructor. Note that the default constructor is
* private - there is no particle without a pointer to a
* ParticleData object.
* @param x the ParticleData object
* @param fs Whether or not the particle is an inital or final-state particle
* @param tls Whether or not the particle initiates a time-like shower
*/
ShowerParticle(tcEventPDPtr x, bool fs, bool tls=false)
: Particle(x), _isFinalState(fs),
_perturbative(0), _initiatesTLS(tls), _x(1.0), _showerKinematics(),
_vMass(ZERO), _thePEGBase() {}
/**
* Copy constructor from a ThePEG Particle
* @param x ThePEG particle
* @param pert Where the particle came from
* @param fs Whether or not the particle is an inital or final-state particle
* @param tls Whether or not the particle initiates a time-like shower
*/
ShowerParticle(const Particle & x, unsigned int pert, bool fs, bool tls=false)
: Particle(x), _isFinalState(fs),
_perturbative(pert), _initiatesTLS(tls), _x(1.0), _showerKinematics(),
_vMass(ZERO), _thePEGBase(&x) {}
//@}
public:
/**
* Access/Set various flags about the state of the particle
*/
//@{
/**
* Access the flag that tells if the particle is final state
* or initial state.
*/
bool isFinalState() const { return _isFinalState; }
/**
* Access the flag that tells if the particle is initiating a
* time like shower when it has been emitted in an initial state shower.
*/
bool initiatesTLS() const { return _initiatesTLS; }
/**
* Access the flag which tells us where the particle came from
* This is 0 for a particle produced in the shower, 1 if the particle came
* from the hard sub-process and 2 is it came from a decay.
*/
unsigned int perturbative() const { return _perturbative; }
//@}
/**
* Set/Get the momentum fraction for initial-state particles
*/
//@{
/**
* For an initial state particle get the fraction of the beam momentum
*/
void x(double x) { _x = x; }
/**
* For an initial state particle set the fraction of the beam momentum
*/
double x() const { return _x; }
//@}
/**
* Set/Get methods for the ShowerKinematics objects
*/
//@{
/**
* Access/ the ShowerKinematics object.
*/
const ShoKinPtr & showerKinematics() const { return _showerKinematics; }
/**
* Set the ShowerKinematics object.
*/
void showerKinematics(const ShoKinPtr in) { _showerKinematics = in; }
//@}
/**
* Members relating to the initial evolution scale and partner for the particle
*/
//@{
/**
* Veto emission at a given scale
*/
void vetoEmission(ShowerPartnerType::Type type, Energy scale);
/**
* Access to the evolution scales
*/
const EvolutionScales & scales() const {return scales_;}
/**
* Access to the evolution scales
*/
EvolutionScales & scales() {return scales_;}
/**
* Return the virtual mass\f$
*/
Energy virtualMass() const { return _vMass; }
/**
* Set the virtual mass
*/
void virtualMass(Energy mass) { _vMass = mass; }
/**
* Return the partner
*/
tShowerParticlePtr partner() const { return _partner; }
/**
* Set the partner
*/
void partner(const tShowerParticlePtr partner) { _partner = partner; }
/**
* Get the possible partners
*/
vector<EvolutionPartner> & partners() { return partners_; }
/**
* Add a possible partners
*/
void addPartner(EvolutionPartner in );
/**
* Clear the evolution partners
*/
void clearPartners() { partners_.clear(); }
/**
* Return the progenitor of the shower
*/
tShowerParticlePtr progenitor() const { return _progenitor; }
/**
* Set the progenitor of the shower
*/
void progenitor(const tShowerParticlePtr progenitor) { _progenitor = progenitor; }
//@}
/**
* Members to store and provide access to variables for a specific
* shower evolution scheme
*/
//@{
struct Parameters {
Parameters() : alpha(1.), beta(), ptx(), pty(), pt() {}
double alpha;
double beta;
Energy ptx;
Energy pty;
Energy pt;
};
/**
* Set the vector containing dimensionless variables
*/
Parameters & showerParameters() { return _parameters; }
//@}
/**
* If this particle came from the hard process get a pointer to ThePEG particle
* it came from
*/
const tcPPtr thePEGBase() const { return _thePEGBase; }
protected:
/**
* Standard clone function.
*/
virtual PPtr clone() const;
/**
* Standard clone function.
*/
virtual PPtr fullclone() const;
private:
/**
* The static object used to initialize the description of this class.
* Indicates that this is a concrete class with persistent data.
*/
static ClassDescription<ShowerParticle> initShowerParticle;
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
ShowerParticle & operator=(const ShowerParticle &);
private:
/**
* Whether the particle is in the final or initial state
*/
bool _isFinalState;
/**
* Whether the particle came from
*/
unsigned int _perturbative;
/**
* Does a particle produced in the backward shower initiate a time-like shower
*/
bool _initiatesTLS;
/**
* Dimensionless parameters
*/
Parameters _parameters;
/**
* The beam energy fraction for particle's in the initial state
*/
double _x;
/**
* The shower kinematics for the particle
*/
ShoKinPtr _showerKinematics;
/**
* Storage of the evolution scales
*/
EvolutionScales scales_;
/**
* Virtual mass
*/
Energy _vMass;
/**
* Partners
*/
tShowerParticlePtr _partner;
/**
* Pointer to ThePEG Particle this ShowerParticle was created from
*/
const tcPPtr _thePEGBase;
/**
* Progenitor
*/
tShowerParticlePtr _progenitor;
/**
* Partners
*/
vector<EvolutionPartner> partners_;
};
inline ostream & operator<<(ostream & os, const ShowerParticle::EvolutionScales & es) {
os << "Scales: QED=" << es.QED / GeV
<< " QCD_c=" << es.QCD_c / GeV
<< " QCD_ac=" << es.QCD_ac / GeV
<< " QED_noAO=" << es.QED_noAO / GeV
<< " QCD_c_noAO=" << es.QCD_c_noAO / GeV
<< " QCD_ac_noAO=" << es.QCD_ac_noAO / GeV
<< '\n';
return os;
}
}
#include "ThePEG/Utilities/ClassTraits.h"
namespace ThePEG {
/** @cond TRAITSPECIALIZATIONS */
/** This template specialization informs ThePEG about the
* base classes of ShowerParticle. */
template <>
struct BaseClassTrait<Herwig::ShowerParticle,1> {
/** Typedef of the first base class of ShowerParticle. */
typedef Particle NthBase;
};
/** This template specialization informs ThePEG about the name of
* the ShowerParticle class and the shared object where it is defined. */
template <>
struct ClassTraits<Herwig::ShowerParticle>
: public ClassTraitsBase<Herwig::ShowerParticle> {
/** Return a platform-independent class name */
static string className() { return "Herwig::ShowerParticle"; }
/** Create a Event object. */
static TPtr create() { return TPtr::Create(Herwig::ShowerParticle(tcEventPDPtr(),true)); }
};
/** @endcond */
}
#endif /* HERWIG_ShowerParticle_H */
diff --git a/Shower/Base/SudakovFormFactor.h b/Shower/Base/SudakovFormFactor.h
--- a/Shower/Base/SudakovFormFactor.h
+++ b/Shower/Base/SudakovFormFactor.h
@@ -1,701 +1,701 @@
// -*- C++ -*-
//
// SudakovFormFactor.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_SudakovFormFactor_H
#define HERWIG_SudakovFormFactor_H
//
// This is the declaration of the SudakovFormFactor class.
//
#include "ThePEG/Interface/Interfaced.h"
#include "Herwig/Shower/SplittingFunctions/SplittingFunction.h"
#include "Herwig/Shower/Couplings/ShowerAlpha.h"
#include "Herwig/Shower/SplittingFunctions/SplittingGenerator.fh"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/PDF/BeamParticleData.h"
#include "ThePEG/EventRecord/RhoDMatrix.h"
#include "ThePEG/EventRecord/SpinInfo.h"
#include "ShowerKinematics.fh"
#include "SudakovFormFactor.fh"
namespace Herwig {
using namespace ThePEG;
/**
* A typedef for the BeamParticleData
*/
typedef Ptr<BeamParticleData>::transient_const_pointer tcBeamPtr;
/** \ingroup Shower
*
* This is the definition of the Sudakov form factor class. In general this
* is the base class for the implementation of Sudakov form factors in Herwig.
* The methods generateNextTimeBranching(), generateNextDecayBranching() and
* generateNextSpaceBranching need to be implemented in classes inheriting from this
* one.
*
* In addition a number of methods are implemented to assist with the calculation
* of the form factor using the veto algorithm in classes inheriting from this one.
*
* In general the Sudakov form-factor, for final-state radiation, is given
* by
* \f[\Delta_{ba}(\tilde{q}_{i+1},\tilde{q}_i)=
* \exp\left\{
* -\int^{\tilde{q}^2_i}_{\tilde{q}^2_{i+1}}
* \frac{{\rm d}\tilde{q}^2}{\tilde{q}^2}
* \int\frac{\alpha_S(z,\tilde{q})}{2\pi}
* P_{ba}(z,\tilde{q})\Theta(p_T)
* \right\}.
* \f]
* We can solve this to obtain the next value of the scale \f$\tilde{q}_{i+1}\f$
* given the previous value \f$\tilde{q}_i\f$
* in the following way. First we obtain a simplified form of the integrand
* which is greater than or equal to the true integrand for all values of
* \f$\tilde{q}\f$.
*
* In practice it is easiest to obtain this over estimate in pieces. The ShowerAlpha
* object contains an over estimate for \f$\alpha_S\f$, the splitting function
* contains both an over estimate of the spltting function and its integral
* which is needed to compute the over estimate of the \f$\tilde{q}\f$ integrand,
* together with an over estimate of the limit of the \f$z\f$ integral.
*
* This gives an overestimate of the integrand
* \f[g(\tilde{q}^2) = \frac{c}{\tilde{q}^2}, \f]
* where because the over estimates are chosen to be independent of \f$\tilde{q}\f$ the
* parameter
* \f[c = \frac{\alpha_{\rm over}}{2\pi}\int^{z_1}_{z_0}P_{\rm over}(z),\f]
* is a constant independent of \f$\tilde{q}\f$.
*
* The guesst() member can then be used to generate generate the value of
* \f$\tilde{q}^2\f$ according to this result. This is done by solving the Sudakov
* form factor, with the over estimates, is equal to a random number
* \f$r\f$ in the interval \f$[0,1]\f$. This gives
* \f[\tilde{q}^2_{i+1}=G^{-1}\left[G(\tilde{q}^2_i)+\ln r\right],\f]
* where \f$G(\tilde{q}^2)=c\ln(\tilde{q}^2)\f$ is the infinite integral
* of \f$g(\tilde{q}^2)\f$ and \f$G^{-1}(x)=\exp\left(\frac{x}c\right)\f$
* is its inverse.
* It this case we therefore obtain
* \f[\tilde{q}^2_{i+1}=\tilde{q}^2_ir^{\frac1c}.\f]
* The value of \f$z\f$ can then be calculated in a similar way
* \f[z = I^{-1}\left[I(z_0)+r\left(I(z_1)-I(z_0)\right)\right],\f]
* using the guessz() member,
* where \f$I=\int P(z){\rm d}z\f$ and \f$I^{-1}\f$ is its inverse.
*
* The veto algorithm then uses rejection using the ratio of the
* true value to the overestimated one to obtain the original distribution.
* This is accomplished using the
* - alphaSVeto() member for the \f$\alpha_S\f$ veto
* - SplittingFnVeto() member for the veto on the value of the splitting function.
* in general there must also be a chech that the emission is in the allowed
* phase space but this is left to the inheriting classes as it will depend
* on the ordering variable.
*
* The Sudakov form factor for the initial-scale shower is different because
* it must include the PDF which guides the backward evolution.
* It is given by
* \f[\Delta_{ba}(\tilde{q}_{i+1},\tilde{q}_i)=
* \exp\left\{
* -\int^{\tilde{q}^2_i}_{\tilde{q}^2_{i+1}}
* \frac{{\rm d}\tilde{q}^2}{\tilde{q}^2}
* \int\frac{\alpha_S(z,\tilde{q})}{2\pi}
* P_{ba}(z,\tilde{q})\frac{x'f_a(\frac{x}z,\tilde{q}^2)}{xf_b(x,\tilde{q^2})}
* \right\},
* \f]
* where \f$x\f$ is the fraction of the beam momentum the parton \f$b\f$ had before
* the backward evolution.
* This can be solve in the same way as for the final-state branching but the constant
* becomes
* \f[c = \frac{\alpha_{\rm over}}{2\pi}\int^{z_1}_{z_0}P_{\rm over}(z)PDF_{\rm max},\f]
* where
* \f[PDF_{\rm max}=\max\frac{x'f_a(\frac{x}z,\tilde{q}^2)}{xf_b(x,\tilde{q^2})},\f]
* which can be set using an interface.
* In addition the PDFVeto() member then is needed to implement the relevant veto.
*
* @see SplittingGenerator
* @see SplittingFunction
* @see ShowerAlpha
* @see \ref SudakovFormFactorInterfaces "The interfaces"
* defined for SudakovFormFactor.
*/
class SudakovFormFactor: public Interfaced {
/**
* The SplittingGenerator is a friend to insert the particles in the
* branchings at initialisation
*/
friend class SplittingGenerator;
public:
/**
* The default constructor.
*/
SudakovFormFactor() : pdfmax_(35.0), pdffactor_(0),
cutOffOption_(0), a_(0.3), b_(2.3), c_(0.3*GeV),
kinCutoffScale_( 2.3*GeV ), vgcut_(0.85*GeV),
vqcut_(0.85*GeV), pTmin_(1.*GeV), pT2min_(ZERO),
z_( 0.0 ),phi_(0.0), pT_(),
theFactorizationScaleFactor(1.0),
theRenormalizationScaleFactor(1.0) {}
/**
* Members to generate the scale of the next branching
*/
//@{
/**
* Return the scale of the next time-like branching. If there is no
* branching then it returns ZERO.
* @param startingScale starting scale for the evolution
* @param ids The PDG codes of the particles in the splitting
* @param cc Whether this is the charge conjugate of the branching
* @param enhance The radiation enhancement factor
- * defined.
+ * @param maxQ2 The maximum \f$Q^2\f$ for the emission
*/
virtual ShoKinPtr generateNextTimeBranching(const Energy startingScale,
const IdList &ids,const bool cc,
- double enhance)=0;
+ double enhance, Energy2 maxQ2)=0;
/**
* Return the scale of the next space-like decay branching. If there is no
* branching then it returns ZERO.
* @param startingScale starting scale for the evolution
* @param stoppingScale stopping scale for the evolution
* @param minmass The minimum mass allowed for the spake-like particle.
* @param ids The PDG codes of the particles in the splitting
* @param cc Whether this is the charge conjugate of the branching
* defined.
* @param enhance The radiation enhancement factor
*/
virtual ShoKinPtr generateNextDecayBranching(const Energy startingScale,
const Energy stoppingScale,
const Energy minmass,
const IdList &ids,
const bool cc,
double enhance)=0;
/**
* Return the scale of the next space-like branching. If there is no
* branching then it returns ZERO.
* @param startingScale starting scale for the evolution
* @param ids The PDG codes of the particles in the splitting
* @param x The fraction of the beam momentum
* @param cc Whether this is the charge conjugate of the branching
* defined.
* @param beam The beam particle
* @param enhance The radiation enhancement factor
*/
virtual ShoKinPtr generateNextSpaceBranching(const Energy startingScale,
const IdList &ids,double x,
const bool cc,double enhance,
tcBeamPtr beam)=0;
//@}
/**
* Generate the azimuthal angle of the branching for forward evolution
* @param particle The branching particle
* @param ids The PDG codes of the particles in the branchings
* @param The Shower kinematics
*/
virtual double generatePhiForward(ShowerParticle & particle,const IdList & ids,
ShoKinPtr kinematics)=0;
/**
* Generate the azimuthal angle of the branching for backward evolution
* @param particle The branching particle
* @param ids The PDG codes of the particles in the branchings
* @param The Shower kinematics
*/
virtual double generatePhiBackward(ShowerParticle & particle,const IdList & ids,
ShoKinPtr kinematics)=0;
/**
* Generate the azimuthal angle of the branching for ISR in decays
* @param particle The branching particle
* @param ids The PDG codes of the particles in the branchings
* @param The Shower kinematics
*/
virtual double generatePhiDecay(ShowerParticle & particle,const IdList & ids,
ShoKinPtr kinematics)=0;
/**
* Methods to provide public access to the private member variables
*/
//@{
/**
* Return the pointer to the SplittingFunction object.
*/
tSplittingFnPtr splittingFn() const { return splittingFn_; }
/**
* Return the pointer to the ShowerAlpha object.
*/
tShowerAlphaPtr alpha() const { return alpha_; }
/**
* The type of interaction
*/
inline ShowerInteraction::Type interactionType() const
{return splittingFn_->interactionType();}
//@}
public:
/**
* Methods to access the kinematic variables for the branching
*/
//@{
/**
* The energy fraction
*/
double z() const { return z_; }
/**
* The azimuthal angle
*/
double phi() const { return phi_; }
/**
* The transverse momentum
*/
Energy pT() const { return pT_; }
//@}
/**
* Access the maximum weight for the PDF veto
*/
double pdfMax() const { return pdfmax_;}
/**
* Method to return the evolution scale given the
* transverse momentum, \f$p_T\f$ and \f$z\f$.
*/
virtual Energy calculateScale(double z, Energy pt, IdList ids,unsigned int iopt)=0;
/**
* Method to create the ShowerKinematics object for a final-state branching
*/
virtual ShoKinPtr createFinalStateBranching(Energy scale,double z,
double phi, Energy pt)=0;
/**
* Method to create the ShowerKinematics object for an initial-state branching
*/
virtual ShoKinPtr createInitialStateBranching(Energy scale,double z,
double phi, Energy pt)=0;
/**
* Method to create the ShowerKinematics object for a decay branching
*/
virtual ShoKinPtr createDecayBranching(Energy scale,double z,
double phi, Energy pt)=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 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:
/**
* Methods to implement the veto algorithm to generate the scale of
* the next branching
*/
//@{
/**
* Value of the energy fraction for the veto algorithm
* @param iopt The option for calculating z
* @param ids The PDG codes of the particles in the splitting
* - 0 is final-state
* - 1 is initial-state for the hard process
* - 2 is initial-state for particle decays
*/
double guessz (unsigned int iopt, const IdList &ids) const;
/**
* Value of the scale for the veto algorithm
* @param t1 The starting valoe of the scale
* @param iopt The option for calculating t
* @param ids The PDG codes of the particles in the splitting
* - 0 is final-state
* - 1 is initial-state for the hard process
* - 2 is initial-state for particle decays
* @param enhance The radiation enhancement factor
* @param identical Whether or not the outgoing particles are identical
*/
Energy2 guesst (Energy2 t1,unsigned int iopt, const IdList &ids,
double enhance, bool identical) const;
/**
* Veto on the PDF for the initial-state shower
* @param t The scale
* @param x The fraction of the beam momentum
* @param parton0 Pointer to the particleData for the
* new parent (this is the particle we evolved back to)
* @param parton1 Pointer to the particleData for the
* original particle
* @param beam The BeamParticleData object
*/
bool PDFVeto(const Energy2 t, const double x,
const tcPDPtr parton0, const tcPDPtr parton1,
tcBeamPtr beam) const;
/**
* The veto on the splitting function.
* @param t The scale
* @param ids The PDG codes of the particles in the splitting
* @param mass Whether or not to use the massive splitting functions
* @return true if vetoed
*/
bool SplittingFnVeto(const Energy2 t,
const IdList &ids,
const bool mass) const {
return UseRandom::rnd()>splittingFn_->ratioP(z_, t, ids,mass);
}
/**
* The veto on the coupling constant
* @param pt2 The value of ther transverse momentum squared, \f$p_T^2\f$.
* @return true if vetoed
*/
bool alphaSVeto(Energy2 pt2) const;
//@}
/**
* Methods to set the kinematic variables for the branching
*/
//@{
/**
* The energy fraction
*/
void z(double in) { z_=in; }
/**
* The azimuthal angle
*/
void phi(double in) { phi_=in; }
/**
* The transverse momentum
*/
void pT(Energy in) { pT_=in; }
//@}
/**
* Set/Get the limits on the energy fraction for the splitting
*/
//@{
/**
* Get the limits
*/
pair<double,double> zLimits() const { return zlimits_;}
/**
* Set the limits
*/
void zLimits(pair<double,double> in) { zlimits_=in; }
//@}
/**
* Set the particles in the splittings
*/
void addSplitting(const IdList &);
/**
* Delete the particles in the splittings
*/
void removeSplitting(const IdList &);
/**
* Access the potential branchings
*/
const vector<IdList> & particles() const { return particles_; }
/**
* For a particle which came from the hard process get the spin density and
* the mapping required to the basis used in the Shower
* @param rho The \f$\rho\f$ matrix
* @param mapping The mapping
* @param particle The particle
* @param showerkin The ShowerKinematics object
*/
bool getMapping(SpinPtr &, RhoDMatrix & map,
ShowerParticle & particle,ShoKinPtr showerkin);
public:
/**
* @name Methods for the cut-off
*/
//@{
/**
* The option being used
*/
unsigned int cutOffOption() const { return cutOffOption_; }
/**
* The kinematic scale
*/
Energy kinScale() const {return kinCutoffScale_;}
/**
* The virtuality cut-off on the gluon \f$Q_g=\frac{\delta-am_q}{b}\f$
* @param scale The scale \f$\delta\f$
* @param mq The quark mass \f$m_q\f$.
*/
Energy kinematicCutOff(Energy scale, Energy mq) const
{return max((scale -a_*mq)/b_,c_);}
/**
* The virtualilty cut-off for gluons
*/
Energy vgCut() const { return vgcut_; }
/**
* The virtuality cut-off for everything else
*/
Energy vqCut() const { return vqcut_; }
/**
* The minimum \f$p_T\f$ for the branching
*/
Energy pTmin() const { return pTmin_; }
/**
* The square of the minimum \f$p_T\f$
*/
Energy2 pT2min() const { return pT2min_; }
/**
* Calculate the virtual masses for a branchings
*/
const vector<Energy> & virtualMasses(const IdList & ids);
//@}
/**
* Set the PDF
*/
void setPDF(tcPDFPtr pdf, Energy scale) {
pdf_ = pdf;
freeze_ = scale;
}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
SudakovFormFactor & operator=(const SudakovFormFactor &);
private:
/**
* Pointer to the splitting function for this Sudakov form factor
*/
SplittingFnPtr splittingFn_;
/**
* Pointer to the coupling for this Sudakov form factor
*/
ShowerAlphaPtr alpha_;
/**
* Maximum value of the PDF weight
*/
double pdfmax_;
/**
* List of the particles this Sudakov is used for to aid in setting up
* interpolation tables if needed
*/
vector<IdList> particles_;
/**
* Option for the inclusion of a factor \f$1/(1-z)\f$ in the PDF estimate
*/
unsigned pdffactor_;
private:
/**
* Option for the type of cut-off to be applied
*/
unsigned int cutOffOption_;
/**
* Parameters for the default Herwig cut-off option, i.e. the parameters for
* the \f$Q_g=\max(\frac{\delta-am_q}{b},c)\f$ kinematic cut-off
*/
//@{
/**
* The \f$a\f$ parameter
*/
double a_;
/**
* The \f$b\f$ parameter
*/
double b_;
/**
* The \f$c\f$ parameter
*/
Energy c_;
/**
* Kinematic cutoff used in the parton shower phase space.
*/
Energy kinCutoffScale_;
//@}
/**
* Parameters for the FORTRAN-like cut-off
*/
//@{
/**
* The virtualilty cut-off for gluons
*/
Energy vgcut_;
/**
* The virtuality cut-off for everything else
*/
Energy vqcut_;
//@}
/**
* Parameters for the \f$p_T\f$ cut-off
*/
//@{
/**
* The minimum \f$p_T\f$ for the branching
*/
Energy pTmin_;
/**
* The square of the minimum \f$p_T\f$
*/
Energy2 pT2min_;
//@}
private:
/**
* Member variables to keep the shower kinematics information
* generated by a call to generateNextTimeBranching or generateNextSpaceBranching
*/
//@{
/**
* The energy fraction
*/
double z_;
/**
* The azimuthal angle
*/
double phi_;
/**
* The transverse momentum
*/
Energy pT_;
//@}
/**
* The limits of \f$z\f$ in the splitting
*/
pair<double,double> zlimits_;
/**
* Stuff for the PDFs
*/
//@{
/**
* PDf
*/
tcPDFPtr pdf_;
/**
* Freezing scale
*/
Energy freeze_;
//@}
public:
/**
* Get the factorization scale factor
*/
double factorizationScaleFactor() const { return theFactorizationScaleFactor; }
/**
* Set the factorization scale factor
*/
void factorizationScaleFactor(double f) { theFactorizationScaleFactor = f; }
/**
* Get the renormalization scale factor
*/
double renormalizationScaleFactor() const { return theRenormalizationScaleFactor; }
/**
* Set the renormalization scale factor
*/
void renormalizationScaleFactor(double f) { theRenormalizationScaleFactor = f; }
private:
/**
* The factorization scale factor.
*/
double theFactorizationScaleFactor;
/**
* The renormalization scale factor.
*/
double theRenormalizationScaleFactor;
};
}
#endif /* HERWIG_SudakovFormFactor_H */
diff --git a/Shower/Default/Decay_QTildeShowerKinematics1to2.cc b/Shower/Default/Decay_QTildeShowerKinematics1to2.cc
--- a/Shower/Default/Decay_QTildeShowerKinematics1to2.cc
+++ b/Shower/Default/Decay_QTildeShowerKinematics1to2.cc
@@ -1,111 +1,112 @@
// -*- C++ -*-
//
// Decay_QTildeShowerKinematics1to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the Decay_QTildeShowerKinematics1to2 class.
//
#include "Decay_QTildeShowerKinematics1to2.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Shower/SplittingFunctions/SplittingFunction.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include <cassert>
#include "Herwig/Shower/ShowerHandler.h"
#include "Herwig/Shower/Base/Evolver.h"
#include "Herwig/Shower/Base/PartnerFinder.h"
#include "Herwig/Shower/Base/ShowerModel.h"
#include "Herwig/Shower/Base/KinematicsReconstructor.h"
#include "Herwig/Shower/Base/ShowerVertex.h"
using namespace Herwig;
void Decay_QTildeShowerKinematics1to2::
updateChildren(const tShowerParticlePtr parent,
const ShowerParticleVector & children,
- ShowerPartnerType::Type partnerType) const {
+ ShowerPartnerType::Type partnerType,
+ bool massVeto) const {
assert(children.size() == 2);
// calculate the scales
splittingFn()->evaluateDecayScales(partnerType,scale(),z(),parent,
children[0],children[1]);
// determine alphas of children according to interpretation of z
const ShowerParticle::Parameters & params = parent->showerParameters();
ShowerParticle::Parameters & child0 = children[0]->showerParameters();
ShowerParticle::Parameters & child1 = children[1]->showerParameters();
child0.alpha = z() * params.alpha;
child1.alpha = (1.-z()) * params.alpha;
child0.ptx = pT() * cos(phi()) + z()* params.ptx;
child0.pty = pT() * sin(phi()) + z()* params.pty;
child0.pt = sqrt( sqr(child0.ptx) + sqr(child0.pty) );
child1.ptx = -pT() * cos(phi()) + (1.-z()) * params.ptx;
child1.pty = -pT() * sin(phi()) + (1.-z()) * params.pty;
child1.pt = sqrt( sqr(child1.ptx) + sqr(child1.pty) );
// set up the colour connections
splittingFn()->colourConnection(parent,children[0],children[1],partnerType,false);
// make the products children of the parent
parent->addChild(children[0]);
parent->addChild(children[1]);
// set the momenta of the children
for(ShowerParticleVector::const_iterator pit=children.begin();
pit!=children.end();++pit) {
setMomentum(*pit,true);
}
}
void Decay_QTildeShowerKinematics1to2::
reconstructParent( const tShowerParticlePtr, const ParticleVector &) const {
throw Exception() << "Decay_QTildeShowerKinematics1to2::updateParent not implemented"
<< Exception::abortnow;
}
void Decay_QTildeShowerKinematics1to2::
reconstructLast(const tShowerParticlePtr last, Energy mass) const {
// set beta component and consequently all missing data from that,
// using the nominal (i.e. PDT) mass.
Energy theMass = mass>ZERO ? mass : last->data().constituentMass();
last->showerParameters().beta=
(sqr(theMass) + sqr(last->showerParameters().pt)
- sqr( last->showerParameters().alpha )*pVector().m2())
/ ( 2.*last->showerParameters().alpha*p_dot_n() );
// set that new momentum
last->set5Momentum( sudakov2Momentum( last->showerParameters().alpha,
last->showerParameters().beta,
last->showerParameters().ptx,
last->showerParameters().pty) );
}
void Decay_QTildeShowerKinematics1to2::initialize(ShowerParticle & particle,PPtr) {
Lorentz5Momentum p, n, ppartner, pcm;
Frame frame;
assert(particle.perturbative()!=1);
// this is for the initial decaying particle
if(particle.perturbative()==2) {
p = particle.momentum();
ShowerParticlePtr partner=particle.partner();
Lorentz5Momentum ppartner(partner->momentum());
// reomved 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);
frame = Rest;
}
else {
tShoKinPtr kin=dynamic_ptr_cast<ShowerParticlePtr>(particle.parents()[0])
->showerKinematics();
p = kin->getBasis()[0];
n = kin->getBasis()[1];
frame = kin->frame();
}
setBasis(p,n,frame);
}
diff --git a/Shower/Default/Decay_QTildeShowerKinematics1to2.h b/Shower/Default/Decay_QTildeShowerKinematics1to2.h
--- a/Shower/Default/Decay_QTildeShowerKinematics1to2.h
+++ b/Shower/Default/Decay_QTildeShowerKinematics1to2.h
@@ -1,95 +1,96 @@
// -*- C++ -*-
//
// Decay_QTildeShowerKinematics1to2.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_Decay_QTildeShowerKinematics1to2_H
#define HERWIG_Decay_QTildeShowerKinematics1to2_H
//
// This is the declaration of the Decay_QTildeShowerKinematics1to2 class.
//
#include "QTildeShowerKinematics1to2.h"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
*
* This (concrete) class provides the specific decay shower
* kinematics information.
*
* @see QTildeShowerKinematics1to2
* @see IS_QTildeShowerKinematics1to2
* @see FS_QTildeShowerKinematics1to2
* @see KinematicsReconstructor
*
*/
class Decay_QTildeShowerKinematics1to2: public QTildeShowerKinematics1to2 {
public:
/**
* The updateChildren, updateParent and updateLast
* members to update the values of the \f$\alpha\f$ and
* \f$p_\perp\f$ variables during the shower evolution.
*/
//@{
/**
* Along with the showering evolution --- going forward for
* time-like (forward) evolution, and going backward for space-like
* (backward) evolution --- the kinematical variables of the
* branching products are calculated and updated from the knowledge
* of the parent kinematics. This method is used by the
* ForwardShowerEvolver.
* @param parent The branching particle
* @param children The particles produced in the branching
* @param partnerType The type of evolution partner
*/
virtual void updateChildren( const tShowerParticlePtr parent,
const ShowerParticleVector & children,
- ShowerPartnerType::Type partnerType) const;
+ ShowerPartnerType::Type partnerType,
+ bool massVeto) const;
/**
* Update the parent Kinematics from the knowledge of the kinematics
* of the children. This method will be used by the
* KinematicsReconstructor.
*/
virtual void reconstructParent( const tShowerParticlePtr parent,
const ParticleVector & children ) const;
/**
* Update the kinematical data of a particle when a reconstruction
* fixpoint was found. This will highly depend on the kind of
* kinematics chosen and will be defined in the inherited concrete
* classes. This method will be used by the KinematicsReconstructor.
* @param last The particle to update
* @param mass The mass to be used, if less than zero on-shell
*/
virtual void reconstructLast(const tShowerParticlePtr last, Energy mass=-1.*GeV) const;
/**
* Perform any initial calculations needed after the branching has been selected
* @param particle The branching particle
* @param parent The bema particle for the jet if needed
*/
virtual void initialize(ShowerParticle & particle,PPtr parent);
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
Decay_QTildeShowerKinematics1to2 & operator=(const Decay_QTildeShowerKinematics1to2 &);
};
}
#endif /* HERWIG_Decay_QTildeShowerKinematics1to2_H */
diff --git a/Shower/Default/FS_QTildeShowerKinematics1to2.cc b/Shower/Default/FS_QTildeShowerKinematics1to2.cc
--- a/Shower/Default/FS_QTildeShowerKinematics1to2.cc
+++ b/Shower/Default/FS_QTildeShowerKinematics1to2.cc
@@ -1,235 +1,251 @@
// -*- C++ -*-
//
// FS_QTildeShowerKinematics1to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the FS_QTildeShowerKinematics1to2 class.
//
#include "FS_QTildeShowerKinematics1to2.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "Herwig/Shower/SplittingFunctions/SplittingFunction.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "ThePEG/Utilities/Debug.h"
#include "Herwig/Shower/ShowerHandler.h"
#include "Herwig/Shower/Base/Evolver.h"
#include "Herwig/Shower/Base/PartnerFinder.h"
#include "Herwig/Shower/Base/ShowerModel.h"
#include "Herwig/Shower/Base/KinematicsReconstructor.h"
#include "Herwig/Shower/Base/ShowerVertex.h"
using namespace Herwig;
void FS_QTildeShowerKinematics1to2::
updateParameters(tShowerParticlePtr theParent,
tShowerParticlePtr theChild0,
tShowerParticlePtr theChild1,
bool setAlpha) const {
const ShowerParticle::Parameters & parent = theParent->showerParameters();
ShowerParticle::Parameters & child0 = theChild0->showerParameters();
ShowerParticle::Parameters & child1 = theChild1->showerParameters();
// determine alphas of children according to interpretation of z
if ( setAlpha ) {
child0.alpha = z() * parent.alpha;
child1.alpha = (1.-z()) * parent.alpha;
}
// set the values
double cphi = cos(phi());
double sphi = sin(phi());
child0.ptx = pT() * cphi + z() * parent.ptx;
child0.pty = pT() * sphi + z() * parent.pty;
child0.pt = sqrt( sqr(child0.ptx) + sqr(child0.pty) );
child1.ptx = -pT() * cphi + (1.-z())* parent.ptx;
child1.pty = -pT() * sphi + (1.-z())* parent.pty;
child1.pt = sqrt( sqr(child1.ptx) + sqr(child1.pty) );
}
void FS_QTildeShowerKinematics1to2::
updateChildren(const tShowerParticlePtr parent,
const ShowerParticleVector & children,
- ShowerPartnerType::Type partnerType) const {
+ ShowerPartnerType::Type partnerType,
+ bool massVeto) const {
assert(children.size()==2);
// calculate the scales
splittingFn()->evaluateFinalStateScales(partnerType,scale(),z(),parent,
children[0],children[1]);
+ // set the maximum virtual masses
+ if(massVeto) {
+ Energy2 q2 = z()*(1.-z())*sqr(scale());
+ vector<long> ids(3);
+ ids[0] = parent->id();
+ ids[1] = children[0]->id();
+ ids[2] = children[1]->id();
+ const vector<Energy> & virtualMasses = SudakovFormFactor()->virtualMasses(ids);
+ if(ids[0]!=ParticleID::g && ids[0]!=ParticleID::gamma ) {
+ q2 += sqr(virtualMasses[0]);
+ }
+ // limits on further evolution
+ children[0]->scales().Max_Q2 = z() *(q2-sqr(virtualMasses[2])/(1.-z()));
+ children[1]->scales().Max_Q2 = (1.-z())*(q2-sqr(virtualMasses[1])/ z() );
+ }
// update the parameters
updateParameters(parent, children[0], children[1], true);
// set up the colour connections
splittingFn()->colourConnection(parent,children[0],children[1],partnerType,false);
// make the products children of the parent
parent->addChild(children[0]);
parent->addChild(children[1]);
// set the momenta of the children
for(ShowerParticleVector::const_iterator pit=children.begin();
pit!=children.end();++pit) {
setMomentum(*pit,true);
}
// sort out the helicity stuff
if(! ShowerHandler::currentHandler()->evolver()->correlations()) return;
SpinPtr pspin(parent->spinInfo());
if(!pspin || !ShowerHandler::currentHandler()->evolver()->spinCorrelations() ) return;
Energy2 t = sqr(scale())*z()*(1.-z());
IdList ids;
ids.push_back(parent->id());
ids.push_back(children[0]->id());
ids.push_back(children[1]->id());
// create the vertex
SVertexPtr vertex(new_ptr(ShowerVertex()));
// set the matrix element
vertex->ME(splittingFn()->matrixElement(z(),t,ids,phi(),true));
// set the incoming particle for the vertex
parent->spinInfo()->decayVertex(vertex);
for(ShowerParticleVector::const_iterator pit=children.begin();
pit!=children.end();++pit) {
// construct the spin info for the children
constructSpinInfo(*pit,true);
// connect the spinInfo object to the vertex
(*pit)->spinInfo()->productionVertex(vertex);
}
}
void FS_QTildeShowerKinematics1to2::
reconstructParent(const tShowerParticlePtr parent,
const ParticleVector & children ) const {
assert(children.size() == 2);
ShowerParticlePtr c1 = dynamic_ptr_cast<ShowerParticlePtr>(children[0]);
ShowerParticlePtr c2 = dynamic_ptr_cast<ShowerParticlePtr>(children[1]);
parent->showerParameters().beta=
c1->showerParameters().beta + c2->showerParameters().beta;
Lorentz5Momentum pnew = c1->momentum() + c2->momentum();
Energy2 m2 = sqr(pT())/z()/(1.-z()) + sqr(c1->mass())/z()
+ sqr(c2->mass())/(1.-z());
pnew.setMass(sqrt(m2));
parent->set5Momentum( pnew );
}
void FS_QTildeShowerKinematics1to2::reconstructLast(const tShowerParticlePtr last,
Energy mass) const {
// set beta component and consequently all missing data from that,
// using the nominal (i.e. PDT) mass.
Energy theMass = mass > ZERO ? mass : last->data().constituentMass();
ShowerParticle::Parameters & lastParam = last->showerParameters();
Energy2 denom = 2. * lastParam.alpha * p_dot_n();
if(abs(denom)/(sqr(pVector().e())+pVector().rho2())<1e-10) {
throw KinematicsReconstructionVeto();
}
lastParam.beta = ( sqr(theMass) + sqr(lastParam.pt) - sqr(lastParam.alpha) * pVector().m2() )
/ denom;
// set that new momentum
Lorentz5Momentum newMomentum = sudakov2Momentum( lastParam.alpha, lastParam.beta,
lastParam.ptx , lastParam.pty);
newMomentum.setMass(theMass);
newMomentum.rescaleEnergy();
if(last->data().stable()) {
last->set5Momentum( newMomentum );
}
else {
last->boost(last->momentum().findBoostToCM());
last->boost(newMomentum.boostVector());
}
}
void FS_QTildeShowerKinematics1to2::initialize(ShowerParticle & particle,PPtr) {
// set the basis vectors
Lorentz5Momentum p,n;
Frame frame;
if(particle.perturbative()!=0) {
// find the partner and its momentum
ShowerParticlePtr partner=particle.partner();
Lorentz5Momentum ppartner(partner->momentum());
// momentum of the emitting particle
p = particle.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(particle.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);
}
}
frame = BackToBack;
}
else if(particle.initiatesTLS()) {
tShoKinPtr kin=dynamic_ptr_cast<ShowerParticlePtr>
(particle.parents()[0]->children()[0])->showerKinematics();
p = kin->getBasis()[0];
n = kin->getBasis()[1];
frame = kin->frame();
}
else {
tShoKinPtr kin=dynamic_ptr_cast<ShowerParticlePtr>(particle.parents()[0])
->showerKinematics();
p = kin->getBasis()[0];
n = kin->getBasis()[1];
frame = kin->frame();
}
// set the basis vectors
setBasis(p,n,frame);
}
void FS_QTildeShowerKinematics1to2::updateParent(const tShowerParticlePtr parent,
const ShowerParticleVector & children,
ShowerPartnerType::Type) const {
IdList ids(3);
ids[0] = parent->id();
ids[1] = children[0]->id();
ids[2] = children[1]->id();
const vector<Energy> & virtualMasses = SudakovFormFactor()->virtualMasses(ids);
if(children[0]->children().empty()) children[0]->virtualMass(virtualMasses[1]);
if(children[1]->children().empty()) children[1]->virtualMass(virtualMasses[2]);
// compute the new pT of the branching
Energy2 pt2=sqr(z()*(1.-z()))*sqr(scale())
- sqr(children[0]->virtualMass())*(1.-z())
- sqr(children[1]->virtualMass())* z() ;
if(ids[0]!=ParticleID::g) pt2 += z()*(1.-z())*sqr(virtualMasses[0]);
if(pt2>ZERO) {
Energy2 q2 =
sqr(children[0]->virtualMass())/z() +
sqr(children[1]->virtualMass())/(1.-z()) +
pt2/z()/(1.-z());
parent->virtualMass(sqrt(q2));
pT(sqrt(pt2));
}
else {
parent->virtualMass(ZERO);
}
}
void FS_QTildeShowerKinematics1to2::
resetChildren(const tShowerParticlePtr parent,
const ShowerParticleVector & children) const {
updateParameters(parent, children[0], children[1], false);
for(unsigned int ix=0;ix<children.size();++ix) {
if(children[ix]->children().empty()) continue;
ShowerParticleVector newChildren;
for(unsigned int iy=0;iy<children[ix]->children().size();++iy)
newChildren.push_back(dynamic_ptr_cast<ShowerParticlePtr>
(children[ix]->children()[iy]));
children[ix]->showerKinematics()->resetChildren(children[ix],newChildren);
}
}
diff --git a/Shower/Default/FS_QTildeShowerKinematics1to2.h b/Shower/Default/FS_QTildeShowerKinematics1to2.h
--- a/Shower/Default/FS_QTildeShowerKinematics1to2.h
+++ b/Shower/Default/FS_QTildeShowerKinematics1to2.h
@@ -1,123 +1,124 @@
// -*- C++ -*-
//
// FS_QTildeShowerKinematics1to2.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_FS_QTildeShowerKinematics1to2_H
#define HERWIG_FS_QTildeShowerKinematics1to2_H
//
// This is the declaration of the FS_QTildeShowerKinematics1to2 class.
//
#include "QTildeShowerKinematics1to2.h"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
*
* This (concrete) class provides the specific Final State shower
* kinematics information.
*
* @see QTildeShowerKinematics1to2
* @see IS_QTildeShowerKinematics1to2
* @see Decay_QTildeShowerKinematics1to2
* @see KinematicsReconstructor
*/
class FS_QTildeShowerKinematics1to2: public QTildeShowerKinematics1to2 {
public:
/**
* Default constructor
*/
inline FS_QTildeShowerKinematics1to2() {}
/**
* The updateChildren, updateParent and updateLast
* members to update the values of the \f$\alpha\f$ and
* \f$p_\perp\f$ variables during the shower evolution.
*/
//@{
/**
* Along with the showering evolution --- going forward for
* time-like (forward) evolution, and going backward for space-like
* (backward) evolution --- the kinematical variables of the
* branching products are calculated and updated from the knowledge
* of the parent kinematics. This method is used by the
* ForwardShowerEvolver.
* @param parent The branching particle
* @param children The particles produced in the branching
* @param partnerType The type of evolution partner
*/
private:
void updateParameters(tShowerParticlePtr theParent,
tShowerParticlePtr theChild0,
tShowerParticlePtr theChild1,
bool setAlpha) const;
public:
virtual void updateChildren( const tShowerParticlePtr parent,
const ShowerParticleVector & children,
- ShowerPartnerType::Type partnerType) const;
+ ShowerPartnerType::Type partnerType,
+ bool massVeto ) const;
virtual void resetChildren( const tShowerParticlePtr parent,
const ShowerParticleVector & children) const;
/**
* Update the parent Kinematics from the knowledge of the kinematics
* of the children. This method will be used by the KinematicsReconstructor.
* @param parent The parent
* @param children The children
* @param partnerType The type of evolution partner
*/
virtual void updateParent(const tShowerParticlePtr parent,
const ShowerParticleVector & children,
ShowerPartnerType::Type partnerType) const;
/**
* Update the parent Kinematics from the knowledge of the kinematics
* of the children. This method will be used by the
* KinematicsReconstructor.
*/
virtual void reconstructParent( const tShowerParticlePtr parent,
const ParticleVector & children ) const;
/**
* Update the kinematical data of a particle when a reconstruction
* fixpoint was found. This will highly depend on the kind of
* kinematics chosen and will be defined in the inherited concrete
* classes. This method will be used by the KinematicsReconstructor.
* @param last The particle to update
* @param mass The mass to be used, if less than zero on-shell
*/
virtual void reconstructLast(const tShowerParticlePtr last, Energy mass=-1.*GeV) const;
/**
* Perform any initial calculations needed after the branching has been selected
* @param particle The branching particle
* @param parent The bema particle for the jet if needed
*/
virtual void initialize(ShowerParticle & particle,PPtr parent);
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
FS_QTildeShowerKinematics1to2 & operator=(const FS_QTildeShowerKinematics1to2 &);
};
}
#endif /* HERWIG_FS_QTildeShowerKinematics1to2_H */
diff --git a/Shower/Default/IS_QTildeShowerKinematics1to2.cc b/Shower/Default/IS_QTildeShowerKinematics1to2.cc
--- a/Shower/Default/IS_QTildeShowerKinematics1to2.cc
+++ b/Shower/Default/IS_QTildeShowerKinematics1to2.cc
@@ -1,193 +1,194 @@
// -*- C++ -*-
//
// IS_QTildeShowerKinematics1to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the IS_QTildeShowerKinematics1to2 class.
//
#include "IS_QTildeShowerKinematics1to2.h"
#include "ThePEG/PDT/EnumParticles.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "ThePEG/Utilities/Debug.h"
#include "Herwig/Shower/ShowerHandler.h"
#include "Herwig/Shower/Base/Evolver.h"
#include "Herwig/Shower/Base/PartnerFinder.h"
#include "Herwig/Shower/Base/ShowerModel.h"
#include "Herwig/Shower/Base/KinematicsReconstructor.h"
#include "Herwig/Shower/Base/ShowerVertex.h"
#include <cassert>
using namespace Herwig;
void IS_QTildeShowerKinematics1to2::
updateChildren( const tShowerParticlePtr theParent,
const ShowerParticleVector & theChildren,
- ShowerPartnerType::Type) const {
+ ShowerPartnerType::Type,
+ bool massVeto) const {
const ShowerParticle::Parameters & parent = theParent->showerParameters();
ShowerParticle::Parameters & child0 = theChildren[0]->showerParameters();
ShowerParticle::Parameters & child1 = theChildren[1]->showerParameters();
double cphi = cos(phi());
double sphi = sin(phi());
child1.alpha = (1.-z()) * parent.alpha;
child1.ptx = (1.-z()) * parent.ptx - cphi * pT();
child1.pty = (1.-z()) * parent.pty - sphi * pT();
child1.pt = sqrt( sqr(child1.ptx) + sqr(child1.pty) );
// space-like child
child0.alpha = parent.alpha - child1.alpha;
child0.beta = parent.beta - child1.beta;
child0.ptx = parent.ptx - child1.ptx;
child0.pty = parent.pty - child1.pty;
}
void IS_QTildeShowerKinematics1to2::
updateParent(const tShowerParticlePtr parent,
const ShowerParticleVector & children,
ShowerPartnerType::Type partnerType) const {
// calculate the scales
splittingFn()->evaluateInitialStateScales(partnerType,scale(),z(),parent,
children[0],children[1]);
// set proper colour connections
splittingFn()->colourConnection(parent,children[0],children[1],
partnerType,true);
// set proper parent/child relationships
parent->addChild(children[0]);
parent->addChild(children[1]);
parent->x(children[0]->x()/z());
// sort out the helicity stuff
// construct the spin info for parent and timelike child
// temporary assignment of shower parameters to calculate correlations
parent->showerParameters().alpha = parent->x();
children[1]->showerParameters().alpha = (1.-z()) * parent->x();
children[1]->showerParameters().ptx = - cos(phi()) * pT();
children[1]->showerParameters().pty = - sin(phi()) * pT();
children[1]->showerParameters().pt = pT();
setMomentum(parent,false);
setMomentum(children[1],true);
if(! ShowerHandler::currentHandler()->evolver()->correlations()) return;
SpinPtr pspin(children[0]->spinInfo());
if(!pspin || !ShowerHandler::currentHandler()->evolver()->spinCorrelations() ) return;
// compute the matrix element for spin correlations
IdList ids;
ids.push_back(parent->id());
ids.push_back(children[0]->id());
ids.push_back(children[1]->id());
Energy2 t = (1.-z())*sqr(scale())/z();
// create the vertex
SVertexPtr vertex(new_ptr(ShowerVertex()));
// set the matrix element
vertex->ME(splittingFn()->matrixElement(z(),t,ids,phi(),false));
// set the incoming particle for the vertex
// (in reality the first child as going backwards)
pspin->decayVertex(vertex);
// construct the spin infos
constructSpinInfo(parent,false);
constructSpinInfo(children[1],true);
// connect the spinInfo objects to the vertex
parent ->spinInfo()->productionVertex(vertex);
children[1]->spinInfo()->productionVertex(vertex);
}
void IS_QTildeShowerKinematics1to2::
reconstructParent(const tShowerParticlePtr theParent,
const ParticleVector & theChildren ) const {
PPtr c1 = theChildren[0];
ShowerParticlePtr c2 = dynamic_ptr_cast<ShowerParticlePtr>(theChildren[1]);
ShowerParticle::Parameters & c2param = c2->showerParameters();
// get shower variables from 1st child in order to keep notation
// parent->(c1, c2) clean even though the splitting was initiated
// from c1. The name updateParent is still referring to the
// timelike branching though.
// on-shell child
c2param.beta = 0.5*( sqr(c2->data().constituentMass()) + sqr(c2param.pt) )
/ ( c2param.alpha * p_dot_n() );
Lorentz5Momentum pnew = sudakov2Momentum(c2param.alpha, c2param.beta,
c2param.ptx , c2param.pty);
pnew.setMass(c2->data().constituentMass());
pnew.rescaleEnergy();
c2->set5Momentum( pnew );
// spacelike child
Lorentz5Momentum pc1(theParent->momentum() - c2->momentum());
pc1.rescaleMass();
c1->set5Momentum(pc1);
}
void IS_QTildeShowerKinematics1to2::
updateLast( const tShowerParticlePtr theLast,Energy px,Energy py) const {
if(theLast->isFinalState()) return;
ShowerParticle::Parameters & last = theLast->showerParameters();
Energy2 pt2 = sqr(px) + sqr(py);
last.alpha = theLast->x();
last.beta = 0.5 * pt2 / last.alpha / p_dot_n();
last.ptx = ZERO;
last.pty = ZERO;
last.pt = ZERO;
// momentum
Lorentz5Momentum ntemp = Lorentz5Momentum(ZERO,-pVector().vect());
double beta = 0.5 * pt2 / last.alpha / (pVector() * ntemp);
Lorentz5Momentum plast =
Lorentz5Momentum( (pVector().z()>ZERO ? px : -px), py, ZERO, ZERO)
+ theLast->x() * pVector() + beta * ntemp;
plast.rescaleMass();
theLast->set5Momentum(plast);
}
void IS_QTildeShowerKinematics1to2::initialize(ShowerParticle & particle, PPtr parent) {
// For the time being we are considering only 1->2 branching
Lorentz5Momentum p, n, pthis, pcm;
assert(particle.perturbative()!=2);
Frame frame;
if(particle.perturbative()==1) {
// find the partner and its momentum
ShowerParticlePtr partner=particle.partner();
assert(partner);
if(partner->isFinalState()) {
Lorentz5Momentum pa = -particle.momentum()+partner->momentum();
Lorentz5Momentum pb = particle.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());
}
frame = BackToBack;
}
else {
p = dynamic_ptr_cast<ShowerParticlePtr>(particle.children()[0])
->showerKinematics()->getBasis()[0];
n = dynamic_ptr_cast<ShowerParticlePtr>(particle.children()[0])
->showerKinematics()->getBasis()[1];
frame = dynamic_ptr_cast<ShowerParticlePtr>(particle.children()[0])
->showerKinematics()->frame();
}
setBasis(p,n,frame);
}
diff --git a/Shower/Default/IS_QTildeShowerKinematics1to2.h b/Shower/Default/IS_QTildeShowerKinematics1to2.h
--- a/Shower/Default/IS_QTildeShowerKinematics1to2.h
+++ b/Shower/Default/IS_QTildeShowerKinematics1to2.h
@@ -1,118 +1,119 @@
// -*- C++ -*-
//
// IS_QTildeShowerKinematics1to2.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_IS_QTildeShowerKinematics1to2_H
#define HERWIG_IS_QTildeShowerKinematics1to2_H
//
// This is the declaration of the IS_QTildeShowerKinematics1to2 class.
//
#include "QTildeShowerKinematics1to2.h"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
*
* This (concrete) class provides the specific Intial State shower
* kinematics information.
*
* @see QTildeShowerKinematics1to2
* @see FS_QTildeShowerKinematics1to2
* @see Decay_QTildeShowerKinematics1to2
* @see KinematicsReconstructor
*/
class IS_QTildeShowerKinematics1to2: public QTildeShowerKinematics1to2 {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* Construct in terms of the basis states
*/
inline IS_QTildeShowerKinematics1to2() {}
//@}
public:
/**
* The updateChildren, updateParent and updateLast
* members to update the values of the \f$\alpha\f$ and
* \f$p_\perp\f$ variables during the shower evolution.
*/
//@{
/**
* Along with the showering evolution --- going forward for
* time-like (forward) evolution, and going backward for space-like
* (backward) evolution --- the kinematical variables of the
* branching products are calculated and updated from the knowledge
* of the parent kinematics. This method is used by the
* ForwardShowerEvolver.
* @param parent The branching particle
* @param children The particles produced in the branching
* @param partnerType The type of evolution partner
*/
virtual void updateChildren( const tShowerParticlePtr parent,
const ShowerParticleVector & children,
- ShowerPartnerType::Type partnerType) const;
+ ShowerPartnerType::Type partnerType,
+ bool massVeto) const;
/**
* Update the parent Kinematics from the knowledge of the kinematics
* of the children. This method will be used by the
* KinematicsReconstructor.
* @param parent The branching particle
* @param children The particles produced in the branching
* @param partnerType The type of evolution partner
*/
virtual void updateParent( const tShowerParticlePtr parent,
const ShowerParticleVector & children,
ShowerPartnerType::Type partnerType) const;
/**
* Update the parent Kinematics from the knowledge of the kinematics
* of the children. This method will be used by the
* KinematicsReconstructor.
*/
virtual void reconstructParent( const tShowerParticlePtr parent,
const ParticleVector & children ) const;
/**
* Update the kinematical data of a particle when a reconstruction
* fixpoint was found. This will highly depend on the kind of
* kinematics chosen and will be defined in the inherited concrete
* classes. This method will be used by the KinematicsReconstructor.
* @param theLast The particle.
* @param px The \f$x\f$ component of the \f$p_T\f$.
* @param py The \f$y\f$ component of the \f$p_T\f$.
*/
virtual void updateLast(const tShowerParticlePtr theLast,
Energy px, Energy py) const;
/**
* Perform any initial calculations needed after the branching has been selected
* @param particle The branching particle
* @param parent The bema particle for the jet if needed
*/
virtual void initialize(ShowerParticle & particle,PPtr parent);
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
IS_QTildeShowerKinematics1to2 & operator=(const IS_QTildeShowerKinematics1to2 &);
};
}
#endif /* HERWIG_IS_QTildeShowerKinematics1to2_H */
diff --git a/Shower/Default/QTildeReconstructor.cc b/Shower/Default/QTildeReconstructor.cc
--- a/Shower/Default/QTildeReconstructor.cc
+++ b/Shower/Default/QTildeReconstructor.cc
@@ -1,2938 +1,2939 @@
// -*- C++ -*-
//
// QTildeReconstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the 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/Base/Evolver.h"
#include "Herwig/Shower/Base/PartnerFinder.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "Herwig/Shower/SplittingFunctions/SplittingFunction.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/EventRecord/ColourLine.h"
#include "ThePEG/Utilities/DescribeClass.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()) {
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->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 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::Type) 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()->showerKinematics()->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, cEvolverPtr,
ShowerInteraction::Type) 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);
}
}
// // find the evolution partners
// ShowerParticleVector particles;
// particles.push_back((**decay->incoming().begin()).branchingParticle());
// for(cit=branchings.begin();cit!=branchings.end();++cit) {
// if((**cit).status()==HardBranching::Outgoing)
// particles.push_back((*cit)->branchingParticle());
// }
// // partners should
// evolver->showerModel()->partnerFinder()
// ->setInitialEvolutionScales(particles,true,type,false);
// 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(isnan(lambda))
throw Exception() << "Rescaling factor is nan in QTildeReconstructor::"
<< "inverseRescalingFactor "
<< Exception::eventerror;
return lambda;
}
bool QTildeReconstructor::
deconstructGeneralSystem(HardTreePtr tree,
cEvolverPtr evolver,
ShowerInteraction::Type 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,evolver,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,
cEvolverPtr evolver,
ShowerInteraction::Type type) const {
// inverse of old recon method
if(_reconopt == 0) {
return deconstructGeneralSystem(tree,evolver,type);
}
else if(_reconopt == 1) {
return deconstructColourSinglets(tree,evolver,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,evolver,type);
}
else
assert(false);
}
bool QTildeReconstructor::
deconstructColourSinglets(HardTreePtr tree,cEvolverPtr evolver,
ShowerInteraction::Type 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::QED||type==ShowerInteraction::Both) {
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,evolver,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::QED||type==ShowerInteraction::Both) {
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,evolver,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,evolver,type);
}
return true;
}
bool QTildeReconstructor::
deconstructColourPartner(HardTreePtr tree,cEvolverPtr evolver,
ShowerInteraction::Type 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,evolver,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,evolver,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,evolver,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()->showerKinematics()->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;
}
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) {
if(betam<0.5) {
gamma = 1./sqrt(1.-sqr(betam));
}
else {
gamma = ( kps+ qs + Q2)/
sqrt(2.*kps*qs + kps*Q2 + qs*Q2 + sqr(Q2) + 2.*q*newq.e()*kp*sqrt(kps + Q2));
}
}
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);
}
// note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper.
ThreeVector<Energy2> ax = newq.vect().cross( oldp.vect() );
double 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::Type) 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,
cEvolverPtr evolver,
ShowerInteraction::Type 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());
}
evolver->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());
}
evolver->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(const 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,
cEvolverPtr evolver,
ShowerInteraction::Type 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());
}
evolver->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->showerKinematics()) {
sparticle->showerKinematics()->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 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::QED||
type==ShowerInteraction::Both) {
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::QED || type == ShowerInteraction::Both;
}
// 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/Default/QTildeSudakov.cc b/Shower/Default/QTildeSudakov.cc
--- a/Shower/Default/QTildeSudakov.cc
+++ b/Shower/Default/QTildeSudakov.cc
@@ -1,977 +1,981 @@
// -*- C++ -*-
//
// QTildeSudakov.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the 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/Default/FS_QTildeShowerKinematics1to2.h"
#include "Herwig/Shower/Default/IS_QTildeShowerKinematics1to2.h"
#include "Herwig/Shower/Default/Decay_QTildeShowerKinematics1to2.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "Herwig/Shower/Base/ShowerVertex.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "Herwig/Shower/ShowerHandler.h"
#include "Herwig/Shower/Base/Evolver.h"
#include "Herwig/Shower/Base/PartnerFinder.h"
#include "Herwig/Shower/Base/ShowerModel.h"
#include "Herwig/Shower/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) {
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]);
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) {
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]);
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) {
+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]!=ParticleID::g &&
+ ids_[0]!=ParticleID::gamma ) q2 += masssquared_[0];
+ if(q2>maxQ2) return true;
// compute the pts
- Energy2 pt2=sqr(z()*(1.-z()))*t-masssquared_[1]*(1.-z())-masssquared_[2]*z();
- if(ids_[0]!=ParticleID::g) pt2+=z()*(1.-z())*masssquared_[0];
+ 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 bool cc,
- double enhance) {
+ double enhance, 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,cc);
// check max > min
if(tmax<=tmin) return ShoKinPtr();
// calculate next value of t using veto algorithm
Energy2 t(tmax);
do {
if(!guessTimeLike(t,tmin,enhance)) break;
}
- while(PSVeto(t) || SplittingFnVeto(z()*(1.-z())*t,ids,true) ||
+ while(PSVeto(t,maxQ2) || SplittingFnVeto(z()*(1.-z())*t,ids,true) ||
alphaSVeto(splittingFn()->angularOrdered() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t));
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,bool cc,
double enhance,
Ptr<BeamParticleData>::transient_const_pointer beam) {
// 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,cc);
// check max > min
if(tmax<=tmin) return ShoKinPtr();
// extract the partons which are needed for the PDF veto
// Different order, incoming parton is id = 1, outgoing are id=0,2
tcPDPtr parton0 = getParticleData(ids[0]);
tcPDPtr parton1 = getParticleData(ids[1]);
if(cc) {
if(parton0->CC()) parton0 = parton0->CC();
if(parton1->CC()) parton1 = parton1->CC();
}
// calculate next value of t using veto algorithm
Energy2 t(tmax),pt2(ZERO);
do {
if(!guessSpaceLike(t,tmin,x,enhance)) break;
pt2=sqr(1.-z())*t-z()*masssquared_[2];
}
while(z() > zLimits().second ||
SplittingFnVeto((1.-z())*t/z(),ids,true) ||
alphaSVeto(splittingFn()->angularOrdered() ? sqr(1.-z())*t : (1.-z())*t) ||
PDFVeto(t,x,parton0,parton1,beam) || pt2 < pT2min() );
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,const bool cc) {
ids_=ids;
if(cc) {
for(unsigned int ix=0;ix<ids.size();++ix) {
if(getParticleData(ids[ix])->CC()) ids_[ix]*=-1;
}
}
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 bool cc,
double enhance) {
// 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,cc);
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)) break;
pt2 = sqr(1.-z())*(t-masssquared_[0])-z()*masssquared_[2];
}
while(SplittingFnVeto((1.-z())*t/z(),ids,true)||
alphaSVeto(splittingFn()->angularOrdered() ? 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) {
// 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]);
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]==ParticleID::g||ids_[0]==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]==ParticleID::g||ids_[2]==ParticleID::gamma) {
limits.first = sqrt((masssquared_[1]+pT2min())/t);
limits.second = 1.-sqrt((masssquared_[2]+pT2min())/t);
}
else if(ids_[1]==ParticleID::g||ids_[1]==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::Type 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);
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 QTildeSudakov::generatePhiForward(ShowerParticle & particle,
const IdList & ids,
ShoKinPtr kinematics) {
// no correlations, return flat phi
if(! ShowerHandler::currentHandler()->evolver()->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]==ParticleID::g || ids[1]==ParticleID::gamma,
ids[2]==ParticleID::g || ids[2]==ParticleID::gamma };
vector<Energy2> pjk(3,ZERO);
vector<Energy> Ek(3,ZERO);
Energy Ei,Ej;
Energy2 m12(ZERO),m22(ZERO);
InvEnergy2 aziMax(ZERO);
bool softAllowed = ShowerHandler::currentHandler()->evolver()->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
vector<Lorentz5Momentum> basis = kinematics->getBasis();
Lorentz5Momentum pVect = basis[0], nVect = basis[1];
Boost beta_bb;
if(kinematics->frame()==ShowerKinematics::BackToBack) {
beta_bb = -(pVect + nVect).boostVector();
}
else if(kinematics->frame()==ShowerKinematics::Rest) {
beta_bb = -pVect.boostVector();
}
else
assert(false);
pVect.boost(beta_bb);
nVect.boost(beta_bb);
Axis axis;
if(kinematics->frame()==ShowerKinematics::BackToBack) {
axis = pVect.vect().unit();
}
else if(kinematics->frame()==ShowerKinematics::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(ShowerHandler::currentHandler()->evolver()->softCorrelations()==1) {
aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag);
}
else if(ShowerHandler::currentHandler()->evolver()->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(ShowerHandler::currentHandler()->evolver()->spinCorrelations()) {
// get the spin density matrix and the mapping
RhoDMatrix mapping;
SpinPtr inspin;
bool needMapping = getMapping(inspin,mapping,particle,kinematics);
// set the decayed flag
inspin->decay();
// get the spin density matrix
RhoDMatrix rho=inspin->rhoMatrix();
// map to the shower basis if needed
if(needMapping) {
RhoDMatrix rhop(rho.iSpin(),false);
for(int ixa=0;ixa<rho.iSpin();++ixa) {
for(int ixb=0;ixb<rho.iSpin();++ixb) {
for(int iya=0;iya<rho.iSpin();++iya) {
for(int iyb=0;iyb<rho.iSpin();++iyb) {
rhop(ixa,ixb) += rho(iya,iyb)*mapping(iya,ixa)*conj(mapping(iyb,ixb));
}
}
}
}
rhop.normalize();
rho = rhop;
}
// calculate the weights
wgts = splittingFn()->generatePhiForward(z,t,ids,rho);
}
else {
wgts = vector<pair<int,Complex> >(1,make_pair(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] << " " << ids[1] << " " << ids[2] << " " << " " << 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(ShowerHandler::currentHandler()->evolver()->softCorrelations()==1) {
aziWgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax;
}
else if(ShowerHandler::currentHandler()->evolver()->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] << " " << ids[1] << " " << ids[2] << " " << " " << 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) {
// no correlations, return flat phi
if(! ShowerHandler::currentHandler()->evolver()->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 = ShowerHandler::currentHandler()->evolver()->softCorrelations() &&
(ids[2]==ParticleID::g || ids[2]==ParticleID::gamma);
Energy2 pipj,pik,m12(ZERO),m22(ZERO);
vector<Energy2> pjk(3,ZERO);
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
vector<Lorentz5Momentum> basis = kinematics->getBasis();
Lorentz5Momentum pVect = basis[0];
Lorentz5Momentum nVect = basis[1];
assert(kinematics->frame()==ShowerKinematics::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(ShowerHandler::currentHandler()->evolver()->softCorrelations()==1) {
aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag);
}
else if(ShowerHandler::currentHandler()->evolver()->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(ShowerHandler::currentHandler()->evolver()->softCorrelations()==0);
}
}
// if spin correlations
vector<pair<int,Complex> > wgts;
if(ShowerHandler::currentHandler()->evolver()->spinCorrelations()) {
// get the spin density matrix and the mapping
RhoDMatrix mapping;
SpinPtr inspin;
bool needMapping = getMapping(inspin,mapping,particle,kinematics);
// set the decayed flag (counterintuitive but going backward)
inspin->decay();
// get the spin density matrix
RhoDMatrix rho=inspin->DMatrix();
// map to the shower basis if needed
if(needMapping) {
RhoDMatrix rhop(rho.iSpin(),false);
for(int ixa=0;ixa<rho.iSpin();++ixa) {
for(int ixb=0;ixb<rho.iSpin();++ixb) {
for(int iya=0;iya<rho.iSpin();++iya) {
for(int iyb=0;iyb<rho.iSpin();++iyb) {
rhop(ixa,ixb) += rho(iya,iyb)*mapping(iya,ixa)*conj(mapping(iyb,ixb));
}
}
}
}
rhop.normalize();
rho = rhop;
}
wgts = splittingFn()->generatePhiBackward(z,t,ids,rho);
}
else {
wgts = vector<pair<int,Complex> >(1,make_pair(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] << " " << ids[1] << " " << ids[2] << " " << " " << 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(ShowerHandler::currentHandler()->evolver()->softCorrelations()==1) {
aziWgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax;
}
else if(ShowerHandler::currentHandler()->evolver()->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] << " " << ids[1] << " " << ids[2] << " " << " " << 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) {
// only soft correlations in this case
// no correlations, return flat phi
if( !(ShowerHandler::currentHandler()->evolver()->softCorrelations() &&
(ids[2]==ParticleID::g || ids[2]==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);
vector<Lorentz5Momentum> basis = kinematics->getBasis();
// compute the transforms to the shower reference frame
// first the boost
Lorentz5Momentum pVect = basis[0];
Lorentz5Momentum nVect = basis[1];
assert(kinematics->frame()==ShowerKinematics::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);
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);
Energy Ei,Ej;
if(ShowerHandler::currentHandler()->evolver()->softCorrelations()==1) {
aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag);
}
else if(ShowerHandler::currentHandler()->evolver()->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(ShowerHandler::currentHandler()->evolver()->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(ShowerHandler::currentHandler()->evolver()->softCorrelations()==1) {
wgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax;
}
else if(ShowerHandler::currentHandler()->evolver()->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] << " " << ids[1] << " " << ids[2] << " " << " " << 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,false);
// final-state branching
if(iopt==0) {
Energy2 scale=(sqr(pt)+masssquared_[1]*(1.-zin)+masssquared_[2]*zin);
if(ids[0]!=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/Default/QTildeSudakov.h b/Shower/Default/QTildeSudakov.h
--- a/Shower/Default/QTildeSudakov.h
+++ b/Shower/Default/QTildeSudakov.h
@@ -1,285 +1,287 @@
// -*- C++ -*-
//
// QTildeSudakov.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_QTildeSudakov_H
#define HERWIG_QTildeSudakov_H
//
// This is the declaration of the QTildeSudakov class.
//
#include "Herwig/Shower/Base/SudakovFormFactor.h"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Shower
*
* The QTildeSudakov class implements the Sudakov form factor for evolution in
* \f$\tilde{q}^2\f$ using the veto algorithm.
*
* @see \ref QTildeSudakovInterfaces "The interfaces"
* defined for QTildeSudakov.
*/
class QTildeSudakov: public SudakovFormFactor {
public:
/**
* The default constructor.
*/
inline QTildeSudakov() {}
/**
* Members to generate the scale of the next branching
*/
//@{
/**
* Return the scale of the next time-like branching. If there is no
* branching then it returns ZERO.
* @param startingScale starting scale for the evolution
* @param ids The PDG codes of the particles in the splitting
* @param cc Whether this is the charge conjugate of the branching
* defined.
* @param enhance The radiation enhancement factor
+ * @param maxQ2 The maximum \f$Q^2\f$ for the emission
*/
virtual ShoKinPtr generateNextTimeBranching(const Energy startingScale,
const IdList &ids,const bool cc,
- double enhance);
+ double enhance, Energy2 maxQ2);
/**
* Return the scale of the next space-like decay branching. If there is no
* branching then it returns ZERO.
* @param startingScale starting scale for the evolution
* @param stoppingScale stopping scale for the evolution
* @param minmass The minimum mass allowed for the spake-like particle.
* @param ids The PDG codes of the particles in the splitting
* @param cc Whether this is the charge conjugate of the branching
* defined.
* @param enhance The radiation enhancement factor
*/
virtual ShoKinPtr generateNextDecayBranching(const Energy startingScale,
const Energy stoppingScale,
const Energy minmass,
const IdList &ids,
const bool cc,
double enhance);
/**
* Return the scale of the next space-like branching. If there is no
* branching then it returns ZERO.
* @param startingScale starting scale for the evolution
* @param ids The PDG codes of the particles in the splitting
* @param x The fraction of the beam momentum
* @param cc Whether this is the charge conjugate of the branching
* defined.
* @param enhance The radiation enhancement factor
* @param beam The beam particle
*/
virtual ShoKinPtr generateNextSpaceBranching(const Energy startingScale,
const IdList &ids,double x,
const bool cc, double enhance,
tcBeamPtr beam);
//@}
/**
* Generate the azimuthal angle of the branching for forward branching
* @param particle The branching particle
* @param ids The PDG codes of the particles in the branchings
* @param The Shower kinematics
*/
virtual double generatePhiForward(ShowerParticle & particle,const IdList & ids,
ShoKinPtr kinematics);
/**
* Generate the azimuthal angle of the branching for backward branching
* @param particle The branching particle
* @param ids The PDG codes of the particles in the branchings
* @param The Shower kinematics
*/
virtual double generatePhiBackward(ShowerParticle & particle,const IdList & ids,
ShoKinPtr kinematics);
/**
* Generate the azimuthal angle of the branching for ISR in decays
* @param particle The branching particle
* @param ids The PDG codes of the particles in the branchings
* @param The Shower kinematics
*/
virtual double generatePhiDecay(ShowerParticle & particle,const IdList & ids,
ShoKinPtr kinematics);
/**
* Method to return the evolution scale given the
* transverse momentum, \f$p_T\f$ and \f$z\f$.
*/
virtual Energy calculateScale(double z, Energy pt, IdList ids,unsigned int iopt);
/**
* Method to create the ShowerKinematics object for a final-state branching
*/
virtual ShoKinPtr createFinalStateBranching(Energy scale,double z,
double phi, Energy pt);
/**
* Method to create the ShowerKinematics object for an initial-state branching
*/
virtual ShoKinPtr createInitialStateBranching(Energy scale,double z,
double phi, Energy pt);
/**
* Method to create the ShowerKinematics object for a decay branching
*/
virtual ShoKinPtr createDecayBranching(Energy scale,double z,
double phi, Energy pt);
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:
/**
* Methods to provide the next value of the scale before the vetos
* are applied.
*/
//@{
/**
* Value of the energy fraction and scale for time-like branching
* @param t The scale
* @param tmin The minimum scale
* @param enhance The radiation enhancement factor
* @return False if scale less than minimum, true otherwise
*/
bool guessTimeLike(Energy2 &t, Energy2 tmin, double enhance);
/**
* Value of the energy fraction and scale for time-like branching
* @param t The scale
* @param tmax The maximum scale
* @param minmass The minimum mass of the particle after the branching
* @param enhance The radiation enhancement factor
*/
bool guessDecay(Energy2 &t, Energy2 tmax,Energy minmass,
double enhance);
/**
* Value of the energy fraction and scale for space-like branching
* @param t The scale
* @param tmin The minimum scale
* @param x Fraction of the beam momentum.
* @param enhance The radiation enhancement factor
*/
bool guessSpaceLike(Energy2 &t, Energy2 tmin, const double x,
double enhance);
//@}
/**
* Initialize the values of the cut-offs and scales
* @param tmin The minimum scale
* @param ids The ids of the partics in the branching
* @param cc Whether this is the charge conjugate of the branching
*/
void initialize(const IdList & ids,Energy2 &tmin, const bool cc);
/**
* Phase Space veto member to implement the \f$\Theta\f$ function as a veto
* so that the emission is within the allowed phase space.
* @param t The scale
+ * @param maxQ2 The maximum virtuality
* @return true if vetoed
*/
- bool PSVeto(const Energy2 t);
+ bool PSVeto(const Energy2 t,const Energy2 maxQ2);
/**
* Compute the limits on \f$z\f$ for time-like branching
* @param scale The scale of the particle
* @return True if lower limit less than upper, otherwise false
*/
bool computeTimeLikeLimits(Energy2 & scale);
/**
* Compute the limits on \f$z\f$ for space-like branching
* @param scale The scale of the particle
* @param x The energy fraction of the parton
* @return True if lower limit less than upper, otherwise false
*/
bool computeSpaceLikeLimits(Energy2 & scale, double x);
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
inline virtual IBPtr clone() const {return new_ptr(*this);}
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
inline virtual IBPtr fullclone() const {return new_ptr(*this);}
//@}
private:
/**
* The assignment operator is private and must never be called.
* In fact, it should not even be implemented.
*/
QTildeSudakov & operator=(const QTildeSudakov &);
private:
/**
* The evolution scale, \f$\tilde{q}\f$.
*/
Energy q_;
/**
* The Ids of the particles in the current branching
*/
IdList ids_;
/**
* The masses of the particles in the current branching
*/
vector<Energy> masses_;
/**
* The mass squared of the particles in the current branching
*/
vector<Energy2> masssquared_;
};
}
#endif /* HERWIG_QTildeSudakov_H */
diff --git a/Shower/SplittingFunctions/SplittingGenerator.cc b/Shower/SplittingFunctions/SplittingGenerator.cc
--- a/Shower/SplittingFunctions/SplittingGenerator.cc
+++ b/Shower/SplittingFunctions/SplittingGenerator.cc
@@ -1,572 +1,577 @@
// -*- C++ -*-
//
// SplittingGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2011 The Herwig Collaboration
//
// Herwig is licenced under version 2 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// This is the implementation of the non-inlined, non-templated member
// functions of the 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/Utilities/StringUtils.h"
#include "ThePEG/Repository/Repository.h"
#include "Herwig/Shower/Base/ShowerParticle.h"
#include "ThePEG/Utilities/Rebinder.h"
#include <cassert>
#include "ThePEG/Utilities/DescribeClass.h"
using namespace Herwig;
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 << _isr_Mode << _fsr_Mode << _bbranchings << _fbranchings;
}
void SplittingGenerator::persistentInput(PersistentIStream & is, int) {
is >> _isr_Mode >> _fsr_Mode >> _bbranchings >> _fbranchings;
}
void SplittingGenerator::Init() {
static ClassDocumentation<SplittingGenerator> documentation
("There class is responsible for initializing the Sudakov form factors ",
"and generating splittings.");
static Switch<SplittingGenerator, bool> interfaceISRMode
("ISR",
"Include initial-state radiation?",
&SplittingGenerator::_isr_Mode, 1, false, false);
static SwitchOption interfaceISRMode0
(interfaceISRMode,"No","ISR (Initial State Radiation) is OFF", 0);
static SwitchOption interfaceISRMode1
(interfaceISRMode,"Yes","ISR (Initial State Radiation) is ON", 1);
static Switch<SplittingGenerator, bool> interfaceFSRMode
("FSR",
"Include final-state radiation?",
&SplittingGenerator::_fsr_Mode, 1, false, false);
static SwitchOption interfaceFSRMode0
(interfaceFSRMode,"No","FSR (Final State Radiation) is OFF", 0);
static SwitchOption interfaceFSRMode1
(interfaceFSRMode,"Yes","FSR (Final State Radiation) is ON", 1);
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);
}
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->id());
for(vector<tPDPtr>::iterator it = products.begin(); it!=products.end(); ++it)
ids.push_back((*it)->id());
// check splitting can handle this
if(!s->splittingFn()->accept(ids))
return "Error: Sudakov " + sudakov + "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->id());
for(vector<tPDPtr>::iterator it = products.begin(); it!=products.end(); ++it)
ids.push_back((*it)->id());
// check splitting can handle this
if(!s->splittingFn()->accept(ids))
return "Error: Sudakov " + sudakov + "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(isISRadiationON() && !final) {
_bbranchings.insert(BranchingInsert(ids[1],BranchingElement(s,ids)));
s->addSplitting(ids);
}
if(isFSRadiationON() && final) {
_fbranchings.insert(BranchingInsert(ids[0],BranchingElement(s,ids)));
s->addSplitting(ids);
}
}
void SplittingGenerator::deleteFromMap(const IdList &ids,
const SudakovPtr &s, bool final) {
if(isISRadiationON() && !final) {
pair<BranchingList::iterator,BranchingList::iterator>
range = _bbranchings.equal_range(ids[1]);
for(BranchingList::iterator it=range.first;
it!=range.second&&it!=_bbranchings.end()&&it->first==ids[1];++it) {
if(it->second.first==s&&it->second.second==ids) {
BranchingList::iterator it2=it;
--it;
_bbranchings.erase(it2);
}
}
s->removeSplitting(ids);
}
if(isFSRadiationON() && final) {
pair<BranchingList::iterator,BranchingList::iterator>
range = _fbranchings.equal_range(ids[0]);
for(BranchingList::iterator it=range.first;
it!=range.second&&it!=_fbranchings.end()&&it->first==ids[0];++it) {
if(it->second.first==s&&it->second.second==ids) {
BranchingList::iterator it2 = it;
--it;
_fbranchings.erase(it2);
}
}
s->removeSplitting(ids);
}
}
Branching SplittingGenerator::chooseForwardBranching(ShowerParticle &particle,
double enhance,
ShowerInteraction::Type type) const {
Energy newQ = ZERO;
ShoKinPtr kinematics = ShoKinPtr();
ShowerPartnerType::Type 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(type != cit->second.first->interactionType() &&
type != ShowerInteraction::Both ) continue;
// whether or not this interaction should be angular ordered
bool angularOrdered = cit->second.first->splittingFn()->angularOrdered();
ShoKinPtr newKin;
ShowerPartnerType::Type type;
// work out which starting scale we need
if(cit->second.first->interactionType()==ShowerInteraction::QED) {
type = ShowerPartnerType::QED;
Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO;
newKin = cit->second.first->
generateNextTimeBranching(startingScale,cit->second.second,
- particle.id()!=cit->first,enhance);
+ particle.id()!=cit->first,enhance,
+ particle.scales().Max_Q2);
}
else if(cit->second.first->interactionType()==ShowerInteraction::QCD) {
// special for octets
if(particle.dataPtr()->iColour()==PDT::Colour8) {
// octet -> octet octet
if(cit->second.first->splittingFn()->colourStructure()==OctetOctetOctet) {
type = ShowerPartnerType::QCDColourLine;
Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO;
newKin= cit->second.first->
generateNextTimeBranching(startingScale,cit->second.second,
- particle.id()!=cit->first,0.5*enhance);
+ particle.id()!=cit->first,0.5*enhance,
+ particle.scales().Max_Q2);
startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO;
ShoKinPtr newKin2 = cit->second.first->
generateNextTimeBranching(startingScale,cit->second.second,
- particle.id()!=cit->first,0.5*enhance);
+ particle.id()!=cit->first,0.5*enhance,
+ 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.first->
generateNextTimeBranching(startingScale, cit->second.second,
- particle.id()!=cit->first,enhance);
+ particle.id()!=cit->first,enhance,
+ 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.first->
generateNextTimeBranching(startingScale,cit->second.second,
- particle.id()!=cit->first,enhance);
+ particle.id()!=cit->first,enhance,
+ 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 = cit->second.second;
sudakov = cit->second.first;
partnerType = type;
}
}
// return empty branching if nothing happened
if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),
ShowerPartnerType::Undefined);
// If a branching has been selected initialize it
kinematics->initialize(particle,PPtr());
// and return it
return Branching(kinematics, ids,sudakov,partnerType);
}
Branching SplittingGenerator::
chooseDecayBranching(ShowerParticle &particle,
const ShowerParticle::EvolutionScales & stoppingScales,
Energy minmass, double enhance,
ShowerInteraction::Type interaction) const {
Energy newQ = Constants::MaxEnergy;
ShoKinPtr kinematics;
SudakovPtr sudakov;
ShowerPartnerType::Type 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.second[1]!=index&&cit->second.second[2]!=index) continue;
// check either right interaction or doing both
if(interaction != cit->second.first->interactionType() &&
interaction != ShowerInteraction::Both ) continue;
// whether or not this interaction should be angular ordered
bool angularOrdered = cit->second.first->splittingFn()->angularOrdered();
ShoKinPtr newKin;
ShowerPartnerType::Type type;
// work out which starting scale we need
if(cit->second.first->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.first->
generateNextDecayBranching(startingScale,stoppingScale,minmass,cit->second.second,
particle.id()!=cit->first,enhance);
}
}
else if(cit->second.first->interactionType()==ShowerInteraction::QCD) {
// special for octets
if(particle.dataPtr()->iColour()==PDT::Colour8) {
// octet -> octet octet
if(cit->second.first->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.first->
generateNextDecayBranching(startingColour,stoppingColour,minmass,
cit->second.second,
particle.id()!=cit->first,0.5*enhance);
}
ShoKinPtr newKin2;
if(startingAnti<stoppingAnti) {
newKin2 = cit->second.first->
generateNextDecayBranching(startingAnti,stoppingAnti,minmass,
cit->second.second,
particle.id()!=cit->first,0.5*enhance);
}
// 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.first->
generateNextDecayBranching(startingScale,stoppingScale,minmass,cit->second.second,
particle.id()!=cit->first,enhance);
}
}
}
// shouldn't be anything else
else
assert(false);
if(!newKin) continue;
// select highest scale
if(newKin->scale() < newQ ) {
newQ = newKin->scale();
ids = cit->second.second;
kinematics=newKin;
sudakov=cit->second.first;
partnerType = type;
}
}
// return empty branching if nothing happened
if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),
ShowerPartnerType::Undefined);
// initialize the branching
kinematics->initialize(particle,PPtr());
// and generate phi
kinematics->phi(sudakov->generatePhiDecay(particle,ids,kinematics));
// and return it
return Branching(kinematics, ids,sudakov,partnerType);
}
Branching SplittingGenerator::
chooseBackwardBranching(ShowerParticle &particle,PPtr beamparticle,
double enhance,
Ptr<BeamParticleData>::transient_const_pointer beam,
ShowerInteraction::Type type,
tcPDFPtr pdf, Energy freeze) const {
Energy newQ=ZERO;
ShoKinPtr kinematics=ShoKinPtr();
ShowerPartnerType::Type 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(type != cit->second.first->interactionType() &&
type != ShowerInteraction::Both ) continue;
// setup the PDF
cit->second.first->setPDF(pdf,freeze);
// whether or not this interaction should be angular ordered
bool angularOrdered = cit->second.first->splittingFn()->angularOrdered();
ShoKinPtr newKin;
ShowerPartnerType::Type type;
if(cit->second.first->interactionType()==ShowerInteraction::QED) {
type = ShowerPartnerType::QED;
Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO;
newKin=cit->second.first->
generateNextSpaceBranching(startingScale,cit->second.second, particle.x(),
particle.id()!=cit->first,enhance,beam);
}
else if(cit->second.first->interactionType()==ShowerInteraction::QCD) {
// special for octets
if(particle.dataPtr()->iColour()==PDT::Colour8) {
// octet -> octet octet
if(cit->second.first->splittingFn()->colourStructure()==OctetOctetOctet) {
type = ShowerPartnerType::QCDColourLine;
Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO;
newKin = cit->second.first->
generateNextSpaceBranching(startingScale,cit->second.second, particle.x(),
particle.id()!=cit->first,0.5*enhance,beam);
startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO;
ShoKinPtr newKin2 = cit->second.first->
generateNextSpaceBranching(startingScale,cit->second.second, particle.x(),
particle.id()!=cit->first,0.5*enhance,beam);
// 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.first->
generateNextSpaceBranching(startingScale,cit->second.second, particle.x(),
particle.id()!=cit->first,enhance,beam);
}
}
// 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.first->
generateNextSpaceBranching(startingScale,cit->second.second, particle.x(),
particle.id()!=cit->first,enhance,beam);
}
}
// 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 = cit->second.second;
sudakov=cit->second.first;
partnerType = type;
}
}
// return empty branching if nothing happened
if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),
ShowerPartnerType::Undefined);
// initialize the ShowerKinematics
// and return it
kinematics->initialize(particle,beamparticle);
// and generate phi
kinematics->phi(sudakov->generatePhiBackward(particle,ids,kinematics));
// 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).first=trans.translate((cit->second).first);}
for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit)
{(cit->second).first=trans.translate((cit->second).first);}
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).first);}
for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit)
{ret.push_back((cit->second).first);}
return ret;
}
void SplittingGenerator::factorizationScaleFactor(double f) {
BranchingList::iterator cit;
for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit)
{(cit->second).first->factorizationScaleFactor(f);}
for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit)
{(cit->second).first->factorizationScaleFactor(f);}
}
void SplittingGenerator::renormalizationScaleFactor(double f) {
BranchingList::iterator cit;
for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit)
{(cit->second).first->renormalizationScaleFactor(f);}
for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit)
{(cit->second).first->renormalizationScaleFactor(f);}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 19, 2:56 PM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3797742
Default Alt Text
(406 KB)

Event Timeline