ATLAS Offline Software
suep_shower.cxx
Go to the documentation of this file.
1 /*
2  * This file is taken from the available public code at:
3  * https://gitlab.com/simonknapen/suep_generator
4  * by Simon Knapen.
5  */
6 #include "suep_shower.h"
7 
8 using namespace boost::math::tools; // For bracket_and_solve_root.
9 // using namespace std;
10 using namespace Pythia8;
11 
12 // constructor
13 Suep_shower::Suep_shower(double mass, double temperature, double energy, Pythia8::Rndm *rndm) {
14  m_m = mass;
15  m_Temp=temperature;
16  m_Etot=energy;
17  m_rndmEngine = rndm;
18 
19  m_A=m_m/m_Temp;
20  m_p_m=std::sqrt(2/(m_A*m_A)*(1+std::sqrt(1+m_A*m_A)));
21 
22  double pmax=std::sqrt(2+2*std::sqrt(1+m_A*m_A))/m_A; // compute the location of the maximum, to split the range
23 
24  tolerance tol = 0.00001;
25  m_p_plus = (bisect(std::bind(&Suep_shower::test_fun, this, std::placeholders::_1),pmax,50.0, tol)).first; // first root
26  m_p_minus = (bisect(std::bind(&Suep_shower::test_fun, this, std::placeholders::_1), 0.0,pmax, tol)).first; // second root
27  m_lambda_plus = - f(m_p_plus)/fp(m_p_plus);
28  m_lambda_minus = f(m_p_minus)/fp(m_p_minus);
29  m_q_plus = m_lambda_plus / (m_p_plus - m_p_minus);
30  m_q_minus = m_lambda_minus / (m_p_plus - m_p_minus);
31  m_q_m = 1- (m_q_plus + m_q_minus);
32 
33 }
34 
35 // maxwell-boltzman distribution, slightly massaged
36 double Suep_shower::f(double p){
37  return p*p*exp(-m_A*p*p/(1+std::sqrt(1+p*p)));
38 }
39 
40 // derivative of maxwell-boltzmann
41 double Suep_shower::fp(double p){
42  return exp(-m_A*p*p/(1+std::sqrt(1+p*p)))*p*(2-m_A*p*p/std::sqrt(1+p*p));
43 }
44 
45 // test function to be solved for m_p_plus, m_p_minus
46 double Suep_shower::test_fun(double p){
47  return log(f(p)/f(m_p_m))+1.0;
48 }
49 
50 // generate one random 4 vector from the thermal distribution
52 
53  Vec4 fourvec;
54  double en, phi, theta, p;//kinematic variables of the 4 vector
55 
56  // first do momentum, following arxiv:1305.5226
57  double U(0.0), V(0.0), X(0.0), Y(0.0), E(0.0);
58  int i=0;
59  while(i<100){
60  if (m_rndmEngine) {
61  U = m_rndmEngine->flat();
62  V = m_rndmEngine->flat();
63  } else {
64  U = ((double) rand() / RAND_MAX);
65  V = ((double) rand() / RAND_MAX);
66  }
67 
68  if(U < m_q_m){
69  Y=U/m_q_m;
70  X=( 1 - Y )*( m_p_minus + m_lambda_minus )+Y*( m_p_plus - m_lambda_plus );
71  if(V < f(X) / f(m_p_m) && X>0){
72  break;
73  }
74  }
75  else{if(U < m_q_m + m_q_plus){
76  E = -log((U-m_q_m)/m_q_plus);
77  X = m_p_plus - m_lambda_plus*(1-E);
78  if(V<exp(E)*f(X)/f(m_p_m) && X>0){
79  break;
80  }
81  }
82  else{
83  E = - log((U-(m_q_m+m_q_plus))/m_q_minus);
84  X = m_p_minus + m_lambda_minus * (1 - E);
85  if(V < exp(E)*f(X)/f(m_p_m) && X>0){
86  break;
87  }
88  }
89  }
90  }
91  p=X*(this->m_m); // X is the dimensionless momentum, p/m
92 
93  // now do the angles
94  if (m_rndmEngine) {
95  phi = 2.0*M_PI*(m_rndmEngine->flat());
96  theta = acos(2.0*m_rndmEngine->flat()-1.0);
97  } else {
98  phi = 2.0*M_PI*((double) rand() / RAND_MAX);
99  theta = acos(2.0*((double) rand() / RAND_MAX)-1.0);
100  }
101 
102  // compose the 4 vector
103  en = std::sqrt(p*p+(this->m_m)*(this->m_m));
104  fourvec.p(p*cos(phi)*sin(theta), p*sin(phi)*sin(theta), p*cos(theta), en);
105 
106  return fourvec;
107 }
108 
109 // auxiliary function which computes the total energy difference as a function of the momentum vectors and a scale factor "a"
110 // to ballance energy, we solve for "a" by demanding that this function vanishes
111 // By rescaling the momentum rather than the energy, I avoid having to do these annoying rotations from the previous version
112 double Suep_shower::reballance_func(double a, const vector< Vec4 > &event){
113  double result =0.0;
114  double p2;
115  for(unsigned n = 0; n<event.size();n++){
116  p2 = event[n].px()*event[n].px() + event[n].py()*event[n].py() + event[n].pz()*event[n].pz();
117  result += std::sqrt(a*a*p2 + (this->m_m)* (this->m_m));
118  }
119  return result - (this->m_Etot);
120 }
121 
122 // generate a shower event, in the rest frame of the shower
124 
125  vector< Vec4 > event;
126  double sum_E = 0.0;
127 
128  // fill up event record
129  while(sum_E<(this->m_Etot)){
130  event.push_back(this->generateFourVector());
131  sum_E += (event.back()).e();
132  }
133 
134  // reballance momenta
135  int len = event.size();
136  double sum_p, correction;
137  for(int i = 1;i<4;i++){ // loop over 3 carthesian directions
138 
139  sum_p = 0.0;
140  for(int n=0;n<len;n++){
141  sum_p+=event[n][i];
142  }
143  correction=-1.0*sum_p/len;
144 
145  for(int n=0;n<len;n++){
146  event[n][i] += correction;
147  }
148  }
149 
150  //Shield against an exception in the calculation of "p_scale" further down. If it fails, abort the event.
151  if(Suep_shower::reballance_func(2.0,event)<0.0){
152  // failed to balance energy.
153  event.clear();
154  return event;
155  }
156 
157  // finally, ballance the total energy, without destroying momentum conservation
158  tolerance tol = 0.00001;
159  double p_scale;
160  try {
161  p_scale = (bisect(std::bind(&Suep_shower::reballance_func, this, std::placeholders::_1, event),0.0,2.0, tol)).first;
162  } catch (std::exception &e) {
163  //in some rare circumstances, this balancing might fail
164  std::cout << "[SUEP_SHOWER] WARNING: Failed to rebalance the following event; Printing for debug and throw exception" << std::endl;
165  std::cout << e.what() << std::endl;
166  std::cout << "N. Particle, px, py, pz, E" << std::endl;
167  for (size_t jj=0; jj < event.size(); jj++) {
168  //print out event
169  std::cout << jj << ": " << event[jj].px() << ", " << event[jj].py() << ", " << event[jj].pz() << ", " << event[jj].e() << std::endl;
170  }
171  throw e;
172  }
173 
174  for(int n=0;n<len;n++){
175  event[n].px(p_scale*event[n].px());
176  event[n].py(p_scale*event[n].py());
177  event[n].pz(p_scale*event[n].pz());
178  // force the energy with the on-shell condition
179  event[n].e(std::sqrt(event[n].px()*event[n].px() + event[n].py()*event[n].py() + event[n].pz()*event[n].pz() + (this->m_m)*(this->m_m)));
180  }
181 
182  return event;
183 }
python.CaloRecoConfig.f
f
Definition: CaloRecoConfig.py:127
get_generator_info.result
result
Definition: get_generator_info.py:21
test_pyathena.px
px
Definition: test_pyathena.py:18
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:64
Suep_shower::generate_shower
std::vector< Pythia8::Vec4 > generate_shower()
Generate a shower event, in the rest frame of the showe.
Definition: suep_shower.cxx:123
theta
Scalar theta() const
theta method
Definition: AmgMatrixBasePlugin.h:71
Suep_shower::f
double f(double p)
Maxwell-Boltzman distribution, slightly massaged.
Definition: suep_shower.cxx:36
M_PI
#define M_PI
Definition: ActiveFraction.h:11
Suep_shower::reballance_func
double reballance_func(double a, const std::vector< Pythia8::Vec4 > &event)
auxiliary function which computes the total energy difference as a function of the momentum vectors a...
Definition: suep_shower.cxx:112
Suep_shower::test_fun
double test_fun(double p)
Test function to be solved for p_plus,p_minus.
Definition: suep_shower.cxx:46
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
drawFromPickle.exp
exp
Definition: drawFromPickle.py:36
dqt_zlumi_pandas.mass
mass
Definition: dqt_zlumi_pandas.py:170
Monitored::X
@ X
Definition: HistogramFillerUtils.h:24
Pythia8
Author: James Monk (jmonk@cern.ch)
Definition: IPythia8Custom.h:13
suep_shower.h
Suep_shower::fp
double fp(double p)
Derivative of Maxwell-Boltzmann.
Definition: suep_shower.cxx:41
tools.zlumi_mc_cf.correction
def correction(mu, runmode, campaign, run=None)
Definition: zlumi_mc_cf.py:4
LArG4FSStartPointFilter.rand
rand
Definition: LArG4FSStartPointFilter.py:80
ParticleGun_FastCalo_ChargeFlip_Config.energy
energy
Definition: ParticleGun_FastCalo_ChargeFlip_Config.py:78
event
POOL::TEvent event(POOL::TEvent::kClassAccess)
lumiFormat.i
int i
Definition: lumiFormat.py:92
trigmenu_modify_prescale_json.fp
fp
Definition: trigmenu_modify_prescale_json.py:53
beamspotman.n
n
Definition: beamspotman.py:731
calibdata.exception
exception
Definition: calibdata.py:496
Amg::pz
@ pz
Definition: GeoPrimitives.h:40
xAOD::double
double
Definition: CompositeParticle_v1.cxx:159
tolerance
Definition: suep_shower.h:17
Monitored::Y
@ Y
Definition: HistogramFillerUtils.h:24
Amg::py
@ py
Definition: GeoPrimitives.h:39
VP1PartSpect::E
@ E
Definition: VP1PartSpectFlags.h:21
PlotCalibFromCool.en
en
Definition: PlotCalibFromCool.py:399
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
a
TList * a
Definition: liststreamerinfos.cxx:10
DeMoScan.first
bool first
Definition: DeMoScan.py:534
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
Suep_shower::Suep_shower
Suep_shower(double mass, double temperature, double energy, Pythia8::Rndm *rndm=0)
Constructor.
Definition: suep_shower.cxx:13
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
Suep_shower::generateFourVector
Pythia8::Vec4 generateFourVector()
generate one random 4 vector from the thermal distribution
Definition: suep_shower.cxx:51