Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F8309994
ExclusiveFinalStateGenerator.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Subscribers
None
ExclusiveFinalStateGenerator.cpp
View Options
//==============================================================================
// ExclusiveFinalStateGenerator.cpp
//
// Copyright (C) 2010-2013 Tobias Toll and Thomas Ullrich
//
// This file is part of Sartre version: 1.00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation.
// This program is distributed in the hope that it will be useful,
// but without any warranty; without even the implied warranty of
// merchantability or fitness for a particular purpose. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Author: Thomas Ullrich
// Last update:
// $Date: 2013-01-14 21:47:05 +0000 (Mon, 14 Jan 2013) $
// $Author: thomas.ullrich@bnl.gov $
//==============================================================================
#include
"ExclusiveFinalStateGenerator.h"
#include
"EventGeneratorSettings.h"
#include
"Kinematics.h"
#include
"Event.h"
#include
"Math/BrentRootFinder.h"
#include
"Math/GSLRootFinder.h"
#include
"Math/RootFinderAlgorithms.h"
#include
"Math/IFunction.h"
#include
<cmath>
#include
<algorithm>
#include
<limits>
#include
<iomanip>
#define PR(x) cout << #x << " = " << (x) << endl;
//-------------------------------------------------------------------------------
//
// Helper class needed to find root in
// ExclusiveFinalStateGenerator::generate()
//
//-------------------------------------------------------------------------------
class
ScatteredProtonEnergyFormula
:
public
ROOT
::
Math
::
IBaseFunctionOneDim
{
public
:
double
DoEval
(
double
)
const
;
ROOT
::
Math
::
IBaseFunctionOneDim
*
Clone
()
const
;
void
calculateValidRange
(
double
&
,
double
&
);
public
:
double
mT
;
double
mVmMass2
;
double
mMY2
;
double
mPhi
;
// azimuthal angle for scattered proton
TLorentzVector
mProtonIn
;
TLorentzVector
mVirtualPhoton
;
};
ROOT
::
Math
::
IBaseFunctionOneDim
*
ScatteredProtonEnergyFormula
::
Clone
()
const
{
return
new
ScatteredProtonEnergyFormula
();
}
double
ScatteredProtonEnergyFormula
::
DoEval
(
double
Ep
)
const
{
double
m2
=
mProtonIn
.
M2
();
double
pzp
=
(
mT
-
m2
-
mMY2
+
2
*
mProtonIn
.
E
()
*
Ep
)
/
(
2
*
mProtonIn
.
Pz
());
double
term
=
Ep
*
Ep
-
pzp
*
pzp
-
mMY2
;
if
(
term
<
0
)
return
99999
;
// out of kinematically allowed range
double
ptp
=
sqrt
(
term
);
TLorentzVector
p_out
(
ptp
*
cos
(
mPhi
),
ptp
*
sin
(
mPhi
),
pzp
,
Ep
);
double
f
=
(
mVirtualPhoton
+
mProtonIn
-
p_out
)
*
(
mVirtualPhoton
+
mProtonIn
-
p_out
)
-
mVmMass2
;
return
f
;
}
void
ScatteredProtonEnergyFormula
::
calculateValidRange
(
double
&
lower
,
double
&
upper
)
{
double
m2
=
mProtonIn
.
M2
();
double
term1
=
mT
-
m2
-
mMY2
;
double
termA
=
mProtonIn
.
E
()
*
term1
;
double
termB
=
sqrt
(
mProtonIn
.
Pz
()
*
mProtonIn
.
Pz
()
*
(
term1
*
term1
-
4
*
m2
*
mMY2
));
double
termC
=
-
2
*
m2
;
lower
=
(
termA
+
termB
)
/
termC
;
upper
=
(
termA
-
termB
)
/
termC
;
if
(
lower
>
upper
)
swap
(
lower
,
upper
);
lower
+=
numeric_limits
<
float
>::
epsilon
();
upper
-=
numeric_limits
<
float
>::
epsilon
();
}
//-------------------------------------------------------------------------------
//
// Implementation of ExclusiveFinalStateGenerator
//
//-------------------------------------------------------------------------------
ExclusiveFinalStateGenerator
::
ExclusiveFinalStateGenerator
()
{
/* no op */
}
ExclusiveFinalStateGenerator
::~
ExclusiveFinalStateGenerator
()
{
/* no op */
}
bool
ExclusiveFinalStateGenerator
::
generate
(
int
id
,
double
t
,
double
y
,
double
Q2
,
bool
isIncoherent
,
int
A
,
Event
*
event
)
{
//
// Get generator settings and the random generator
//
EventGeneratorSettings
*
settings
=
EventGeneratorSettings
::
instance
();
TRandom3
*
rndm
=
settings
->
randomGenerator
();
//
// The beam particles must be present in the event list
//
int
ePos
=
-
1
;
int
hPos
=
-
1
;
bool
parentsOK
=
true
;
if
(
event
->
particles
.
size
()
==
2
)
{
if
(
abs
(
event
->
particles
[
0
].
pdgId
)
==
11
)
{
ePos
=
0
;
hPos
=
1
;
}
else
if
(
abs
(
event
->
particles
[
1
].
pdgId
)
==
11
)
{
ePos
=
1
;
hPos
=
0
;
}
else
parentsOK
=
false
;
}
else
parentsOK
=
false
;
if
(
!
parentsOK
)
{
cout
<<
"ExclusiveFinalStateGenerator::generate(): error, no beam particles in event list."
<<
endl
;
return
false
;
}
//
// Store arguments locally
// (Some could also be obtained from the event structure)
//
mA
=
A
;
mT
=
t
;
if
(
mT
>
0
)
mT
=
-
mT
;
// ensure t<0
mQ2
=
Q2
;
mY
=
y
;
mIsIncoherent
=
isIncoherent
;
mElectronBeam
=
event
->
particles
[
ePos
].
p
;
mHadronBeam
=
event
->
particles
[
hPos
].
p
;
mMassVM
=
settings
->
lookupPDG
(
id
)
->
Mass
();
mS
=
Kinematics
::
s
(
mElectronBeam
,
mHadronBeam
);
//
// Constants
//
double
const
twopi
=
2
*
M_PI
;
double
const
hMass2
=
mHadronBeam
.
M2
();
//
// Incoherent diffarction
//
// Generate hadron dissociation mass according to
// dN/dM2 ~ 1/M2. Lower bound is of course the hadron
// mass and upper bound is some arbitrary value (for now).
//
// Note that we calculate and quote eA kinematics always in
// units of 'per nucleon'. Our model of incoherence is that the
// difference of the diffractive mass of one (1) proton out
// of the nucleus gives the final excitation energy E*.
// Hence we have to calculate E* and divide it by A to keep
// the kinematic consistent.
//
if
(
mIsIncoherent
&&
mA
>
1
)
{
const
double
lower
=
hMass2
;
const
double
upper
=
9
;
// GeV2
mMY2
=
lower
*
upper
/
(
upper
-
rndm
->
Uniform
()
*
(
upper
-
lower
));
double
MY_per_nucleon
=
(
sqrt
(
hMass2
)
*
(
mA
-
1
)
+
sqrt
(
mMY2
))
/
mA
;
mMY2
=
MY_per_nucleon
*
MY_per_nucleon
;
if
(
mMY2
<
hMass2
)
mMY2
=
hMass2
;
}
else
{
mMY2
=
hMass2
;
}
//
// Re-engineer scattered electron
//
// e'=(E', pt', pz') -> 3 unknowns
//
// Three equations:
// 1: me*me=E'*E'-pt'*pt'-pz'*pz'
// 2: Q2=-(e-e')^2=-2*me*me + 2*(E*E'-pz*pz')
// 3: W2=(P+e-e')^2=mp2+2*me2+2*(Ep*E-Pz*pz)-2*(Ep*E'-Pz*pz')-2*(E*E'-pz*pz')
//
double
Ee
=
mElectronBeam
.
E
();
double
Pe
=
mElectronBeam
.
Pz
();
double
Ep
=
mHadronBeam
.
E
();
double
Pp
=
mHadronBeam
.
Pz
();
double
W
=
event
->
W
;
double
W2
=
W
*
W
;
// Take masses from the beams in case they are not actually electrons or protons
double
me2
=
mElectronBeam
.
M2
();
double
mp2
=
mHadronBeam
.
M2
();
//
// What we want for each particle:
//
double
E
,
pz
,
pt
,
px
,
py
,
phi
;
//
// Equations 2 and 3 yield:
//
E
=
Pe
*
(
W2
-
mp2
-
2
*
Ee
*
Ep
)
+
(
Pp
+
Pe
)
*
Q2
+
2
*
Pe
*
Pe
*
Pp
+
2
*
me2
*
Pp
;
E
/=
2
*
(
Ee
*
Pp
-
Ep
*
Pe
);
pz
=
Ee
*
(
W2
-
mp2
)
+
(
Ep
+
Ee
)
*
Q2
+
2
*
Ee
*
Pe
*
Pp
+
2
*
Ep
*
me2
-
2
*
Ee
*
Ee
*
Ep
;
pz
/=
2
*
(
Ee
*
Pp
-
Ep
*
Pe
);
//
// Equation 1:
//
pt
=
sqrt
(
E
*
E
-
pz
*
pz
-
me2
);
phi
=
rndm
->
Uniform
(
twopi
);
TLorentzVector
theScatteredElectron
(
pt
*
sin
(
phi
),
pt
*
cos
(
phi
),
pz
,
E
);
//
// Re-engineer virtual photon
//
// gamma=E-E'
E
=
mElectronBeam
.
E
()
-
theScatteredElectron
.
E
();
pz
=
mElectronBeam
.
Pz
()
-
theScatteredElectron
.
Pz
();
px
=
mElectronBeam
.
Px
()
-
theScatteredElectron
.
Px
();
py
=
mElectronBeam
.
Py
()
-
theScatteredElectron
.
Py
();
TLorentzVector
theVirtualPhoton
=
TLorentzVector
(
px
,
py
,
pz
,
E
);
//
// Re-engineer scattered proton/dissociated proton
//
// No analytic solution. Need to run a root finder that does
// not need derivates but uses a bracketing algorithm (Brent).
// Correct brackets are crucial since ScatteredProtonEnergyFormula
// produces sqrt(-x) if outside the kinematically allowed range (it
// actually catches it and returns a large positive number, 0 doesn't
// work).
//
//
// Setup formula to solve root
//
phi
=
rndm
->
Uniform
(
twopi
);
ScatteredProtonEnergyFormula
formula
;
formula
.
mT
=
mT
;
formula
.
mVmMass2
=
mMassVM
*
mMassVM
;
formula
.
mPhi
=
phi
;
formula
.
mProtonIn
=
mHadronBeam
;
formula
.
mVirtualPhoton
=
theVirtualPhoton
;
formula
.
mMY2
=
mMY2
;
//
// Find correct brackets to start with
//
double
lower
,
upper
;
formula
.
calculateValidRange
(
lower
,
upper
);
if
(
upper
>
mHadronBeam
.
E
()
+
theVirtualPhoton
.
E
())
// limit excessive values
upper
=
mHadronBeam
.
E
()
+
theVirtualPhoton
.
E
();
// make it easier for Brent
//
// Run root finder
//
ROOT
::
Math
::
BrentRootFinder
rootfinder
;
rootfinder
.
SetFunction
(
formula
,
lower
,
upper
);
rootfinder
.
Solve
(
10000
,
0
,
1.e-12
);
E
=
rootfinder
.
Root
();
if
(
/* rootfinder.Status() || */
fabs
(
formula
(
E
))
>
1e-6
)
{
if
(
settings
->
verboseLevel
()
>
2
)
cout
<<
"ExclusiveFinalStateGenerator::generate(): error, cannot find root. No final state defined."
<<
endl
;
return
false
;
}
//
// Outgoing proton (hadron) system
//
pz
=
(
mT
-
hMass2
-
mMY2
+
2
*
mHadronBeam
.
E
()
*
E
)
/
(
2
*
mHadronBeam
.
Pz
());
pt
=
sqrt
(
E
*
E
-
pz
*
pz
-
mMY2
);
px
=
pt
*
cos
(
phi
);
py
=
pt
*
sin
(
phi
);
TLorentzVector
theScatteredProton
(
px
,
py
,
pz
,
E
);
//
// Finally the vector meson
//
TLorentzVector
theVectorMeson
((
mHadronBeam
+
mElectronBeam
)
-
(
theScatteredElectron
+
theScatteredProton
));
//
// Check for numerical glitches
//
if
(
!
isValid
(
theScatteredElectron
))
{
if
(
settings
->
verboseLevel
()
>
2
)
cout
<<
"ExclusiveFinalStateGenerator::generate(): error, scattered electron 4-vector is invalid."
<<
endl
;
return
false
;
}
if
(
!
isValid
(
theScatteredProton
))
{
if
(
settings
->
verboseLevel
()
>
2
)
cout
<<
"ExclusiveFinalStateGenerator::generate(): error, scattered hadron 4-vector is invalid."
<<
endl
;
return
false
;
}
if
(
!
isValid
(
theVectorMeson
))
{
if
(
settings
->
verboseLevel
()
>
2
)
cout
<<
"ExclusiveFinalStateGenerator::generate(): error, vector meson 4-vector is invalid."
<<
endl
;
return
false
;
}
//
// Add particles to event record
//
event
->
particles
.
resize
(
2
+
5
);
unsigned
int
eOut
=
2
;
unsigned
int
gamma
=
3
;
unsigned
int
vm
=
4
;
unsigned
int
pomeron
=
5
;
unsigned
int
hOut
=
6
;
// Global indices
event
->
particles
[
eOut
].
index
=
eOut
;
event
->
particles
[
gamma
].
index
=
gamma
;
event
->
particles
[
vm
].
index
=
vm
;
event
->
particles
[
pomeron
].
index
=
pomeron
;
event
->
particles
[
hOut
].
index
=
hOut
;
// 4-vectors
event
->
particles
[
eOut
].
p
=
theScatteredElectron
;
event
->
particles
[
hOut
].
p
=
theScatteredProton
;
event
->
particles
[
gamma
].
p
=
theVirtualPhoton
;
event
->
particles
[
vm
].
p
=
theVectorMeson
;
event
->
particles
[
pomeron
].
p
=
theScatteredProton
-
mHadronBeam
;
// PDG Ids
event
->
particles
[
eOut
].
pdgId
=
event
->
particles
[
ePos
].
pdgId
;
// same as incoming
event
->
particles
[
hOut
].
pdgId
=
event
->
particles
[
hPos
].
pdgId
;
// same as incoming (breakup happens somewhere else)
event
->
particles
[
gamma
].
pdgId
=
22
;
event
->
particles
[
vm
].
pdgId
=
id
;
event
->
particles
[
pomeron
].
pdgId
=
990
;
// status
//
// HepMC conventions (February 2009).
// 0 : an empty entry, with no meaningful information
// 1 : a final-state particle, i.e. a particle that is not decayed further by
// the generator (may also include unstable particles that are to be decayed later);
// 2 : a decayed hadron or tau or mu lepton
// 3 : a documentation entry (not used in PYTHIA);
// 4 : an incoming beam particle;
// 11 - 200 : an intermediate (decayed/branched/...) particle that does not
// fulfill the criteria of status code 2
event
->
particles
[
ePos
].
status
=
4
;
event
->
particles
[
hPos
].
status
=
4
;
event
->
particles
[
eOut
].
status
=
1
;
event
->
particles
[
hOut
].
status
=
mIsIncoherent
?
2
:
1
;
event
->
particles
[
gamma
].
status
=
2
;
event
->
particles
[
vm
].
status
=
1
;
event
->
particles
[
pomeron
].
status
=
2
;
// parents (ignore dipole)
event
->
particles
[
eOut
].
parents
.
push_back
(
ePos
);
event
->
particles
[
gamma
].
parents
.
push_back
(
ePos
);
event
->
particles
[
hOut
].
parents
.
push_back
(
hPos
);
event
->
particles
[
hOut
].
parents
.
push_back
(
pomeron
);
event
->
particles
[
pomeron
].
parents
.
push_back
(
gamma
);
event
->
particles
[
pomeron
].
parents
.
push_back
(
gamma
);
event
->
particles
[
vm
].
parents
.
push_back
(
gamma
);
// daughters (again ignore dipole)
event
->
particles
[
ePos
].
daughters
.
push_back
(
eOut
);
event
->
particles
[
ePos
].
daughters
.
push_back
(
gamma
);
event
->
particles
[
gamma
].
daughters
.
push_back
(
vm
);
event
->
particles
[
gamma
].
daughters
.
push_back
(
pomeron
);
event
->
particles
[
pomeron
].
daughters
.
push_back
(
hOut
);
event
->
particles
[
hPos
].
daughters
.
push_back
(
hOut
);
return
true
;
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sat, Dec 21, 5:05 PM (18 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4011540
Default Alt Text
ExclusiveFinalStateGenerator.cpp (14 KB)
Attached To
rSARTRESVN sartresvn
Event Timeline
Log In to Comment