ATLAS Offline Software
Loading...
Searching...
No Matches
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
8using namespace boost::math::tools; // For bracket_and_solve_root.
9// using namespace std;
10using namespace Pythia8;
11
12// constructor
13Suep_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
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
31 m_q_m = 1- (m_q_plus + m_q_minus);
32
33}
34
35// maxwell-boltzman distribution, slightly massaged
36double 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
41double 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
46double 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 //coverity[DC.WEAK_CRYPTO]
99 phi = 2.0*M_PI*((double) rand() / RAND_MAX);
100 //coverity[DC.WEAK_CRYPTO]
101 theta = acos(2.0*((double) rand() / RAND_MAX)-1.0);
102 }
103
104 // compose the 4 vector
105 en = std::sqrt(p*p+(this->m_m)*(this->m_m));
106 //coverity[COPY_PASTE_ERROR]
107 fourvec.p(p*cos(phi)*sin(theta), p*sin(phi)*sin(theta), p*cos(theta), en);
108
109 return fourvec;
110}
111
112// auxiliary function which computes the total energy difference as a function of the momentum vectors and a scale factor "a"
113// to ballance energy, we solve for "a" by demanding that this function vanishes
114// By rescaling the momentum rather than the energy, I avoid having to do these annoying rotations from the previous version
115double Suep_shower::reballance_func(double a, const vector< Vec4 > &event){
116 double result =0.0;
117 double p2;
118 for(unsigned n = 0; n<event.size();n++){
119 p2 = event[n].px()*event[n].px() + event[n].py()*event[n].py() + event[n].pz()*event[n].pz();
120 result += std::sqrt(a*a*p2 + (this->m_m)* (this->m_m));
121 }
122 return result - (this->m_Etot);
123}
124
125// generate a shower event, in the rest frame of the shower
127
128 vector< Vec4 > event;
129 double sum_E = 0.0;
130
131 // fill up event record
132 while(sum_E<(this->m_Etot)){
133 event.push_back(this->generateFourVector());
134 sum_E += (event.back()).e();
135 }
136
137 // reballance momenta
138 int len = event.size();
139 double sum_p, correction;
140 for(int i = 1;i<4;i++){ // loop over 3 carthesian directions
141
142 sum_p = 0.0;
143 for(int n=0;n<len;n++){
144 sum_p+=event[n][i];
145 }
146 correction=-1.0*sum_p/len;
147
148 for(int n=0;n<len;n++){
149 event[n][i] += correction;
150 }
151 }
152
153 //Shield against an exception in the calculation of "p_scale" further down. If it fails, abort the event.
154 if(Suep_shower::reballance_func(2.0,event)<0.0){
155 // failed to balance energy.
156 event.clear();
157 return event;
158 }
159
160 // finally, ballance the total energy, without destroying momentum conservation
161 tolerance tol = 0.00001;
162 double p_scale;
163 try {
164 p_scale = (bisect(std::bind(&Suep_shower::reballance_func, this, std::placeholders::_1, event),0.0,2.0, tol)).first;
165 } catch (std::exception &e) {
166 //in some rare circumstances, this balancing might fail
167 std::cout << "[SUEP_SHOWER] WARNING: Failed to rebalance the following event; Printing for debug and throw exception" << std::endl;
168 std::cout << e.what() << std::endl;
169 std::cout << "N. Particle, px, py, pz, E" << std::endl;
170 for (size_t jj=0; jj < event.size(); jj++) {
171 //print out event
172 std::cout << jj << ": " << event[jj].px() << ", " << event[jj].py() << ", " << event[jj].pz() << ", " << event[jj].e() << std::endl;
173 }
174 throw e;
175 }
176
177 for(int n=0;n<len;n++){
178 event[n].px(p_scale*event[n].px());
179 event[n].py(p_scale*event[n].py());
180 event[n].pz(p_scale*event[n].pz());
181 // force the energy with the on-shell condition
182 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)));
183 }
184
185 return event;
186}
#define M_PI
Scalar phi() const
phi method
Scalar theta() const
theta method
static Double_t a
Suep_shower(double mass, double temperature, double energy, Pythia8::Rndm *rndm=0)
Constructor.
double test_fun(double p)
Test function to be solved for p_plus,p_minus.
double m_p_m
convenience function of mass/Temperature ratio
Definition suep_shower.h:83
double fp(double p)
Derivative of Maxwell-Boltzmann.
double m_q_plus
solutions for shower generation.
Definition suep_shower.h:89
double m_p_minus
Definition suep_shower.h:85
Pythia8::Vec4 generateFourVector()
generate one random 4 vector from the thermal distribution
double m_q_minus
Definition suep_shower.h:89
double m_m
Mass of the dark mesons to be generated in the shower.
Definition suep_shower.h:53
Pythia8::Rndm * m_rndmEngine
Random number generator, if not provided will use rand()
Definition suep_shower.h:50
double m_p_plus
solutions for shower generation.
Definition suep_shower.h:85
double f(double p)
Maxwell-Boltzman distribution, slightly massaged.
double m_lambda_minus
Definition suep_shower.h:87
double m_Etot
Total energy of the system.
Definition suep_shower.h:59
double m_Temp
Temperature parameter.
Definition suep_shower.h:56
double m_lambda_plus
solutions in Lambda for shower generation
Definition suep_shower.h:87
std::vector< Pythia8::Vec4 > generate_shower()
Generate a shower event, in the rest frame of the showe.
double m_q_m
Definition suep_shower.h:89
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...
double m_A
mass/Temperature ratio
Definition suep_shower.h:81
Author: James Monk (jmonk@cern.ch)