Page MenuHomeHEPForge

No OneTemporary

diff --git a/Hadronization/MatrixElementClusterFissioner.cc b/Hadronization/MatrixElementClusterFissioner.cc
--- a/Hadronization/MatrixElementClusterFissioner.cc
+++ b/Hadronization/MatrixElementClusterFissioner.cc
@@ -1,2078 +1,2086 @@
// -*- C++ -*-
//
// MatrixElementClusterFissioner.cc is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2019 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
//
// Thisk is the implementation of the non-inlined, non-templated member
// functions of the MatrixElementClusterFissioner class.
//
#include "MatrixElementClusterFissioner.h"
#include <ThePEG/Interface/ClassDocumentation.h>
#include <ThePEG/Interface/Reference.h>
#include <ThePEG/Interface/Parameter.h>
#include <ThePEG/Interface/Switch.h>
#include <ThePEG/Persistency/PersistentOStream.h>
#include <ThePEG/Persistency/PersistentIStream.h>
#include <ThePEG/PDT/EnumParticles.h>
#include "Herwig/Utilities/Kinematics.h"
#include "Cluster.h"
#include "ThePEG/Repository/UseRandom.h"
#include "ThePEG/Repository/EventGenerator.h"
#include <ThePEG/Utilities/DescribeClass.h>
#include "ThePEG/Interface/ParMap.h"
#include "Herwig/Utilities/AlphaS.h"
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <cassert>
#include <vector>
using namespace Herwig;
DescribeClass<MatrixElementClusterFissioner,ClusterFissioner>
describeMatrixElementClusterFissioner("Herwig::MatrixElementClusterFissioner","Herwig.so");
// Initialize counters
unsigned int MatrixElementClusterFissioner::_counterMaxLoopViolations=0;
unsigned int MatrixElementClusterFissioner::_counterPaccGreater1=0;
unsigned int MatrixElementClusterFissioner::_counterFissionMatrixElement=0;
MatrixElementClusterFissioner::MatrixElementClusterFissioner() :
_allowHadronFinalStates(2),
_massSampler(0),
_phaseSpaceSamplerCluster(0),
_phaseSpaceSamplerConstituent(0),
_matrixElement(0),
_fissionApproach(0),
_powerLawPower(0.0),
_maxLoopFissionMatrixElement(5000000),
_safetyFactorMatrixElement(10.0),
_epsilonResolution(1.0),
_failModeMaxLoopMatrixElement(0),
_writeOut(0)
{}
MatrixElementClusterFissioner::~MatrixElementClusterFissioner(){
if (_counterMaxLoopViolations){
std::cout << "WARNING: There have been "
<< _counterMaxLoopViolations
<< "/" << _counterFissionMatrixElement
<< " Maximum tries violations during the Simulation! ("
<< 100.0*double(_counterMaxLoopViolations)/double(_counterFissionMatrixElement)
<< " %)\n"
<< "You may want to reduce MatrixElementClusterFissioner:SafetyFactorOverEst (=>potentially Pacc>=1) "
<< "and/or increase MatrixElementClusterFissioner:MaxLoopMatrixElement (=>slower performance)\n";
}
if (_counterPaccGreater1){
std::cout << "WARNING: There have been "
<< _counterPaccGreater1
<< "/" << _counterFissionMatrixElement
<< " Pacc>=1 exceptions during the Simulation! ("
<< 100.0*double(_counterPaccGreater1)/double(_counterFissionMatrixElement)
<< " %)\n"
<< "You may want to increase MatrixElementClusterFissioner:SafetyFactorOverEst to reduce this "
<< "\nNOTE: look at the log file and look for the larges Pacc accepted and multiply "
<< "\n MatrixElementClusterFissioner:SafetyFactorOverEst by this factor";
}
}
IBPtr MatrixElementClusterFissioner::clone() const {
return new_ptr(*this);
}
IBPtr MatrixElementClusterFissioner::fullclone() const {
return new_ptr(*this);
}
void MatrixElementClusterFissioner::persistentOutput(PersistentOStream & os) const {
os << _allowHadronFinalStates
<< _massSampler
<< _phaseSpaceSamplerCluster
<< _phaseSpaceSamplerConstituent
<< _matrixElement
<< _fissionApproach
<< _powerLawPower
<< _maxLoopFissionMatrixElement
<< _safetyFactorMatrixElement
<< _epsilonResolution
<< _failModeMaxLoopMatrixElement
<< _writeOut
;
}
void MatrixElementClusterFissioner::persistentInput(PersistentIStream & is, int) {
is >> _allowHadronFinalStates
>> _massSampler
>> _phaseSpaceSamplerCluster
>> _phaseSpaceSamplerConstituent
>> _matrixElement
>> _fissionApproach
>> _powerLawPower
>> _maxLoopFissionMatrixElement
>> _safetyFactorMatrixElement
>> _epsilonResolution
>> _failModeMaxLoopMatrixElement
>> _writeOut
;
}
/*
namespace{
void printV(Lorentz5Momentum p) {
std::cout << "("<<p.e()/GeV<<"|"<<p.vect().x()/GeV<<","<<p.vect().y()/GeV<<","<<p.vect().z()/GeV<<") Mass = "<<p.mass()/GeV<<" m = "<<p.m()/GeV<<"\n";
}
}
*/
void MatrixElementClusterFissioner::doinit() {
ClusterFissioner::doinit();
// TODO: Some User warnings/errors but not complete list
if (_matrixElement!=0 && _fissionApproach==0) generator()->logWarning( Exception(
"For non-trivial MatrixElement you need to enable FissionApproach=New or Hybrid\n",
Exception::warning));
}
void MatrixElementClusterFissioner::Init() {
+ // TODO test for what can be copied
+ // std::cout << "sizeof Cluster " << sizeof(Cluster) << std::endl;
+ // std::cout << "sizeof Axis " << sizeof(Axis) << std::endl;
+ // std::cout << "sizeof Axis & " << sizeof(Axis&) << std::endl;
+ // std::cout << "sizeof Axis * " << sizeof(Axis*) << std::endl;
+ // std::cout << "sizeof energy " << sizeof(Energy) << std::endl;
+ // std::cout << "sizeof energy2 " << sizeof(Energy2) << std::endl;
+ // std::cout << "sizeof bool " << sizeof(bool) << std::endl;
+ // std::cout << "sizeof energy & " << sizeof(Energy&) << std::endl;
+ // std::cout << "sizeof energy * " << sizeof(Energy*) << std::endl;
static ClassDocumentation<MatrixElementClusterFissioner> documentation
("Class responsibles for chopping up the clusters");
static Switch<MatrixElementClusterFissioner,int> interfaceFissionApproach
("FissionApproach",
"Option for different Cluster Fission approaches",
&MatrixElementClusterFissioner::_fissionApproach, 0, false, false);
static SwitchOption interfaceFissionApproachDefault
(interfaceFissionApproach,
"Default",
"Default Herwig-7.3.0 cluster fission without restructuring",
0);
static SwitchOption interfaceFissionApproachNew
(interfaceFissionApproach,
"New",
"New cluster fission which allows to choose MassSampler"
", PhaseSpaceSampler and MatrixElement",
1);
static SwitchOption interfaceFissionApproachHybrid
(interfaceFissionApproach,
"Hybrid",
"New cluster fission which allows to choose MassSampler"
", PhaseSpaceSampler and MatrixElement, but uses Default"
" Approach for BeamClusters",
2);
static SwitchOption interfaceFissionApproachPreservePert
(interfaceFissionApproach,
"PreservePert",
"New cluster fission which allows to choose MassSampler"
", PhaseSpaceSampler and MatrixElement, but uses Default"
" Approach for BeamClusters",
3);
static SwitchOption interfaceFissionApproachPreserveNonPert
(interfaceFissionApproach,
"PreserveNonPert",
"New cluster fission which allows to choose MassSampler"
", PhaseSpaceSampler and MatrixElement, but uses Default"
" Approach for BeamClusters",
4);
static SwitchOption interfaceFissionApproachPreserveFirstPert
(interfaceFissionApproach,
"PreserveFirstPert",
"New cluster fission which allows to choose MassSampler"
", PhaseSpaceSampler and MatrixElement, but uses Default"
" Approach for BeamClusters",
5);
// Switch C->H1,C2 C->H1,H2 on or off
static Switch<MatrixElementClusterFissioner,int> interfaceAllowHadronFinalStates
("AllowHadronFinalStates",
"Option for allowing hadron final states of cluster fission",
&MatrixElementClusterFissioner::_allowHadronFinalStates, 0, false, false);
static SwitchOption interfaceAllowHadronFinalStatesNone
(interfaceAllowHadronFinalStates,
"None",
"Option for disabling hadron final states of cluster fission",
0);
static SwitchOption interfaceAllowHadronFinalStatesSemiHadronicOnly
(interfaceAllowHadronFinalStates,
"SemiHadronicOnly",
"Option for allowing hadron final states of cluster fission of type C->H1,C2 "
"(NOT YET USABLE WITH MatrixElement only use option None)",
1);
static SwitchOption interfaceAllowHadronFinalStatesAll
(interfaceAllowHadronFinalStates,
"All",
"Option for allowing hadron final states of cluster fission "
"of type C->H1,C2 or C->H1,H2 "
"(NOT YET USABLE WITH MatrixElement only use option None)",
2);
// Mass Sampler Switch
static Switch<MatrixElementClusterFissioner,int> interfaceMassSampler
("MassSampler",
"Option for different Mass sampling options",
&MatrixElementClusterFissioner::_massSampler, 0, false, false);
static SwitchOption interfaceMassSamplerDefault
(interfaceMassSampler,
"Default",
"Choose H7.2.3 default mass sampling using PSplitX",
0);
static SwitchOption interfaceMassSamplerUniform
(interfaceMassSampler,
"Uniform",
"Choose Uniform Mass sampling in M1,M2 space",
1);
static SwitchOption interfaceMassSamplerFlatPhaseSpace
(interfaceMassSampler,
"FlatPhaseSpace",
"Choose Flat Phase Space sampling of Mass in M1,M2 space (Recommended)",
2);
static SwitchOption interfaceMassSamplerPhaseSpacePowerLaw
(interfaceMassSampler,
"PhaseSpacePowerLaw",
"Choose Phase Space times a power law sampling of Mass in M1,M2 space.",
3);
static Parameter<MatrixElementClusterFissioner,double>
interfaceMassPowerLaw("MassPowerLaw",
"power of mass power law modulation of FlatPhaseSpace",
&MatrixElementClusterFissioner::_powerLawPower, 0.0, -10.0, 0.0, 10.0,
false,false,false);
// Phase Space Sampler Switch
static Switch<MatrixElementClusterFissioner,int> interfacePhaseSpaceSamplerCluster
("PhaseSpaceSamplerCluster",
"Option for different phase space sampling options",
&MatrixElementClusterFissioner::_phaseSpaceSamplerCluster, 0, false, false);
static SwitchOption interfacePhaseSpaceSamplerClusterAligned
(interfacePhaseSpaceSamplerCluster,
"Aligned",
"Draw the momentum of child clusters to be aligned"
" the relative momentum of the mother cluster",
0);
static SwitchOption interfacePhaseSpaceSamplerClusterIsotropic
(interfacePhaseSpaceSamplerCluster,
"Isotropic",
"Draw the momentum of child clusters to be isotropic"
" the relative momentum of the mother cluster",
1);
static SwitchOption interfacePhaseSpaceSamplerClusterTchannel
(interfacePhaseSpaceSamplerCluster,
"Tchannel",
"Draw the momentum of child clusters to be t-channel like"
" the relative momentum of the mother cluster"
" i.e. cosTheta ~ 1/(1+A-cosTheta)^2",
2);
static Switch<MatrixElementClusterFissioner,int> interfacePhaseSpaceSamplerConstituents
("PhaseSpaceSamplerConstituents",
"Option for different phase space sampling options",
&MatrixElementClusterFissioner::_phaseSpaceSamplerConstituent, 0, false, false);
static SwitchOption interfacePhaseSpaceSamplerConstituentsAligned
(interfacePhaseSpaceSamplerConstituents,
"Aligned",
"Draw the momentum of the constituents of the child clusters "
"to be aligned relative to the direction of the child cluster",
0);
static SwitchOption interfacePhaseSpaceSamplerConstituentsIsotropic
(interfacePhaseSpaceSamplerConstituents,
"Isotropic",
"Draw the momentum of the constituents of the child clusters "
"to be isotropic relative to the direction of the child cluster",
1);
static SwitchOption interfacePhaseSpaceSamplerConstituentsTchannel
(interfacePhaseSpaceSamplerConstituents,
"Exponential",
"Draw the momentum of the constituents of the child clusters "
"to be exponential relative to the direction of the child cluster"
" i.e. cosTheta ~ exp(lam*(cosTheta-1)",
2);
// Matrix Element Choice Switch
static Switch<MatrixElementClusterFissioner,int> interfaceMatrixElement
("MatrixElement",
"Option for different Matrix Element options",
&MatrixElementClusterFissioner::_matrixElement, 0, false, false);
static SwitchOption interfaceMatrixElementDefault
(interfaceMatrixElement,
"Default",
"Choose trivial matrix element i.e. whatever comes from the mass and "
"phase space sampling",
0);
static SwitchOption interfaceMatrixElementSoftQQbarFinalFinal
(interfaceMatrixElement,
"SoftQQbarFinalFinal",
"Choose Soft p1,p2->q1,q2,g*->q1,q2,q,qbar matrix element"
"NOTE: Here the matrix element depends on qi.q(bar)",
1);
static SwitchOption interfaceMatrixElementSoftQQbarInitialFinal
(interfaceMatrixElement,
"SoftQQbarInitialFinal",
"Choose Soft p1,p2->q1,q2,g*->q1,q2,q,qbar matrix element "
"NOTE: Here the matrix element depends on pi.q(bar)",
2);
static SwitchOption interfaceMatrixElementTest
(interfaceMatrixElement,
"Test",
"Choose Soft p1,p2->q1,q2,g*->q1,q2,q,qbar matrix element "
"NOTE: Here the matrix element depends on pi.q(bar)",
4);
static SwitchOption interfaceMatrixElementSoftQQbarInitialFinalTchannel
(interfaceMatrixElement,
"SoftQQbarInitialFinalTchannel",
"Choose Soft p1,p2->q1,q2,g*->q1,q2,q,qbar matrix element "
"NOTE: Here the matrix element depends on pi.q(bar)",
5);
// Technical Max loop parameter for New ClusterFission approach and Matrix Element
// Rejection sampling
static Parameter<MatrixElementClusterFissioner,int> interfaceMaxLoopMatrixElement
("MaxLoopMatrixElement",
"Technical Parameter for how many tries are allowed to sample the "
"Cluster Fission matrix element before reverting to fissioning "
"using the default Fission Aproach",
&MatrixElementClusterFissioner::_maxLoopFissionMatrixElement, 5000000, 100, 1e8,
false, false, Interface::limited);
static Switch<MatrixElementClusterFissioner,int> interfaceFailModeMaxLoopMatrixElement
("FailModeMaxLoopMatrixElement",
"How to fail if we try more often than MaxLoopMatrixElement",
&MatrixElementClusterFissioner::_failModeMaxLoopMatrixElement, 0, false, false);
static SwitchOption interfaceDiquarkClusterFissionOldFission
(interfaceFailModeMaxLoopMatrixElement,
"OldFission",
"Use old Cluster Fission Aproach if we try more often than MaxLoopMatrixElement",
0);
static SwitchOption interfaceDiquarkClusterFissionRejectEvent
(interfaceFailModeMaxLoopMatrixElement,
"RejectEvent",
"Reject Event if we try more often than MaxLoopMatrixElement",
1);
static Switch<MatrixElementClusterFissioner,int> interfaceDiquarkClusterFission
("DiquarkClusterFission",
"Allow clusters to fission to 1 or 2 diquark Clusters or Turn off diquark fission completely",
&MatrixElementClusterFissioner::_diquarkClusterFission, 0, false, false);
static SwitchOption interfaceDiquarkClusterFissionAll
(interfaceDiquarkClusterFission,
"All",
"Allow diquark clusters and baryon clusters to fission to new diquark Clusters",
2);
static SwitchOption interfaceDiquarkClusterFissionOnlyBaryonClusters
(interfaceDiquarkClusterFission,
"OnlyBaryonClusters",
"Allow only baryon clusters to fission to new diquark Clusters",
1);
static SwitchOption interfaceDiquarkClusterFissionNo
(interfaceDiquarkClusterFission,
"No",
"Don't allow clusters to fission to new diquark Clusters",
0);
static SwitchOption interfaceDiquarkClusterFissionOff
(interfaceDiquarkClusterFission,
"Off",
"Don't allow clusters fission to draw diquarks ",
-1);
// Matrix Element Choice Switch
static Parameter<MatrixElementClusterFissioner,double>
interfaceSafetyFactorOverEst("SafetyFactorOverEst","Safety factor with which the numerical overestimate is calculated",
&MatrixElementClusterFissioner::_safetyFactorMatrixElement, 0, 10.0, 1.0, 1000.0,false,false,false);
// Matrix Element IR cutoff
static Parameter<MatrixElementClusterFissioner,double>
interfaceMatrixElementIRCutOff("MatrixElementResolutionCutOff",
"Resolution CutOff for MatrixElement t-channel with the Coloumb divergence. "
"for MatrixElement SoftQQbarInitialFinalTchannel e.g. such that 1/(t^2)->1/((t-_epsilonResolution*mGluonConst^2)^2)",
&MatrixElementClusterFissioner::_epsilonResolution, 0, 0.01, 1e-6, 1000.0,false,false,false);
// Matrix Element Choice Switch
static Switch<MatrixElementClusterFissioner,int> interfaceWriteOut
("WriteOut",
"Option for different Matrix Element options",
&MatrixElementClusterFissioner::_writeOut, 0, false, false);
static SwitchOption interfaceWriteOutNo
(interfaceWriteOut,
"No",
"Choose trivial matrix element i.e. whatever comes from the mass and "
"phase space sampling",
0);
static SwitchOption interfaceWriteOutYes
(interfaceWriteOut,
"Yes",
"Choose Soft q1,q2->q1,q2,g*->q1,q2,q,qbar matrix element",
1);
}
tPVector MatrixElementClusterFissioner::fission(ClusterVector & clusters, bool softUEisOn) {
// return if no clusters
if (clusters.empty()) return tPVector();
/*****************
* Loop over the (input) collection of cluster pointers, and store in
* the vector splitClusters all the clusters that need to be split
* (these are beam clusters, if soft underlying event is off, and
* heavy non-beam clusters).
********************/
stack<ClusterPtr> splitClusters;
for(ClusterVector::iterator it = clusters.begin() ;
it != clusters.end() ; ++it) {
/**************
* Skip 3-component clusters that have been redefined (as 2-component
* clusters) or not available clusters. The latter check is indeed
* redundant now, but it is used for possible future extensions in which,
* for some reasons, some of the clusters found by ClusterFinder are tagged
* straight away as not available.
**************/
if((*it)->isRedefined() || !(*it)->isAvailable()) continue;
// if the cluster is a beam cluster add it to the vector of clusters
// to be split or if it is heavy
if((*it)->isBeamCluster() || isHeavy(*it)) splitClusters.push(*it);
}
tPVector finalhadrons;
cut(splitClusters, clusters, finalhadrons, softUEisOn);
return finalhadrons;
}
void MatrixElementClusterFissioner::cut(stack<ClusterPtr> & clusterStack,
ClusterVector &clusters, tPVector & finalhadrons,
bool softUEisOn) {
/**************************************************
* This method does the splitting of the cluster pointed by cluPtr
* and "recursively" by all of its cluster children, if heavy. All of these
* new children clusters are added (indeed the pointers to them) to the
* collection of cluster pointers collecCluPtr. The method works as follows.
* Initially the vector vecCluPtr contains just the input pointer to the
* cluster to be split. Then it will be filled "recursively" by all
* of the cluster's children that are heavy enough to require, in their turn,
* to be split. In each loop, the last element of the vector vecCluPtr is
* considered (only once because it is then removed from the vector).
* This approach is conceptually recursive, but avoid the overhead of
* a concrete recursive function. Furthermore it requires minimal changes
* in the case that the fission of an heavy cluster could produce more
* than two cluster children as assumed now.
*
* Draw the masses: for normal, non-beam clusters a power-like mass dist
* is used, whereas for beam clusters a fast-decreasing exponential mass
* dist is used instead (to avoid many iterative splitting which could
* produce an unphysical large transverse energy from a supposed soft beam
* remnant process).
****************************************/
// Here we recursively loop over clusters in the stack and cut them
while (!clusterStack.empty()) {
// take the last element of the vector
ClusterPtr iCluster = clusterStack.top(); clusterStack.pop();
// split it
cutType ct = iCluster->numComponents() == 2 ?
cutTwo(iCluster, finalhadrons, softUEisOn) :
cutThree(iCluster, finalhadrons, softUEisOn);
// There are cases when we don't want to split, even if it fails mass test
if(!ct.first.first || !ct.second.first) {
// if an unsplit beam cluster leave if for the underlying event
if(iCluster->isBeamCluster() && softUEisOn)
iCluster->isAvailable(false);
continue;
}
// check if clusters
ClusterPtr one = dynamic_ptr_cast<ClusterPtr>(ct.first.first);
ClusterPtr two = dynamic_ptr_cast<ClusterPtr>(ct.second.first);
// is a beam cluster must be split into two clusters
if(iCluster->isBeamCluster() && (!one||!two) && softUEisOn) {
iCluster->isAvailable(false);
continue;
}
// There should always be a intermediate quark(s) from the splitting
assert(ct.first.second && ct.second.second);
/// \todo sort out motherless quark pairs here. Watch out for 'quark in final state' errors
iCluster->addChild(ct.first.first);
// iCluster->addChild(ct.first.second);
// ct.first.second->addChild(ct.first.first);
iCluster->addChild(ct.second.first);
// iCluster->addChild(ct.second.second);
// ct.second.second->addChild(ct.second.first);
// Sometimes the clusters decay C -> H + C' or C -> H + H' rather then C -> C' + C''
if(one) {
clusters.push_back(one);
if(one->isBeamCluster() && softUEisOn)
one->isAvailable(false);
if(isHeavy(one) && one->isAvailable())
clusterStack.push(one);
}
if(two) {
clusters.push_back(two);
if(two->isBeamCluster() && softUEisOn)
two->isAvailable(false);
if(isHeavy(two) && two->isAvailable())
clusterStack.push(two);
}
}
}
MatrixElementClusterFissioner::cutType
MatrixElementClusterFissioner::cutTwo(ClusterPtr & cluster, tPVector & finalhadrons,
bool softUEisOn) {
switch (_fissionApproach)
{
case 0:
return ClusterFissioner::cutTwo(cluster, finalhadrons, softUEisOn);
break;
case 1:
return cutTwoMatrixElement(cluster, finalhadrons, softUEisOn);
break;
case 2:
if (cluster->isBeamCluster()) {
return ClusterFissioner::cutTwo(cluster, finalhadrons, softUEisOn);
}
else {
return cutTwoMatrixElement(cluster, finalhadrons, softUEisOn);
}
break;
case 3:
{
bool isPert=false;
for (unsigned int i = 0; i < cluster->numComponents(); i++)
{
if (cluster->isPerturbative(i))
isPert=true;
}
if (isPert)
return ClusterFissioner::cutTwo(cluster, finalhadrons, softUEisOn);
else
return cutTwoMatrixElement(cluster, finalhadrons, softUEisOn);
break;
}
case 4:
{
bool isPert=false;
for (unsigned int i = 0; i < cluster->numComponents(); i++)
{
if (cluster->isPerturbative(i))
isPert=true;
}
if (!isPert)
return ClusterFissioner::cutTwo(cluster, finalhadrons, softUEisOn);
else
return cutTwoMatrixElement(cluster, finalhadrons, softUEisOn);
break;
}
case 5:
{
bool isPert=true;
for (unsigned int i = 0; i < cluster->numComponents(); i++)
{
if (!cluster->isPerturbative(i)) {
isPert=false;
break;
}
}
if (isPert)
return ClusterFissioner::cutTwo(cluster, finalhadrons, softUEisOn);
else
return cutTwoMatrixElement(cluster, finalhadrons, softUEisOn);
break;
}
default:
assert(false);
}
}
namespace {
int areNotSame(const Lorentz5Momentum & p1,const Lorentz5Momentum & p2){
double tol=1e-5;
if (abs(p1.vect().x()-p2.vect().x())>tol*GeV){
std::cout << "disagreeing x " <<std::setprecision(-log10(tol)+2) << abs(p1.vect().x()-p2.vect().x())/GeV<< std::endl;
return 1;
}
if (abs(p1.vect().y()-p2.vect().y())>tol*GeV){
std::cout << "disagreeing y " <<std::setprecision(-log10(tol)+2)<< abs(p1.vect().y()-p2.vect().y())/GeV<< std::endl;
return 2;
}
if (abs(p1.vect().z()-p2.vect().z())>tol*GeV){
std::cout << "disagreeing z " <<std::setprecision(-log10(tol)+2)<< abs(p1.vect().z()-p2.vect().z())/GeV<< std::endl;
return 3;
}
if (abs(p1.e()-p2.e())>tol*GeV){
std::cout << "disagreeing e " <<std::setprecision(-log10(tol)+2)<< abs(p1.e()-p2.e())/GeV<< std::endl;
return 4;
}
if (abs(p1.m()-p2.m())>tol*GeV){
std::cout << "disagreeing m " <<std::setprecision(-log10(tol)+2)<< abs(p1.m()-p2.m())/GeV<< std::endl;
return 4;
}
if (abs(p1.m()-p1.mass())>tol*GeV){
std::cout << "disagreeing p1 m - mass " <<std::setprecision(-log10(tol)+2)<< abs(p1.m()-p1.mass())/GeV<< std::endl;
return 4;
}
if (abs(p2.m()-p2.mass())>tol*GeV){
std::cout << "disagreeing p2 m - mass " <<std::setprecision(-log10(tol)+2)<< abs(p2.m()-p2.mass())/GeV<< std::endl;
return 4;
}
return 0;
}
}
MatrixElementClusterFissioner::cutType
MatrixElementClusterFissioner::cutTwoMatrixElement(ClusterPtr & cluster, tPVector & finalhadrons,
bool softUEisOn) {
// need to make sure only 2-cpt clusters get here
assert(cluster->numComponents() == 2);
tPPtr ptrQ1 = cluster->particle(0);
tPPtr ptrQ2 = cluster->particle(1);
Energy Mc = cluster->mass();
// TODO BEGIN Changed comp to default
if ( Mc < spectrum()->massLightestHadronPair(ptrQ1->dataPtr(),ptrQ2->dataPtr())) {
static const PPtr null = PPtr();
return cutType(PPair(null,null),PPair(null,null));
}
// TODO END Changed comp to default
assert(ptrQ1);
assert(ptrQ2);
// And check if those particles are from a beam remnant
bool rem1 = cluster->isBeamRemnant(0);
bool rem2 = cluster->isBeamRemnant(1);
// workout which distribution to use
bool soft1(false),soft2(false);
switch (_iopRem) {
case 0:
soft1 = rem1 || rem2;
soft2 = rem2 || rem1;
break;
case 1:
soft1 = rem1;
soft2 = rem2;
break;
}
// Initialization for the exponential ("soft") mass distribution.
int counter_MEtry = 0;
Energy Mc1 = ZERO;
Energy Mc2 = ZERO;
Energy m = ZERO;
Energy m1 = ptrQ1->data().constituentMass();
Energy m2 = ptrQ2->data().constituentMass();
Energy mMin = getParticleData(ParticleID::d)->constituentMass();
// Minimal threshold for non-zero Mass PhaseSpace
if ( Mc < (m1 + m2 + 2*mMin )) {
static const PPtr null = PPtr();
return cutType(PPair(null,null),PPair(null,null));
}
tcPDPtr toHadron1, toHadron2;
PPtr newPtr1 = PPtr ();
PPtr newPtr2 = PPtr ();
Lorentz5Momentum pClu1, pClu2, pQ1, pQone, pQtwo, pQ2;
Lorentz5Momentum pClu = cluster->momentum(); // known
const Lorentz5Momentum p0Q1 = ptrQ1->momentum(); // known (mom Q1 before fission)
const Lorentz5Momentum p0Q2 = ptrQ2->momentum(); // known (mom Q2 before fission)
// where to return to in case of rejected sample
enum returnTo {
FlavourSampling,
MassSampling,
PhaseSpaceSampling,
MatrixElementSampling,
Done
};
// start with FlavourSampling
returnTo retTo=FlavourSampling;
int letFissionToXHadrons = _allowHadronFinalStates;
// if a beam cluster not allowed to decay to hadrons
if (cluster->isBeamCluster() && softUEisOn) letFissionToXHadrons = 0;
// ### Flavour, Mass, PhaseSpace and MatrixElement Sampling loop until accepted: ###
bool escape = false;
double weightMasses,weightPhaseSpaceAngles;
+ // TODO make this better
+ // TODO make this independent of explicit u/d quark
+ Energy mLightestQuark = getParticleData(ThePEG::ParticleID::u)->constituentMass();
+ if (mLightestQuark>getParticleData(ThePEG::ParticleID::d)->constituentMass())
+ mLightestQuark = getParticleData(ThePEG::ParticleID::d)->constituentMass();
do
{
switch (retTo)
{
case FlavourSampling:
{
// ## Flavour sampling and kinematic constraints ##
drawNewFlavour(newPtr1,newPtr2,cluster);
// get a flavour for the qqbar pair
// check for right ordering
assert (ptrQ2);
assert (newPtr2);
assert (ptrQ2->dataPtr());
assert (newPtr2->dataPtr());
// careful if DiquarkClusters can exist
bool Q1diq = DiquarkMatcher::Check(ptrQ1->id());
bool Q2diq = DiquarkMatcher::Check(ptrQ2->id());
bool newQ1diq = DiquarkMatcher::Check(newPtr1->id());
bool newQ2diq = DiquarkMatcher::Check(newPtr2->id());
bool diqClu1 = Q1diq && newQ1diq;
bool diqClu2 = Q2diq && newQ2diq;
// DEBUG only:
// std::cout << "Make Clusters: ( " << ptrQ1->PDGName() << " " << newPtr1->PDGName() << " ), ( "
// << ptrQ2->PDGName() << " " << newPtr2->PDGName() << " )\n";
// check if Hadron formation is possible
if (!( diqClu1 || diqClu2 )
&& (cantMakeHadron(ptrQ1, newPtr1) || cantMakeHadron(ptrQ2, newPtr2))) {
swap(newPtr1, newPtr2);
// check again
if(cantMakeHadron(ptrQ1, newPtr1) || cantMakeHadron(ptrQ2, newPtr2)) {
throw Exception()
<< "MatrixElementClusterFissioner cannot split the cluster ("
<< ptrQ1->PDGName() << ' ' << ptrQ2->PDGName()
<< ") into hadrons.\n"
<< "drawn Flavour: "<< newPtr1->PDGName()<<"\n"<< Exception::runerror;
}
}
else if ( diqClu1 || diqClu2 ){
bool swapped=false;
if ( !diqClu1 && cantMakeHadron(ptrQ1,newPtr1) ) {
swap(newPtr1, newPtr2);
swapped=true;
}
if ( !diqClu2 && cantMakeHadron(ptrQ2,newPtr2) ) {
assert(!swapped);
swap(newPtr1, newPtr2);
}
if ( diqClu2 && diqClu1 && ptrQ1->id()*newPtr1->id()>0 ) {
assert(!swapped);
swap(newPtr1, newPtr2);
}
if (!diqClu1) assert(!cantMakeHadron(ptrQ1,newPtr1));
if (!diqClu2) assert(!cantMakeHadron(ptrQ2,newPtr2));
}
// Check that new clusters can produce particles and there is enough
// phase space to choose the drawn flavour
m = newPtr1->data().constituentMass();
// Do not split in the case there is no phase space available + permille security
double eps=0.1;
if(Mc < (1+eps)*(m1 + m + m2 + m)) {
retTo = FlavourSampling;
// escape if no flavour phase space possibile without fission
if (fabs((m - mMin)/GeV) < 1e-3) {
escape = true;
retTo = Done;
}
continue;
}
pQ1.setMass(m1);
pQone.setMass(m);
pQtwo.setMass(m);
pQ2.setMass(m2);
// Determined the (5-components) momenta (all in the LAB frame)
// p0Q1.setMass(ptrQ1->mass()); // known (mom Q1 before fission)
// p0Q1.rescaleEnergy(); // TODO check if needed
// p0Q2.setMass(ptrQ2->mass()); // known (mom Q2 before fission)
// p0Q2.rescaleEnergy();// TODO check if needed
pClu.rescaleMass();
Energy MLHP1 = spectrum()->hadronPairThreshold(ptrQ1->dataPtr(),newPtr1->dataPtr());
Energy MLHP2 = spectrum()->hadronPairThreshold(ptrQ2->dataPtr(),newPtr2->dataPtr());
Energy MLH1 = spectrum()->lightestHadron(ptrQ1->dataPtr(),newPtr1->dataPtr())->mass();
Energy MLH2 = spectrum()->lightestHadron(ptrQ2->dataPtr(),newPtr2->dataPtr())->mass();
bool canBeSingleHadron1 = (m1 + m) < MLHP1;
bool canBeSingleHadron2 = (m2 + m) < MLHP2;
Energy mThresh1 = (m1 + m);
Energy mThresh2 = (m2 + m);
if (canBeSingleHadron1) mThresh1 = MLHP1;
if (canBeSingleHadron2) mThresh2 = MLHP2;
switch (letFissionToXHadrons)
{
case 0:
{
// Option None: only C->C1,C2 allowed
// check if mass phase space is non-zero
// resample or escape if only allowed mass phase space is for C->H1,H2 or C->H1,C2
if ( Mc < (mThresh1 + mThresh2)) {
// escape if not even the lightest flavour phase space is possibile
- // TODO make this independent of explicit u/d quark
- if (
- fabs((m - getParticleData(ThePEG::ParticleID::u)->constituentMass())/GeV) < 1e-3
- ||
- fabs((m - getParticleData(ThePEG::ParticleID::d)->constituentMass())/GeV) < 1e-3
- ) {
+ if ( fabs((m - mLightestQuark)/GeV) < 1e-3 ) {
escape = true;
retTo = Done;
continue;
}
else {
retTo = FlavourSampling;
continue;
}
}
break;
}
case 1:
{
// Option SemiHadronicOnly: C->H,C allowed
// NOTE: TODO implement matrix element for this
// resample or escape if only allowed mass phase space is for C->H1,H2
// First case is for ensuring the enough mass to be available and second one rejects disjoint mass regions
if ( ( (canBeSingleHadron1 && canBeSingleHadron2)
&& Mc < (mThresh1 + mThresh2) )
||
( (canBeSingleHadron1 || canBeSingleHadron2)
&& (canBeSingleHadron1 ? Mc-(m2+m) < MLH1:false || canBeSingleHadron2 ? Mc-(m1+m) < MLH2:false) )
){
// escape if not even the lightest flavour phase space is possibile
- // TODO make this independent of explicit u/d quark
- if (
- fabs((m - getParticleData(ThePEG::ParticleID::u)->constituentMass())/GeV) < 1e-3
- ||
- fabs((m - getParticleData(ThePEG::ParticleID::d)->constituentMass())/GeV) < 1e-3
- ) {
+ if (fabs((m - mLightestQuark)/GeV) < 1e-3 ) {
escape = true;
retTo = Done;
continue;
}
else {
retTo = FlavourSampling;
continue;
}
}
break;
}
case 2:
{
// Option All: C->H,C and C->H,H allowed
// NOTE: TODO implement matrix element for this
// Mass Phase space for all option can always be found if cluster massive enough to go
// to the lightest 2 hadrons
break;
}
default:
assert(false);
}
// Note: want to fallthrough (in C++17 one could uncomment
// the line below to show that this is intentional)
[[fallthrough]];
}
/*
* MassSampling choices:
* - Default (default)
* - Uniform
* - FlatPhaseSpace
* - SoftMEPheno
* */
case MassSampling:
{
weightMasses = drawNewMasses(Mc, soft1, soft2, pClu1, pClu2,
ptrQ1, pQ1, newPtr1, pQone,
newPtr2, pQtwo, ptrQ2, pQ2);
// TODO IF C->C1,C2 (and not C->C,H or H1,H2) masses sampled and is in PhaseSpace must push through
// because otherwise no matrix element
if(weightMasses==0.0) {
// TODO check which option is better
retTo = FlavourSampling;
// retTo = MassSampling;
continue;
}
// derive the masses of the children
Mc1 = pClu1.mass();
Mc2 = pClu2.mass();
// static kinematic threshold
if(_kinematicThresholdChoice != 1 )
{
// NOTE: that the squared thresholds below are
// numerically more stringent which is needed
// kaellen function calculation
if(sqr(Mc1) < sqr(m1+m) || sqr(Mc2) < sqr(m+m2) || sqr(Mc1+Mc2) > sqr(Mc)){
// TODO check which option is better
// retTo = FlavourSampling;
retTo = MassSampling;
continue;
}
// dynamic kinematic threshold
}
else if(_kinematicThresholdChoice == 1) {
bool C1 = ( sqr(Mc1) )/( sqr(m1) + sqr(m) + _kinThresholdShift ) < 1.0 ? true : false;
bool C2 = ( sqr(Mc2) )/( sqr(m2) + sqr(m) + _kinThresholdShift ) < 1.0 ? true : false;
bool C3 = ( sqr(Mc1) + sqr(Mc2) )/( sqr(Mc) ) > 1.0 ? true : false;
if( C1 || C2 || C3 ) {
// TODO check which option is better
// retTo = FlavourSampling;
retTo = MassSampling;
continue;
}
}
else
assert(false);
/**************************
* New (not present in Fortran Herwig):
* check whether the fragment masses Mc1 and Mc2 are above the
* threshold for the production of the lightest pair of hadrons with the
* right flavours. If not, then set by hand the mass to the lightest
* single hadron with the right flavours, in order to solve correctly
* the kinematics, and (later in this method) create directly such hadron
* and add it to the children hadrons of the cluster that undergoes the
* fission (i.e. the one pointed by iCluPtr). Notice that in this special
* case, the heavy cluster that undergoes the fission has one single
* cluster child and one single hadron child. We prefer this approach,
* rather than to create a light cluster, with the mass set equal to
* the lightest hadron, and let then the class LightClusterDecayer to do
* the job to decay it to that single hadron, for two reasons:
* First, because the sum of the masses of the two constituents can be,
* in this case, greater than the mass of that hadron, hence it would
* be impossible to solve the kinematics for such two components, and
* therefore we would have a cluster whose components are undefined.
* Second, the algorithm is faster, because it avoids the reshuffling
* procedure that would be necessary if we used LightClusterDecayer
* to decay the light cluster to the lightest hadron.
****************************/
// override chosen masses if needed
toHadron1 = spectrum()->chooseSingleHadron(ptrQ1->dataPtr(), newPtr1->dataPtr(),Mc1);
if ( letFissionToXHadrons == 0 && toHadron1 ) {
// reject mass samples which would force C->C,H or C->H1,H2 fission if desired
//
// Check if Mc1max < MLHP1, in which case we might need to choose a different flavour
// else resampling the masses should be sufficient
Energy MLHP1 = spectrum()->massLightestHadronPair(ptrQ1->dataPtr(), newPtr1->dataPtr());
Energy MLHP2 = spectrum()->massLightestHadronPair(ptrQ2->dataPtr(), newPtr2->dataPtr());
Energy Mc1max = (m2+m) > MLHP2 ? (Mc-(m2+m)):(Mc-MLHP2);
// for avoiding inf loops set min threshold
if ( Mc1max - MLHP1 < 1e-2*GeV ) {
retTo = FlavourSampling;
}
else {
retTo = MassSampling;
}
continue;
}
if(toHadron1) {
Mc1 = toHadron1->mass();
pClu1.setMass(Mc1);
}
toHadron2 = spectrum()->chooseSingleHadron(ptrQ2->dataPtr(), newPtr2->dataPtr(),Mc2);
if ( letFissionToXHadrons == 0 && toHadron2 ) {
// reject mass samples which would force C->C,H or C->H1,H2 fission if desired
//
// Check if Mc2max < MLHP2, in which case we might need to choose a different flavour
// else resampling the masses should be sufficient
Energy MLHP1 = spectrum()->massLightestHadronPair(ptrQ1->dataPtr(), newPtr1->dataPtr());
Energy MLHP2 = spectrum()->massLightestHadronPair(ptrQ2->dataPtr(), newPtr2->dataPtr());
Energy Mc2max = (m1+m) > MLHP1 ? (Mc-(m1+m)):(Mc-MLHP1);
// for avoiding inf loops set min threshold
if ( Mc2max - MLHP2 < 1e-2*GeV ) {
retTo = FlavourSampling;
}
else {
retTo = MassSampling;
}
continue;
}
if(toHadron2) {
Mc2 = toHadron2->mass();
pClu2.setMass(Mc2);
}
if (letFissionToXHadrons == 1 && (toHadron1 && toHadron2) ) {
// reject mass samples which would force C->H1,H2 fission if desired
// TODO check which option is better
// retTo = FlavourSampling;
retTo = MassSampling;
continue;
}
// Check if the decay kinematics is still possible: if not then
// force the one-hadron decay for the other cluster as well.
// NOTE: that the squared thresholds below are
// numerically more stringent which is needed
// kaellen function calculation
if(sqr(Mc1 + Mc2) > sqr(Mc)) {
// reject if we would need to create a C->H,H process if letFissionToXHadrons<2
if (letFissionToXHadrons < 2) {
// TODO check which option is better
// retTo = FlavourSampling;
retTo = MassSampling;
continue;
}
// TODO forbid other cluster!!!! to be also at hadron
if(!toHadron1) {
toHadron1 = spectrum()->chooseSingleHadron(ptrQ1->dataPtr(), newPtr1->dataPtr(),Mc-Mc2);
// toHadron1 = spectrum()->chooseSingleHadron(ptrQ1->dataPtr(), newPtr1->dataPtr(),ZERO);
if(toHadron1) {
Mc1 = toHadron1->mass();
pClu1.setMass(Mc1);
}
}
else if(!toHadron2) {
toHadron2 = spectrum()->chooseSingleHadron(ptrQ2->dataPtr(), newPtr2->dataPtr(),Mc-Mc1);
// toHadron2 = spectrum()->chooseSingleHadron(ptrQ2->dataPtr(), newPtr2->dataPtr(),ZERO);
if(toHadron2) {
Mc2 = toHadron2->mass();
pClu2.setMass(Mc2);
}
}
}
// NOTE: that the squared thresholds below are
// numerically more stringent which is needed
// kaellen function calculation
if (sqr(Mc) <= sqr(Mc1+Mc2)){
// escape if already lightest quark drawn
- if (
- fabs((m - getParticleData(ThePEG::ParticleID::u)->constituentMass())/GeV) < 1e-3
- ||
- fabs((m - getParticleData(ThePEG::ParticleID::d)->constituentMass())/GeV) < 1e-3
- ) {
+ if (fabs((m - mLightestQuark)/GeV) < 1e-3 ) {
// escape = true;
retTo = Done;
}
else {
// Try again with lighter quark
retTo = FlavourSampling;
}
continue;
}
// Note: want to fallthrough (in C++17 one could uncomment
// the line below to show that this is intentional)
[[fallthrough]];
}
/*
* PhaseSpaceSampling choices:
* - FullyAligned (default)
* - AlignedIsotropic
* - FullyIsotropic
* */
case PhaseSpaceSampling:
{
// ### Sample the Phase Space with respect to Matrix Element: ###
// TODO insert here PhaseSpace sampler
weightPhaseSpaceAngles = drawKinematics(pClu,p0Q1,p0Q2,toHadron1,toHadron2,
pClu1,pClu2,pQ1,pQone,pQtwo,pQ2);
if(weightPhaseSpaceAngles==0.0) {
// TODO check which option is better
retTo = MassSampling;
continue;
}
+ // Activate only if needed
+ if (0)
{ //sanity
if (areNotSame(pClu1+pClu2,pClu)) {
std::cout << "PCLU" << std::endl;
}
if (areNotSame(pClu1,pQ1+pQone)) {
std::cout << "PCLU1" << std::endl;
}
if (areNotSame(pClu2,pQ2+pQtwo)) {
std::cout << "PCLU2" << std::endl;
}
if (areNotSame(pClu,pQ1+pQone+pQ2+pQtwo)) {
std::cout << "PTOT" << std::endl;
}
}
// Should be precise i.e. no rejection expected
// Note: want to fallthrough (in C++17 one could uncomment
// the line below to show that this is intentional)
[[fallthrough]];
}
/*
* MatrixElementSampling choices:
* - Default (default)
* - SoftQQbar
* */
case MatrixElementSampling:
{
counter_MEtry++;
// TODO maybe bridge this to work more neatly
// Ignore matrix element for C->C,H or C->H1,H2 fission
if (toHadron1 || toHadron2) {
retTo = Done;
break;
}
// Actual MatrixElement evaluated at sampled PhaseSpace point
double SQME = calculateSQME(p0Q1,p0Q2,pQ1,pQone,pQ2,pQtwo);
// Total overestimate of MatrixElement independent
// of the PhaseSpace point and independent of M1,M2
double SQMEoverEstimate = calculateSQME_OverEstimate(Mc,m1,m2,m);
// weight for MatrixElement*PhaseSpace must be in [0:1]
double weightSQME = SQME/SQMEoverEstimate;
assert(weightSQME>0.0);
// weight(M1,M2) for M1*M2*(Two body PhaseSpace)**3 should be in [0,1]
double weightFlatPS = weightFlatPhaseSpace(Mc, Mc1, Mc2, m, m1, m2, ptrQ1, ptrQ2, newPtr1);
if (weightFlatPS<0 || weightFlatPS>1.0){
throw Exception() << "weightFlatPS = "<< weightFlatPS << " > 1 or negative in MatrixElementClusterFissioner::cutTwo"
<< "Mc = " << Mc/GeV
<< "Mc1 = " << Mc1/GeV
<< "Mc2 = " << Mc2/GeV
<< "m1 = " << m1/GeV
<< "m2 = " << m2/GeV
<< "m = " << m/GeV
<< "SQME = " << SQME
<< "SQME_OE = " << SQMEoverEstimate
<< "PS = " << weightFlatPS
<< Exception::runerror;
}
// current phase space point is distributed according to weightSamp
double Pacc = weightFlatPS * weightSQME;
double SamplingWeight = weightMasses * weightPhaseSpaceAngles;
if (!(SamplingWeight >= 0 ) || std::isnan(SamplingWeight) || std::isinf(SamplingWeight)){
throw Exception() << "SamplingWeight = "<< SamplingWeight << " in MatrixElementClusterFissioner::cutTwo"
<< "Mc = " << Mc/GeV
<< "Mc1 = " << Mc1/GeV
<< "Mc2 = " << Mc2/GeV
<< "m1 = " << m1/GeV
<< "m2 = " << m2/GeV
<< "m = " << m/GeV
<< "weightMasses = " << weightMasses
<< "weightPhaseSpaceAngles = " << weightPhaseSpaceAngles
<< "PS = " << weightFlatPS
<< Exception::runerror;
}
Pacc/=SamplingWeight;
if (!(Pacc >= 0 ) || std::isnan(Pacc) || std::isinf(Pacc)){
throw Exception() << "Pacc = "<< Pacc << " < 0 in MatrixElementClusterFissioner::cutTwo"
<< "Mc = " << Mc/GeV
<< "Mc1 = " << Mc1/GeV
<< "Mc2 = " << Mc2/GeV
<< "m1 = " << m1/GeV
<< "m2 = " << m2/GeV
<< "m = " << m/GeV
<< "SQME = " << SQME
<< "SQME_OE = " << SQMEoverEstimate
<< "PS = " << weightFlatPS
<< Exception::runerror;
}
assert(Pacc >= 0.0);
if (_matrixElement!=0) {
if ( Pacc > 1.0){
countPaccGreater1();
throw Exception() << "Pacc = "<< Pacc << " > 1 in MatrixElementClusterFissioner::cutTwo"
<< "Mc = " << Mc/GeV
<< "Mc1 = " << Mc1/GeV
<< "Mc2 = " << Mc2/GeV
<< "m1 = " << m1/GeV
<< "m2 = " << m2/GeV
<< "m = " << m/GeV
<< Exception::warning;
}
}
static int first=_writeOut;
if (_matrixElement==0 || UseRandom::rnd()<Pacc) { //Always accept a sample if trivial matrix element
if (_writeOut) {
// std::cout << "\nAccept Pacc = "<<Pacc<<"\n";
std::ofstream out("data_CluFis.dat", std::ios::app | std::ios::out);
Lorentz5Momentum p0Q1tmp(p0Q1);
Lorentz5Momentum pClu1tmp(pClu1);
Lorentz5Momentum pClu2tmp(pClu2);
p0Q1tmp.boost(-pClu.boostVector());
pClu1tmp.boost(-pClu.boostVector());
double cosThetaP1C1=p0Q1tmp.vect().cosTheta(pClu1tmp.vect());
out << Pacc << "\t"
<< Mc/GeV << "\t"
<< pClu1.mass()/GeV << "\t"
<< pClu2.mass()/GeV << "\t"
<< pQone*pQtwo/(pQone.mass()*pQtwo.mass()) << "\t"
<< pQ1*pQ2/(pQ1.mass()*pQ2.mass()) << "\t"
<< pQ1*pQtwo/(pQ1.mass()*pQtwo.mass()) << "\t"
<< pQ2*pQone/(pQ2.mass()*pQone.mass()) << "\t"
<< p0Q1*(pQone+pQtwo)/(p0Q1.mass()*(pQone.mass()+pQtwo.mass())) << "\t"
<< p0Q2*(pQone+pQtwo)/(p0Q2.mass()*(pQone.mass()+pQtwo.mass())) << "\t"
<< m/GeV << "\t"
<< cosThetaP1C1
<< "\n";
out.close();
Energy MbinStart=2.0*GeV;
Energy MbinEnd=91.0*GeV;
Energy dMbin=1.0*GeV;
Energy MbinLow;
Energy MbinHig;
if ( fabs((m-getParticleData(ParticleID::d)->constituentMass())/GeV)<1e-5
&& fabs((m1-getParticleData(ParticleID::d)->constituentMass())/GeV)<1e-5
&& fabs((m2-getParticleData(ParticleID::d)->constituentMass())/GeV)<1e-5) {
int cnt = 0;
for (Energy MbinIt=MbinStart; MbinIt < MbinEnd; MbinIt+=dMbin)
{
if (first){
first=0;
std::cout << "\nFirst\n" << std::endl;
int ctr=0;
for (Energy MbinIt=MbinStart; MbinIt < MbinEnd; MbinIt+=dMbin)
{
std::string name = "WriteOut/data_CluFis_BinM_"+std::to_string(ctr)+".dat";
std::ofstream out2(name,std::ios::out);
out2 << "# Binned from "<<MbinIt/GeV << "\tto\t" << (MbinIt+dMbin)/GeV<<"\n";
out2 << "# m=m1=m2=0.325\n";
out2 << "# (1) Pacc\t"
<< "(2) Mc/GeV\t"
<< "(3) M1/GeV\t"
<< "(4) M2/GeV\t"
<< "(5) q.qbar/(mq^2)\t"
<< "(6) q1.q2/(m1*m2)\t"
<< "(7) q1.qbar/(m1*mq)\t"
<< "(8) q2.q/(m2*mq)\t"
<< "(9) p1.(q+qbar)/(m1*2*mq)\t"
<< "(10) p2.(q+qbar)/(m2*2*mq)\t"
<< "(11) m/GeV\t"
<< "(12) cos(theta_p1_Q1)\n";
out2.close();
ctr++;
}
// first=0;
}
MbinLow = MbinIt;
MbinHig = MbinLow+dMbin;
if (Mc>MbinLow && Mc<MbinHig) {
std::string name = "WriteOut/data_CluFis_BinM_"+std::to_string(cnt)+".dat";
std::ofstream out2(name, std::ios::app );
Lorentz5Momentum p0Q1tmp(p0Q1);
Lorentz5Momentum pClu1tmp(pClu1);
Lorentz5Momentum pClu2tmp(pClu2);
p0Q1tmp.boost(-pClu.boostVector());
pClu1tmp.boost(-pClu.boostVector());
double cosThetaP1C1=p0Q1tmp.vect().cosTheta(pClu1tmp.vect());
out2 << Pacc << "\t"
<< Mc/GeV << "\t"
<< pClu1.mass()/GeV << "\t"
<< pClu2.mass()/GeV << "\t"
<< pQone*pQtwo/(pQone.mass()*pQtwo.mass()) << "\t"
<< pQ1*pQ2/(pQ1.mass()*pQ2.mass()) << "\t"
<< pQ1*pQtwo/(pQ1.mass()*pQtwo.mass()) << "\t"
<< pQ2*pQone/(pQ2.mass()*pQone.mass()) << "\t"
<< p0Q1*(pQone+pQtwo)/(p0Q1.mass()*(pQone.mass()+pQtwo.mass())) << "\t"
<< p0Q2*(pQone+pQtwo)/(p0Q2.mass()*(pQone.mass()+pQtwo.mass())) << "\t"
<< m/GeV << "\t"
<< cosThetaP1C1
<< "\n";
out2.close();
break;
}
// if (Mc<MbinIt) break;
cnt++;
}
}
}
retTo=Done;
break;
}
retTo = MassSampling;
continue;
}
default:
{
assert(false);
}
}
}
while (retTo!=Done && !escape && counter_MEtry < _maxLoopFissionMatrixElement);
if(escape) {
// happens if we get at too light cluster to begin with
static const PPtr null = PPtr();
return cutType(PPair(null,null),PPair(null,null));
}
if(counter_MEtry >= _maxLoopFissionMatrixElement) {
countMaxLoopViolations();
// happens if we get too massive clusters where the matrix element
// is very inefficiently sampled
std::stringstream warning;
warning
<< "Matrix Element rejection sampling tried more than "
<< counter_MEtry
<< " times.\nMcluster = " << Mc/GeV
<< "GeV\nm1 = " << m1/GeV
<< "GeV\nm2 = " << m2/GeV
<< "GeV\nm = " << m/GeV
<< "GeV\n"
<< "isBeamCluster = " << cluster->isBeamCluster()
<<"Using default as MatrixElementClusterFissioner::cutTwo as a fallback.\n"
<< "***This Exception should not happen too often!*** ";
generator()->logWarning( Exception(warning.str(),Exception::warning));
switch (_failModeMaxLoopMatrixElement)
{
case 0:
// OldFission
return ClusterFissioner::cutTwo(cluster,finalhadrons,softUEisOn);
break;
case 1:
// RejectEvent
throw Exception() << warning.str()
<< Exception::eventerror;
break;
default:
assert(false);
}
}
assert(abs(Mc1-pClu1.m())<1e-2*GeV);
assert(abs(Mc2-pClu2.m())<1e-2*GeV);
assert(abs(Mc1-pClu1.mass())<1e-2*GeV);
assert(abs(Mc2-pClu2.mass())<1e-2*GeV);
{
Lorentz5Momentum pp1(p0Q1);
Lorentz5Momentum pclu1(pClu1);
pclu1.boost(-pClu.boostVector());
pp1.boost(-pClu.boostVector());
// std::ofstream out("testCF.dat", std::ios::app);
// out << pclu1.vect().cosTheta(pp1.vect())<<"\n";
// out.close();
}
// Count successfull ClusterFission
countFissionMatrixElement();
// ==> full sample generated
/******************
* The previous methods have determined the kinematics and positions
* of C -> C1 + C2.
* In the case that one of the two product is light, that means either
* decayOneHadronClu1 or decayOneHadronClu2 is true, then the momenta
* of the components of that light product have not been determined,
* and a (light) cluster will not be created: the heavy father cluster
* decays, in this case, into a single (not-light) cluster and a
* single hadron. In the other, "normal", cases the father cluster
* decays into two clusters, each of which has well defined components.
* Notice that, in the case of components which point to particles, the
* momenta of the components is properly set to the new values, whereas
* we do not change the momenta of the pointed particles, because we
* want to keep all of the information (that is the new momentum of a
* component after the splitting, which is contained in the _momentum
* member of the Component class, and the (old) momentum of that component
* before the splitting, which is contained in the momentum of the
* pointed particle). Please not make confusion of this only apparent
* inconsistency!
********************/
LorentzPoint posC,pos1,pos2;
posC = cluster->vertex();
calculatePositions(pClu, posC, pClu1, pClu2, pos1, pos2);
cutType rval;
if(toHadron1) {
rval.first = produceHadron(toHadron1, newPtr1, pClu1, pos1);
finalhadrons.push_back(rval.first.first);
}
else {
rval.first = produceCluster(ptrQ1, newPtr1, pClu1, pos1, pQ1, pQone, rem1);
}
if(toHadron2) {
rval.second = produceHadron(toHadron2, newPtr2, pClu2, pos2);
finalhadrons.push_back(rval.second.first);
}
else {
rval.second = produceCluster(ptrQ2, newPtr2, pClu2, pos2, pQ2, pQtwo, rem2);
}
return rval;
}
/**
* Calculate the masses and possibly kinematics of the cluster
* fission at hand; if claculateKineamtics is perfomring non-trivial
* steps kinematics calulcated here will be overriden. Currently resorts to the default
* @return the potentially non-trivial distribution weight=f(M1,M2)
* On Failure we return 0
*/
double MatrixElementClusterFissioner::drawNewMasses(const Energy Mc, const bool soft1, const bool soft2,
Lorentz5Momentum& pClu1, Lorentz5Momentum& pClu2,
tcPPtr ptrQ1, const Lorentz5Momentum& pQ1,
tcPPtr newPtr1, const Lorentz5Momentum& pQone,
tcPPtr, const Lorentz5Momentum& pQtwo,
tcPPtr ptrQ2, const Lorentz5Momentum& pQ2) const {
// TODO add precise weightMS that could be used used for improving the rejection Sampling
switch (_massSampler)
{
case 0:
return ClusterFissioner::drawNewMasses(Mc, soft1, soft2, pClu1, pClu2, ptrQ1, pQ1, tcPPtr(), pQone, tcPPtr(),pQtwo, ptrQ2, pQ2);
break;
case 1:
return drawNewMassesUniform(Mc, pClu1, pClu2, pQ1, pQone, pQ2);
break;
case 2:
return drawNewMassesPhaseSpace(Mc, pClu1, pClu2, pQ1, pQone, pQ2, ptrQ1, newPtr1, ptrQ2);
break;
case 3:
return drawNewMassesPhaseSpacePowerLaw(Mc, pClu1, pClu2, pQ1, pQone, pQ2, ptrQ1, newPtr1, ptrQ2);
break;
default:
assert(false);
}
return 0;// failure
}
/**
* Sample the masses for flat phase space
* */
double MatrixElementClusterFissioner::drawNewMassesUniform(const Energy Mc, Lorentz5Momentum& pClu1, Lorentz5Momentum& pClu2,
const Lorentz5Momentum& pQ1,
const Lorentz5Momentum& pQ,
const Lorentz5Momentum& pQ2) const {
Energy M1,M2;
const Energy m1 = pQ1.mass();
const Energy m2 = pQ2.mass();
const Energy m = pQ.mass();
const Energy M1min = m1 + m;
const Energy M2min = m2 + m;
const Energy M1max = Mc - M2min;
const Energy M2max = Mc - M1min;
assert(M1max-M1min>ZERO);
assert(M2max-M2min>ZERO);
double r1;
double r2;
int counter = 0;
const int max_counter = 100;
while (counter < max_counter) {
r1 = UseRandom::rnd();
r2 = UseRandom::rnd();
M1 = (M1max-M1min)*r1 + M1min;
M2 = (M2max-M2min)*r2 + M2min;
counter++;
if ( Mc > M1 + M2) break;
}
if (counter==max_counter
|| Mc < M1 + M2
|| M1 <= M1min
|| M2 <= M2min ) return 0.0; // failure
pClu1.setMass(M1);
pClu2.setMass(M2);
return 1.0; // succeeds
}
/**
* Sample the masses for flat phase space
* */
double MatrixElementClusterFissioner::drawNewMassesPhaseSpacePowerLaw(const Energy Mc,
Lorentz5Momentum& pClu1, Lorentz5Momentum& pClu2,
const Lorentz5Momentum& pQ1,
const Lorentz5Momentum& pQ,
const Lorentz5Momentum& pQ2,
tcPPtr ptrQ1, tcPPtr ptrQ2, tcPPtr ptrQ) const {
Energy M1,M2,MuS;
const Energy m1 = pQ1.mass();
const Energy m2 = pQ2.mass();
const Energy m = pQ.mass();
const Energy M1min = m1 + m;
const Energy M2min = m2 + m;
const Energy M1max = Mc - M2min;
const Energy M2max = Mc - M1min;
assert(M1max-M1min>ZERO);
assert(M2max-M2min>ZERO);
double r1;
double r2;
int counter = 0;
const int max_counter = 200;
while (counter < max_counter) {
r1 = UseRandom::rnd();
r2 = UseRandom::rnd();
M1 = (M1max-M1min)*r1 + M1min;
M2 = (M2max-M2min)*r2 + M2min;
counter++;
if (sqr(M1+M2)>sqr(Mc))
continue;
// if (!phaseSpaceVeto(Mc,M1,M2,m,m1,m2) ) break; // For FlatPhaseSpace sampling vetoing
if (!phaseSpaceVeto(Mc,M1,M2,m,m1,m2, ptrQ1, ptrQ2, ptrQ,_powerLawPower) ) break; // For FlatPhaseSpace sampling vetoing
}
if (counter==max_counter) return 0.0; // failure
pClu1.setMass(M1);
pClu2.setMass(M2);
return weightPhaseSpaceConstituentMasses(Mc, M1, M2, m, m1, m2, _powerLawPower); // succeeds return weight
}
/**
* Sample the masses for flat phase space
* */
double MatrixElementClusterFissioner::drawNewMassesPhaseSpace(const Energy Mc,
Lorentz5Momentum& pClu1, Lorentz5Momentum& pClu2,
const Lorentz5Momentum& pQ1,
const Lorentz5Momentum& pQ,
const Lorentz5Momentum& pQ2,
tcPPtr ptrQ1, tcPPtr ptrQ2, tcPPtr ptrQ ) const {
Energy M1,M2,MuS;
const Energy m1 = pQ1.mass();
const Energy m2 = pQ2.mass();
const Energy m = pQ.mass();
const Energy M1min = m1 + m;
const Energy M2min = m2 + m;
const Energy M1max = Mc - M2min;
const Energy M2max = Mc - M1min;
assert(M1max-M1min>ZERO);
assert(M2max-M2min>ZERO);
double r1;
double r2;
int counter = 0;
const int max_counter = 200;
while (counter < max_counter) {
r1 = UseRandom::rnd();
r2 = UseRandom::rnd();
M1 = (M1max-M1min)*r1 + M1min;
M2 = (M2max-M2min)*r2 + M2min;
counter++;
if (sqr(M1+M2)>sqr(Mc))
continue;
// if (!phaseSpaceVeto(Mc,M1,M2,m,m1,m2) ) break; // For FlatPhaseSpace sampling vetoing
if (!phaseSpaceVeto(Mc,M1,M2,m,m1,m2, ptrQ1, ptrQ2, ptrQ) ) break; // For FlatPhaseSpace sampling vetoing
}
if (counter==max_counter) return 0.0; // failure
pClu1.setMass(M1);
pClu2.setMass(M2);
return weightFlatPhaseSpace(Mc, M1, M2, m, m1, m2, ptrQ1, ptrQ2, ptrQ); // succeeds return weight
}
std::pair<Axis,double> MatrixElementClusterFissioner::sampleDirectionConstituents(
const Lorentz5Momentum & pClu, const Energy Mcluster) const {
switch (_phaseSpaceSamplerConstituent)
{
case 0:
{
// Aligned
return std::make_pair(pClu.vect().unit(),1.0);
}
case 1:
{
// Isotropic
return std::make_pair(sampleDirectionIsotropic(),1.0);
}
case 2:
{
// Exponential
// New
// double C_est_Exponential=1.18;
// double power_est_Exponential=0.65;
// Old
double C_est_Exponential=0.63;
double power_est_Exponential=0.89;
double lambda=C_est_Exponential*pow(Mcluster/GeV,power_est_Exponential);
return sampleDirectionExponential(pClu.vect().unit(), lambda);
}
default:
assert(false);
break;
}
return std::make_pair(Axis(),0.0); // Failure
}
std::pair<Axis,double> MatrixElementClusterFissioner::sampleDirectionCluster(
const Lorentz5Momentum & pQ,
const Lorentz5Momentum & pClu) const {
switch (_phaseSpaceSamplerCluster)
{
case 0:
{
// Aligned
Axis dir;
if (_covariantBoost)
// in Covariant Boost the positive z-Axis is defined as the direction of
// the pQ vector in the Cluster rest frame
dir = Axis(0,0,1);
else
dir = sampleDirectionAligned(pQ, pClu);
return std::make_pair(dir,1.0);
}
case 1:
{
// Isotropic
return std::make_pair(sampleDirectionIsotropic(),1.0);
}
case 2:
{
// Tchannel
Energy M=pClu.mass();
// New
// double C_est_Tchannel=3.66;
// double power_est_Tchannel=-1.95;
// Old
double C_est_Tchannel=9.78;
double power_est_Tchannel=-2.5;
double A = C_est_Tchannel*pow(M/GeV,power_est_Tchannel);
double Ainv = 1.0/(1.0+A);
return sampleDirectionTchannel(sampleDirectionAligned(pQ,pClu),Ainv);
}
default:
assert(false);
}
return std::make_pair(Axis(),0.0); // Failure
}
-std::pair<Axis,double> MatrixElementClusterFissioner::sampleDirectionExponential(const Axis dirQ, const double lambda) const {
+std::pair<Axis,double> MatrixElementClusterFissioner::sampleDirectionExponential(const Axis & dirQ, const double lambda) const {
Axis FinalDir = dirQ;
double cosTheta = Kinematics::sampleCosExp(lambda);
double phi;
// std::cout << "cosThetaSamp = "<< cosTheta <<"\tlambda = " <<lambda << std::endl;
// If no change in angle keep the direction fixed
if (fabs(cosTheta-1.0)>1e-14) {
// rotate to sampled angles
FinalDir.rotate(acos(cosTheta),dirQ.orthogonal());
phi = UseRandom::rnd(-Constants::pi,Constants::pi);
FinalDir.rotate(phi,dirQ);
}
// std::cout << "cosThetaTrue = "<< FinalDir.cosTheta(dirQ) <<"\tlambda = " <<lambda << std::endl;
double weight = exp(lambda*(cosTheta-1.0));
if (std::isnan(weight) ||std::isinf(weight) )
std::cout << "lambda = " << lambda << "\t cos " << cosTheta<< std::endl;
assert(!std::isnan(weight));
assert(!std::isinf(weight));
if (fabs(FinalDir.cosTheta(dirQ)-cosTheta)>1e-8) std::cout << "cosThetaTrue = "<< FinalDir.cosTheta(dirQ) <<"\tlambda = " <<lambda << std::endl;
return std::make_pair(FinalDir,weight);
}
-std::pair<Axis,double> MatrixElementClusterFissioner::sampleDirectionTchannel(const Axis dirQ, const double Ainv) const {
+std::pair<Axis,double> MatrixElementClusterFissioner::sampleDirectionTchannel(const Axis & dirQ, const double Ainv) const {
double cosTheta = Kinematics::sampleCosTchannel(Ainv);
double phi;
Axis FinalDir = dirQ;
// If no change in angle keep the direction fixed
if (fabs(cosTheta-1.0)>1e-14) {
// rotate to sampled angles
FinalDir.rotate(acos(cosTheta),dirQ.orthogonal());
phi = UseRandom::rnd(-Constants::pi,Constants::pi);
FinalDir.rotate(phi,dirQ);
}
double weight = 0.0;
if (1.0-Ainv>1e-10)
weight=1.0/pow(1.0/Ainv-cosTheta,2.0);
else
weight=1.0/pow((1.0-cosTheta)+(1.0-Ainv),2.0);
if (std::isnan(weight) ||std::isinf(weight) )
std::cout << "Ainv = " << Ainv << "\t cos " << cosTheta<< std::endl;
assert(!std::isnan(weight));
assert(!std::isinf(weight));
if (fabs(FinalDir.cosTheta(dirQ)-cosTheta)>1e-8) std::cout << "cosThetaTrue = "<< FinalDir.cosTheta(dirQ) <<"\tAinv = " <<Ainv << std::endl;
return std::make_pair(FinalDir,weight);
}
Axis MatrixElementClusterFissioner::sampleDirectionAligned(const Lorentz5Momentum & pQ, const Lorentz5Momentum & pClu) const {
Lorentz5Momentum pQinCOM(pQ);
pQinCOM.setMass(pQ.m());
pQinCOM.boost( -pClu.boostVector() ); // boost from LAB to C
return pQinCOM.vect().unit();
}
Axis MatrixElementClusterFissioner::sampleDirectionAlignedSmeared(const Lorentz5Momentum & pQ, const Lorentz5Momentum & pClu) const {
Lorentz5Momentum pQinCOM(pQ);
pQinCOM.setMass(pQ.m());
pQinCOM.boost( -pClu.boostVector() ); // boost from LAB to C
if (pQinCOM.vect().mag2()<=ZERO){
return sampleDirectionAlignedSmeared(pClu-pQ,pClu);
}
const Axis dir = pQinCOM.vect().unit();
double cluSmear = 0.5;
double cosTheta;
do {
cosTheta = 1.0 + cluSmear*log( UseRandom::rnd() );
}
while (fabs(cosTheta)>1.0 || std::isnan(cosTheta) || std::isinf(cosTheta));
if (!(dir.mag2()>ZERO)){
std::cout << "\nDRI = 0"<< dir.mag2() << std::endl;
}
Axis dirSmeared = dir;
double phi;
if (fabs(cosTheta-1.0)>1e-10) {
// rotate to sampled angles
dirSmeared.rotate(acos(cosTheta),dir.orthogonal());
phi = UseRandom::rnd(-M_PI,M_PI);
dirSmeared.rotate(phi,dir);
}
if (!(dirSmeared.mag2()>ZERO)){
std::cout << "\nDRI SMR = 0" <<cosTheta<< "\t" <<acos(cosTheta)<< "\t"<< phi<< "\t"<< dirSmeared.mag2() << std::endl;
std::cout << dir.orthogonal() << std::endl;
}
return dirSmeared;
}
Axis MatrixElementClusterFissioner::sampleDirectionIsotropic() const {
double cosTheta = -1 + 2.0 * UseRandom::rnd();
double sinTheta = sqrt(1.0-cosTheta*cosTheta);
double Phi = 2.0 * Constants::pi * UseRandom::rnd();
Axis uClusterUniform(cos(Phi)*sinTheta, sin(Phi)*sinTheta, cosTheta);
return uClusterUniform.unit();
}
Axis MatrixElementClusterFissioner::sampleDirectionSemiUniform(const Lorentz5Momentum & pQ, const Lorentz5Momentum & pClu) const {
Axis dir = sampleDirectionAligned(pQ,pClu);
Axis res;
do {
res=sampleDirectionIsotropic();
}
while (dir*res<0);
return res;
}
namespace {
double SoftFunction(
const Lorentz5Momentum & pi,
const Lorentz5Momentum & pj,
const Lorentz5Momentum & q,
const Lorentz5Momentum & qbar) {
Energy2 mq2 = q*q;
- double numerator = -(pi*pj)*(q*qbar+mq2)/sqr(GeV2);
- double denominator = sqr(q*qbar+mq2)*(pi*(q+qbar))*(pj*(q+qbar))/sqr(GeV2*GeV2);
+ Energy2 qqbar = q*qbar;
+ Energy2 piq = pi*q;
+ Energy2 piqbar = pi*qbar;
+ Energy2 pjq = pj*q;
+ Energy2 pjqbar = pj*qbar;
+ double numerator = -(pi*pj)*(qqbar+mq2)/sqr(GeV2);
+ double denominator = sqr(qqbar+mq2)*(piq+piqbar)*(pjq+pjqbar)/sqr(GeV2*GeV2);
int cataniScheme = 1;
// Different expressions which should yield similar results
switch (cataniScheme) {
case 0:
- numerator += ((pi*q)*(pj*qbar) + (pj*q)*(pi*qbar))/sqr(GeV2);
+ numerator += ((piq)*(pjqbar) + (pjq)*(piqbar))/sqr(GeV2);
break;
case 1:
- numerator += - (0.5*(pi*(q-qbar))*(pj*(q-qbar)))/sqr(GeV2);
+ numerator += - (0.5*(piq-piqbar)*(pjq-pjqbar))/sqr(GeV2);
break;
default:
assert(false);
}
double Iij = numerator/denominator;
return Iij;
}
}
/* SQME for p1,p2->C1(q1,q),C2(q2,qbar)
* Note that:
* p0Q1 -> p1
* p0Q2 -> p2
* pQ1 -> q1
* pQone -> q
* pQ2 -> q2
* pQone -> qbar
* */
double MatrixElementClusterFissioner::calculateSQME(
const Lorentz5Momentum & p1,
const Lorentz5Momentum & p2,
const Lorentz5Momentum & q1,
const Lorentz5Momentum & q,
const Lorentz5Momentum & q2,
const Lorentz5Momentum & qbar) const {
double SQME;
switch (_matrixElement)
{
case 0:
SQME = 1.0;
break;
case 1:
{
/*
// Energy2 p1p2 = p1*p2;
Energy2 q1q2 = q1 * q2;
Energy2 q1q = q1 * q ;
Energy2 q2qbar = q2 * qbar;
Energy2 q2q = q2 * q ;
Energy2 q1qbar = q1 * qbar;
Energy2 qqbar = q * qbar;
Energy2 mq2 = q.mass2();
double Numerator = q1q2 * (qqbar + mq2)/sqr(GeV2);
Numerator += 0.5 * (q1q - q1qbar)*(q2q - q2qbar)/sqr(GeV2);
double Denominator = sqr(qqbar + mq2)*(q1q + q1qbar)*(q2q + q2qbar)/sqr(sqr(GeV2));
SQME = Numerator/Denominator;
*/
double I11 = SoftFunction(q1,q1,q,qbar);
double I22 = SoftFunction(q2,q2,q,qbar);
double I12 = SoftFunction(q1,q2,q,qbar);
SQME = (I11+I22-2.0*I12);
if (SQME<0.0) {
std::cout << "I11 = " << I11<< std::endl;
std::cout << "I22 = " << I22<< std::endl;
std::cout << "2*I12 = " << I12<< std::endl;
std::cout << "soft = " << I11+I22-2.0*I12<< std::endl;
std::cout << "M = " << (p1+p2).m()/GeV<< std::endl;
std::cout << "M1 = " << (q1+q).m()/GeV<< std::endl;
std::cout << "M2 = " << (q2+qbar).m()/GeV<< std::endl;
std::cout << "m1 = " << (q1).m()/GeV<< std::endl;
std::cout << "m2 = " << (q2).m()/GeV<< std::endl;
std::cout << "m = " << (q).m()/GeV<< std::endl;
}
break;
}
case 2:
{
/*
Energy2 p1p2 = p1 * p2;
Energy2 p1q = p1 * q ;
Energy2 p2qbar = p2 * qbar;
Energy2 p2q = p2 * q ;
Energy2 p1qbar = p1 * qbar;
Energy2 qqbar = q * qbar;
Energy2 mq2 = q.mass2();
double Numerator = p1p2 * (qqbar + mq2)/sqr(GeV2);
Numerator += 0.5 * (p1q - p1qbar)*(p2q - p2qbar)/sqr(GeV2);
double Denominator = sqr(qqbar + mq2)*(p1q + p1qbar)*(p2q + p2qbar)/sqr(sqr(GeV2));
SQME = Numerator/Denominator;
*/
double I11 = SoftFunction(p1,p1,q,qbar);
double I22 = SoftFunction(p2,p2,q,qbar);
double I12 = SoftFunction(p1,p2,q,qbar);
SQME = (I11+I22-2.0*I12);
if (SQME<0.0) {
std::cout << "I11 = " << I11<< std::endl;
std::cout << "I22 = " << I22<< std::endl;
std::cout << "2*I12 = " << I12<< std::endl;
std::cout << "soft = " << I11+I22-2.0*I12<< std::endl;
std::cout << "M = " << (p1+p2).m()/GeV<< std::endl;
std::cout << "M1 = " << (q1+q).m()/GeV<< std::endl;
std::cout << "M2 = " << (q2+qbar).m()/GeV<< std::endl;
std::cout << "m1 = " << (q1).m()/GeV<< std::endl;
std::cout << "m2 = " << (q2).m()/GeV<< std::endl;
std::cout << "m = " << (q).m()/GeV<< std::endl;
}
break;
}
case 4:
{
SQME = sqr(sqr(GeV2))/(sqr(q*qbar-q*q)*(p1*(q1+q)-p1*p1-sqrt((p1*p1)*(q*q)))*(p2*(q2+qbar)-p2*p2-sqrt((p2*p2)*(q*q))));
break;
}
case 5:
{
/*
Energy2 p1p2 = p1 * p2;
Energy2 p1q = p1 * q ;
Energy2 p2qbar = p2 * qbar;
Energy2 p2q = p2 * q ;
Energy2 p1qbar = p1 * qbar;
Energy2 qqbar = q * qbar;
Energy2 mq2 = q.mass2();
double Numerator = p1p2 * (qqbar + mq2)/sqr(GeV2);
Numerator += 0.5 * (p1q - p1qbar)*(p2q - p2qbar)/sqr(GeV2);
double Denominator = sqr(qqbar + mq2)*(p1q + p1qbar)*(p2q + p2qbar)/sqr(sqr(GeV2));
// add test Tchannel Matrix Element interference with gluon mass regulated
// Denominator *= sqr(sqr(p1-q1)-_epsilonResolution*sqrt((p1*p1)*(p2*p2)))/sqr(GeV2);
*/
- Energy mg=getParticleData(spectrum()->gluonId())->constituentMass();
+ static Energy mg=getParticleData(spectrum()->gluonId())->constituentMass();
double Denominator = (sqr(p1-q1)-_epsilonResolution*mg*mg)/(GeV2);
Denominator *= (sqr(p2-q2)-_epsilonResolution*mg*mg)/(GeV2);
double Numerator = ((q1*q2)*(p1*p2)+(p2*q1)*(p1*q2))/sqr(GeV2);
// double I11 = SoftFunction(p1,p1,q,qbar);
// double I22 = SoftFunction(p2,p2,q,qbar);
// double I12 = SoftFunction(p1,p2,q,qbar);
double I11 = SoftFunction(q1,q1,q,qbar);
double I22 = SoftFunction(q2,q2,q,qbar);
double I12 = SoftFunction(q1,q2,q,qbar);
SQME = Numerator*(I11+I22-2.0*I12)/Denominator;
if (SQME<0.0) {
std::cout << "I11 = " << I11<< std::endl;
std::cout << "I22 = " << I22<< std::endl;
std::cout << "2*I12 = " << I12<< std::endl;
std::cout << "soft = " << I11+I22-2.0*I12<< std::endl;
std::cout << "Numerator = " << Numerator<< std::endl;
std::cout << "Denominator = " << Denominator<< std::endl;
std::cout << "M = " << (p1+p2).m()/GeV<< std::endl;
std::cout << "M1 = " << (q1+q).m()/GeV<< std::endl;
std::cout << "M2 = " << (q2+qbar).m()/GeV<< std::endl;
std::cout << "m1 = " << (q1).m()/GeV<< std::endl;
std::cout << "m2 = " << (q2).m()/GeV<< std::endl;
std::cout << "m = " << (q).m()/GeV<< std::endl;
}
break;
}
default:
assert(false);
}
if (SQME < 0) throw Exception()
<< "Squared Matrix Element = "<< SQME <<" < 0 in MatrixElementClusterFissioner::calculateSQME() "
<< Exception::runerror;
return SQME;
}
/* Overestimate for SQME for p1,p2->C1(q1,q),C2(q2,qbar)
* Note that:
* p0Q1 -> p1 where Mass -> m1
* p0Q2 -> p2 where Mass -> m2
* pQ1 -> q1 where Mass -> m1
* pQone -> q where Mass -> mq
* pQ2 -> q2 where Mass -> m2
* pQone -> qbar where Mass -> mq
* */
double MatrixElementClusterFissioner::calculateSQME_OverEstimate(
const Energy& Mc,
const Energy& m1,
const Energy& m2,
const Energy& mq
) const {
double SQME_OverEstimate;
switch (_matrixElement)
{
case 0:
SQME_OverEstimate = 1.0;
break;
case 1:
{
// Fit factor for guess of best overestimate
double A = 0.25;
SQME_OverEstimate = _safetyFactorMatrixElement*A*pow(mq/GeV,-4);
break;
}
case 2:
{
// Fit factor for guess of best overestimate
double A = 0.25;
SQME_OverEstimate = _safetyFactorMatrixElement*A*pow(mq/GeV,-4);
break;
}
case 4:
{
// Fit factor for guess of best overestimate
SQME_OverEstimate = _safetyFactorMatrixElement*sqr(sqr(GeV2))/(sqr(mq*mq)*m1*m2*(m1+mq)*(m2+mq));
break;
}
case 5:
{
// Fit factor for guess of best overestimate
// Energy MassMax = 8.550986578849006037e+00*GeV; // mass max of python
// double wTotMax = 5.280507222727160297e+03; // at MassMax
// double argExp = 55.811; // from fit of python package
// double powLog = 0.08788; // from fit of python package
Energy MassMax = 5.498037126562503119e+01*GeV; // mass max of python
double wTotMax = 1.570045806367627112e+06; // at MassMax
double argExp = 16.12; // from fit of python package
double powLog = 0.3122; // from fit of python package
// Energy2 p1p2=0.5*(Mc*Mc-m1*m1-m2*m2);
// SQME_OverEstimate = _safetyFactorMatrixElement*A*pow(mq/GeV,-4)*(2*sqr(p1p2))/sqr(_epsilonResolution*(m1*m2));
Energy Mmin = (m1+m2+2*mq);
// Energy MdblPrec = Mmin*exp(pow(pow(log(MassMax/Mmin),powLog)+600.0/argExp,1.0/powLog));
// if (Mc >MdblPrec)
// std::cout << "errroRRRRR R MC = " << Mc/GeV << "\t Mcmax "<< MdblPrec/GeV<< std::endl;
if (MassMax<Mmin) MassMax=Mmin;
double Overestimate = wTotMax*exp(argExp*(pow(log(Mc/Mmin),powLog)-pow(log(MassMax/Mmin),powLog)));
SQME_OverEstimate = _safetyFactorMatrixElement*Overestimate;//*A*pow(mq/GeV,-4)*(2*sqr(p1p2))/sqr(_epsilonResolution*(m1*m2));
if (SQME_OverEstimate==0 || std::isinf(SQME_OverEstimate)|| std::isnan(SQME_OverEstimate)) {
std::cout << "SQME_OverEstimate is " << SQME_OverEstimate << std::endl;
std::cout << "Overestimate is " << Overestimate << std::endl;
std::cout << "MC " << Mc/GeV << std::endl;
std::cout << "m " << mq/GeV << std::endl;
std::cout << "m1 " << m1/GeV << std::endl;
std::cout << "m2 " << m2/GeV << std::endl;
}
break;
}
default:
assert(false);
}
return SQME_OverEstimate;
}
double MatrixElementClusterFissioner::drawKinematics(
const Lorentz5Momentum & pClu,
const Lorentz5Momentum & p0Q1,
const Lorentz5Momentum & p0Q2,
const bool toHadron1,
const bool toHadron2,
Lorentz5Momentum & pClu1,
Lorentz5Momentum & pClu2,
Lorentz5Momentum & pQ1,
Lorentz5Momentum & pQbar,
Lorentz5Momentum & pQ,
Lorentz5Momentum & pQ2bar) const {
double weightTotal=0.0;
if (pClu.mass() < pClu1.mass() + pClu2.mass()
|| pClu1.mass()<ZERO
|| pClu2.mass()<ZERO ) {
throw Exception() << "Impossible Kinematics in MatrixElementClusterFissioner::drawKinematics() (A)\n"
<< "Mc = "<< pClu.mass()/GeV <<" GeV\n"
<< "Mc1 = "<< pClu1.mass()/GeV <<" GeV\n"
<< "Mc2 = "<< pClu2.mass()/GeV <<" GeV\n"
<< Exception::eventerror;
}
// Sample direction of the daughter clusters
std::pair<Axis,double> directionCluster = sampleDirectionCluster(p0Q1, pClu);
Axis DirToClu = directionCluster.first;
weightTotal = directionCluster.second;
if (0 && _writeOut) {
ofstream out("WriteOut/test_Cluster.dat",std::ios::app);
Lorentz5Momentum pQinCOM(p0Q1);
pQinCOM.setMass(p0Q1.m());
pQinCOM.boost( -pClu.boostVector() ); // boost from LAB to C
out << DirToClu.cosTheta(pQinCOM.vect()) << "\n";
}
if (_covariantBoost) {
const Energy M = pClu.mass();
const Energy M1 = pClu1.mass();
const Energy M2 = pClu2.mass();
const Energy PcomClu=Kinematics::pstarTwoBodyDecay(M,M1,M2);
Momentum3 pClu1sampVect( PcomClu*DirToClu);
Momentum3 pClu2sampVect(-PcomClu*DirToClu);
pClu1.setMass(M1);
pClu1.setVect(pClu1sampVect);
pClu1.rescaleEnergy();
pClu2.setMass(M2);
pClu2.setVect(pClu2sampVect);
pClu2.rescaleEnergy();
}
else {
Lorentz5Momentum pClutmp(pClu);
pClutmp.boost(-pClu.boostVector());
Kinematics::twoBodyDecay(pClutmp, pClu1.mass(), pClu2.mass(),DirToClu, pClu1, pClu2);
}
// In the case that cluster1 does not decay immediately into a single hadron,
// calculate the momenta of Q1 (as constituent of C1) and Qbar in the
// (parent) C1 frame first, where the direction of Q1 is u.vect().unit(),
// and then boost back in the LAB frame.
if(!toHadron1) {
if (pClu1.m() < pQ1.mass() + pQbar.mass() ) {
throw Exception() << "Impossible Kinematics in MatrixElementClusterFissioner::drawKinematics() (B)"
<< Exception::eventerror;
}
std::pair<Axis,double> direction1 = sampleDirectionConstituents(pClu1,pClu.mass());
// Need to boost constituents first into the pClu rest frame
// boost from Cluster1 rest frame to Cluster COM Frame
// Kinematics::twoBodyDecay(pClu1, pQ1.mass(), pQbar.mass(), DirClu1, pQ1, pQbar);
Kinematics::twoBodyDecay(pClu1, pQ1.mass(), pQbar.mass(), direction1.first, pQ1, pQbar);
weightTotal*=direction1.second;
if (0 && _writeOut) {
ofstream out("WriteOut/test_Constituents1.dat",std::ios::app);
Lorentz5Momentum pQ1inCOM(pQ1);
pQ1inCOM.setMass(pQ1.m());
pQ1inCOM.boost( -pClu1.boostVector() ); // boost from LAB to C
out << pQ1inCOM.vect().cosTheta(pClu1.vect()) << "\n";
}
}
// In the case that cluster2 does not decay immediately into a single hadron,
// Calculate the momenta of Q and Q2bar (as constituent of C2) in the
// (parent) C2 frame first, where the direction of Q is u.vect().unit(),
// and then boost back in the LAB frame.
if(!toHadron2) {
if (pClu2.m() < pQ.mass() + pQ2bar.mass() ) {
throw Exception() << "Impossible Kinematics in MatrixElementClusterFissioner::drawKinematics() (C)"
<< Exception::eventerror;
}
std::pair<Axis,double> direction2 = sampleDirectionConstituents(pClu2,pClu.mass());
// boost from Cluster2 rest frame to Cluster COM Frame
Kinematics::twoBodyDecay(pClu2, pQ2bar.mass(), pQ.mass(), direction2.first, pQ2bar, pQ);
weightTotal*=direction2.second;
if (0 && _writeOut) {
ofstream out("WriteOut/test_Constituents2.dat",std::ios::app);
Lorentz5Momentum pQ2inCOM(pQ2bar);
pQ2inCOM.setMass(pQ2bar.m());
pQ2inCOM.boost( -pClu2.boostVector() ); // boost from LAB to C
out << pQ2inCOM.vect().cosTheta(pClu2.vect()) << "\n";
}
}
// Boost all momenta from the Cluster COM frame to the Lab frame
if (_covariantBoost) {
std::vector<Lorentz5Momentum *> momenta;
momenta.push_back(&pClu1);
momenta.push_back(&pClu2);
if (!toHadron1) {
momenta.push_back(&pQ1);
momenta.push_back(&pQbar);
}
if (!toHadron2) {
momenta.push_back(&pQ);
momenta.push_back(&pQ2bar);
}
Kinematics::BoostIntoTwoParticleFrame(pClu.mass(),p0Q1, p0Q2, momenta);
}
else {
pClu1.boost(pClu.boostVector());
pClu2.boost(pClu.boostVector());
pQ1.boost(pClu.boostVector());
pQ2bar.boost(pClu.boostVector());
pQ.boost(pClu.boostVector());
pQbar.boost(pClu.boostVector());
}
return weightTotal; // success
}
diff --git a/Hadronization/MatrixElementClusterFissioner.h b/Hadronization/MatrixElementClusterFissioner.h
--- a/Hadronization/MatrixElementClusterFissioner.h
+++ b/Hadronization/MatrixElementClusterFissioner.h
@@ -1,379 +1,379 @@
// -*- C++ -*-
//
// MatrixElementClusterFissioner.h is a part of Herwig - A multi-purpose Monte Carlo event generator
// Copyright (C) 2002-2019 The Herwig Collaboration
//
// Herwig is licenced under version 3 of the GPL, see COPYING for details.
// Please respect the MCnet academic guidelines, see GUIDELINES for details.
//
#ifndef HERWIG_MatrixElementClusterFissioner_H
#define HERWIG_MatrixElementClusterFissioner_H
#include <ThePEG/Interface/Interfaced.h>
#include "CluHadConfig.h"
#include "ClusterFissioner.h"
#include "HadronSpectrum.h"
namespace Herwig {
using namespace ThePEG;
/** \ingroup Hadronization
* \class MatrixElementClusterFissioner
* \brief This class handles clusters which are too heavy by a semi-perturbative cluster fission matrix element.
* \author Stefan Kiebacher
*
* @see \ref MatrixElementClusterFissionerInterfaces "The interfaces"
* defined for MatrixElementClusterFissioner.
*/
class MatrixElementClusterFissioner: public ClusterFissioner {
public:
/** @name Standard constructors and destructors. */
//@{
/**
* Default constructor.
*/
MatrixElementClusterFissioner();
/**
* Default destructor.
*/
virtual ~MatrixElementClusterFissioner();
//@}
virtual tPVector fission(ClusterVector & clusters, bool softUEisOn);
public:
/** @name Functions used by the persistent I/O system. */
//@{
/**
* Function used to write out object persistently.
* @param os the persistent output stream written to.
*/
void persistentOutput(PersistentOStream & os) const;
/**
* Function used to read in object persistently.
* @param is the persistent input stream read from.
* @param version the version number of the object when written.
*/
void persistentInput(PersistentIStream & is, int version);
//@}
/**
* Standard Init function used to initialize the interfaces.
*/
static void Init();
protected:
/** @name Clone Methods. */
//@{
/**
* Make a simple clone of this object.
* @return a pointer to the new object.
*/
virtual IBPtr clone() const;
/** Make a clone of this object, possibly modifying the cloned object
* to make it sane.
* @return a pointer to the new object.
*/
virtual IBPtr fullclone() const;
//@}
private:
/**
* Private and non-existent assignment operator.
*/
MatrixElementClusterFissioner & operator=(const MatrixElementClusterFissioner &) = delete;
virtual void cut(stack<ClusterPtr> &,
ClusterVector&, tPVector & finalhadrons, bool softUEisOn);
public:
/**
* Splits the input cluster.
*
* Split the input cluster (which can be either an heavy non-beam
* cluster or a beam cluster). The result is two pairs of particles. The
* first element of each pair is new cluster/hadron, while the second
* element of each pair is the particle drawn from the vacuum to create
* the new cluster/hadron.
* Notice that this method treats also beam clusters by using a different
* mass spectrum used to generate the cluster child masses (see method
* drawChildMass).
*/
//@{
/**
* Split two-component cluster
*/
virtual cutType cutTwo(ClusterPtr &, tPVector & finalhadrons, bool softUEisOn);
/**
* Split two-component cluster using New FissionApproach
*/
virtual cutType cutTwoMatrixElement(ClusterPtr &, tPVector & finalhadrons, bool softUEisOn);
//@}
protected:
/**
* Calculate the masses and possibly kinematics of the cluster
* fission at hand; if claculateKineamtics is perfomring non-trivial
* steps kinematics claulcated here will be overriden. Currentl;y resorts to the default
* @return the potentially non-trivial distribution weight=f(M1,M2)
* On Failure we return 0
*/
virtual double drawNewMasses(const Energy Mc, const bool soft1, const bool soft2,
Lorentz5Momentum& pClu1, Lorentz5Momentum& pClu2,
tcPPtr ptrQ1, const Lorentz5Momentum& pQ1,
tcPPtr, const Lorentz5Momentum& pQone,
tcPPtr, const Lorentz5Momentum& pQtwo,
tcPPtr ptrQ2, const Lorentz5Momentum& pQ2) const;
/**
* Calculate the masses and possibly kinematics of the cluster
* fission at hand; if claculateKineamtics is perfomring non-trivial
* steps kinematics claulcated here will be overriden. Currentl;y resorts to the default
*/
double drawNewMassesDefault(const Energy Mc, const bool soft1, const bool soft2,
Lorentz5Momentum& pClu1, Lorentz5Momentum& pClu2,
tcPPtr ptrQ1, const Lorentz5Momentum& pQ1,
tcPPtr, const Lorentz5Momentum& pQone,
tcPPtr, const Lorentz5Momentum& pQtwo,
tcPPtr ptrQ2, const Lorentz5Momentum& pQ2) const;
/**
* Sample the masses for flat phase space
* */
double drawNewMassesUniform(const Energy Mc,
Lorentz5Momentum & pClu1, Lorentz5Momentum & pClu2,
const Lorentz5Momentum & pQ1,
const Lorentz5Momentum & pQ,
const Lorentz5Momentum & pQ2) const;
/**
* Sample the masses for flat phase space
* */
double drawNewMassesPhaseSpace(const Energy Mc,
Lorentz5Momentum & pClu1, Lorentz5Momentum & pClu2,
const Lorentz5Momentum & pQ1,
const Lorentz5Momentum & pQ,
const Lorentz5Momentum & pQ2,
tcPPtr ptrQ1, tcPPtr ptrQ2, tcPPtr ptrQ ) const;
/**
* Sample the masses for flat phase space modulated by a power law
* */
double drawNewMassesPhaseSpacePowerLaw(const Energy Mc,
Lorentz5Momentum& pClu1, Lorentz5Momentum& pClu2,
const Lorentz5Momentum& pQ1,
const Lorentz5Momentum& pQ,
const Lorentz5Momentum& pQ2,
tcPPtr ptrQ1, tcPPtr ptrQ2, tcPPtr ptrQ) const;
/**
* Calculate the final kinematics of a heavy cluster decay C->C1 +
* C2, if not already performed by drawNewMasses
* @return returns false if failes
*/
double drawKinematics(const Lorentz5Momentum &pClu,
const Lorentz5Momentum &p0Q1,
const Lorentz5Momentum &p0Q2,
const bool toHadron1, const bool toHadron2,
Lorentz5Momentum &pClu1, Lorentz5Momentum &pClu2,
Lorentz5Momentum &pQ1, Lorentz5Momentum &pQb,
Lorentz5Momentum &pQ, Lorentz5Momentum &pQ2b) const;
/**
* Calculation of the squared matrix element from the drawn
* momenta
* @return value of the squared matrix element in units of
* 1/GeV4
* */
double calculateSQME(
const Lorentz5Momentum & p1,
const Lorentz5Momentum & p2,
const Lorentz5Momentum & q1,
const Lorentz5Momentum & q,
const Lorentz5Momentum & q2,
const Lorentz5Momentum & qbar) const;
/**
* Calculation of the overestimate for the squared matrix
* element independent on M1 and M2
* @return value of the overestimate squared matrix element
* in units of 1/GeV4
* */
double calculateSQME_OverEstimate(
const Energy& Mc,
const Energy& m1,
const Energy& m2,
const Energy& mq) const;
protected:
/** @name Access members for child classes. */
//@{
/**
* Access to the hadron selector
*/
// HadronSpectrumPtr hadronSpectrum() const {return _hadronSpectrum;}
//@}
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:
std::pair<Axis,double> sampleDirectionCluster(const Lorentz5Momentum & pQ, const Lorentz5Momentum & pClu) const;
std::pair<Axis,double> sampleDirectionConstituents(const Lorentz5Momentum & pClu, const Energy Mcluster) const;
/**
* Samples the direction of Cluster Fission products uniformly
**/
Axis sampleDirectionIsotropic() const;
/**
* Samples the direction of Cluster Fission products uniformly
* but only accepts those flying in the direction of pRelCOM
**/
Axis sampleDirectionSemiUniform(const Lorentz5Momentum & pQ, const Lorentz5Momentum & pClu) const;
/**
* Samples the direction of Cluster Fission products according to Default
* fully aligned D = 1+1 Fission
* */
Axis sampleDirectionAligned(const Lorentz5Momentum & pQ, const Lorentz5Momentum & pClu) const;
/**
* Samples the direction of Cluster Fission products according to Default
* Tchannel like distribution
* */
- std::pair<Axis,double> sampleDirectionTchannel(const Axis dirQ, const double Ainv) const;
+ std::pair<Axis,double> sampleDirectionTchannel(const Axis & dirQ, const double Ainv) const;
/**
* Samples the direction of direction from an exponential distribution
* */
- std::pair<Axis,double> sampleDirectionExponential(const Axis dirQ, const double lambda) const;
+ std::pair<Axis,double> sampleDirectionExponential(const Axis & dirQ, const double lambda) const;
/**
* Samples the direction of Cluster Fission products according to smeared direction along the cluster
* */
Axis sampleDirectionAlignedSmeared(const Lorentz5Momentum & pQ, const Lorentz5Momentum & pClu) const;
/**
* Check if a cluster is heavy enough to be at least kinematically able to split
*/
bool canSplitMinimally(tcClusterPtr, Energy);
/**
* Check if can't make a hadron from the partons
*/
inline bool cantMakeHadron(tcPPtr p1, tcPPtr p2) {
return ! spectrum()->canBeHadron(p1->dataPtr(), p2->dataPtr());
}
void countPaccGreater1(){
_counterPaccGreater1++;
};
void countMaxLoopViolations(){
_counterMaxLoopViolations++;
};
void countFissionMatrixElement(){
_counterFissionMatrixElement++;
};
private:
/**
* Flag for allowing Hadron Final states in Cluster Fission
*/
int _allowHadronFinalStates;
/**
* Choice of Mass sampling for MatrixElementClusterFissioner
* i.e. rejection sampling starting from MassPresampling
* Chooses the to be sampled Mass distribution
* Note: This ideal distribution would be ideally
* exactly the integral over the angles as a
* function of M1,M2
*/
int _massSampler;
/**
* Choice of Phase Space sampling for MatrixElementClusterFissioner
* for child cluster directions and constituent directions
*/
int _phaseSpaceSamplerCluster;
int _phaseSpaceSamplerConstituent;
/**
* Choice of Matrix Element for MatrixElementClusterFissioner
* Note: The choice of the matrix element requires
* to provide one overestimate as a function
* of M1,M2 and another overestimate of the
* previous overestimate independent of
* M1 and M2 i.e. only dependent on M,m1,m2,m
*/
int _matrixElement;
/**
* Choice of MatrixElementClusterFissioner Approach
*/
int _fissionApproach;
/**
* Power for MassPreSampler = PowerLaw
*/
double _powerLawPower;
/**
* Choice of MatrixElementClusterFissioner Approach
* Technical Parameter for how many tries are allowed to sample the
* Cluster Fission matrix element before reverting to fissioning
* using the default Fission Aproach
*/
int _maxLoopFissionMatrixElement;
/*
* Safety factor for a better overestimate of the matrix Element
*
* */
double _safetyFactorMatrixElement;
/*
* IR cutOff for IR divergent diagramms
* */
double _epsilonResolution;
/*
* Failing mode for MaxLoopMatrixElement
* */
int _failModeMaxLoopMatrixElement;
// For MatrixElement only:
// Counter for how many times we accept events with Pacc>1
static unsigned int _counterPaccGreater1;
// Counter for how many times we escape the sampling by
// tries > _maxLoopFissionMatrixElement
// NOTE: This maxing out either rejects event or uses old
// ClusterFission
static unsigned int _counterMaxLoopViolations;
static unsigned int _counterFissionMatrixElement;
private:
int _writeOut;
};
}
#endif /* HERWIG_MatrixElementClusterFissioner_H */

File Metadata

Mime Type
text/x-diff
Expires
Sat, Dec 21, 6:41 PM (5 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4023848
Default Alt Text
(90 KB)

Event Timeline