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#include <functional> // for bind()
8#include <boost/math/tools/roots.hpp>
9
10using namespace boost::math::tools; // For bracket_and_solve_root.
11// using namespace std;
12using namespace Pythia8;
13
14// constructor
15Suep_shower::Suep_shower(double mass, double temperature, double energy, Pythia8::Rndm *rndm) {
16 m_m = mass;
17 m_Temp=temperature;
18 m_Etot=energy;
19 m_rndmEngine = rndm;
20
22 m_p_m=std::sqrt(2/(m_A*m_A)*(1+std::sqrt(1+m_A*m_A)));
23
24 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
25
26 tolerance tol = 0.00001;
27 m_p_plus = (bisect(std::bind(&Suep_shower::test_fun, this, std::placeholders::_1),pmax,50.0, tol)).first; // first root
28 m_p_minus = (bisect(std::bind(&Suep_shower::test_fun, this, std::placeholders::_1), 0.0,pmax, tol)).first; // second root
33 m_q_m = 1- (m_q_plus + m_q_minus);
34
35}
36
37// maxwell-boltzman distribution, slightly massaged
38double Suep_shower::f(double p){
39 return p*p*exp(-m_A*p*p/(1+std::sqrt(1+p*p)));
40}
41
42// derivative of maxwell-boltzmann
43double Suep_shower::fp(double p){
44 return exp(-m_A*p*p/(1+std::sqrt(1+p*p)))*p*(2-m_A*p*p/std::sqrt(1+p*p));
45}
46
47// test function to be solved for m_p_plus, m_p_minus
48double Suep_shower::test_fun(double p){
49 return log(f(p)/f(m_p_m))+1.0;
50}
51
52// generate one random 4 vector from the thermal distribution
54
55 Vec4 fourvec;
56 double en, phi, theta, p;//kinematic variables of the 4 vector
57
58 // first do momentum, following arxiv:1305.5226
59 double U(0.0), V(0.0), X(0.0), Y(0.0), E(0.0);
60 int i=0;
61 while(i<100){
62 if (m_rndmEngine) {
63 U = m_rndmEngine->flat();
64 V = m_rndmEngine->flat();
65 } else {
66 U = ((double) rand() / RAND_MAX);
67 V = ((double) rand() / RAND_MAX);
68 }
69
70 if(U < m_q_m){
71 Y=U/m_q_m;
72 X=( 1 - Y )*( m_p_minus + m_lambda_minus )+Y*( m_p_plus - m_lambda_plus );
73 if(V < f(X) / f(m_p_m) && X>0){
74 break;
75 }
76 }
77 else{if(U < m_q_m + m_q_plus){
78 E = -log((U-m_q_m)/m_q_plus);
79 X = m_p_plus - m_lambda_plus*(1-E);
80 if(V<exp(E)*f(X)/f(m_p_m) && X>0){
81 break;
82 }
83 }
84 else{
85 E = - log((U-(m_q_m+m_q_plus))/m_q_minus);
86 X = m_p_minus + m_lambda_minus * (1 - E);
87 if(V < exp(E)*f(X)/f(m_p_m) && X>0){
88 break;
89 }
90 }
91 }
92 }
93 p=X*(this->m_m); // X is the dimensionless momentum, p/m
94
95 // now do the angles
96 if (m_rndmEngine) {
97 phi = 2.0*M_PI*(m_rndmEngine->flat());
98 theta = acos(2.0*m_rndmEngine->flat()-1.0);
99 } else {
100 //coverity[DC.WEAK_CRYPTO]
101 phi = 2.0*M_PI*((double) rand() / RAND_MAX);
102 //coverity[DC.WEAK_CRYPTO]
103 theta = acos(2.0*((double) rand() / RAND_MAX)-1.0);
104 }
105
106 // compose the 4 vector
107 en = std::sqrt(p*p+(this->m_m)*(this->m_m));
108 //coverity[COPY_PASTE_ERROR]
109 fourvec.p(p*cos(phi)*sin(theta), p*sin(phi)*sin(theta), p*cos(theta), en);
110
111 return fourvec;
112}
113
114// auxiliary function which computes the total energy difference as a function of the momentum vectors and a scale factor "a"
115// to ballance energy, we solve for "a" by demanding that this function vanishes
116// By rescaling the momentum rather than the energy, I avoid having to do these annoying rotations from the previous version
117double Suep_shower::reballance_func(double a, const vector< Vec4 > &event){
118 double result =0.0;
119 double p2;
120 for(unsigned n = 0; n<event.size();n++){
121 p2 = event[n].px()*event[n].px() + event[n].py()*event[n].py() + event[n].pz()*event[n].pz();
122 result += std::sqrt(a*a*p2 + (this->m_m)* (this->m_m));
123 }
124 return result - (this->m_Etot);
125}
126
127// generate a shower event, in the rest frame of the shower
129
130 vector< Vec4 > event;
131 double sum_E = 0.0;
132
133 // fill up event record
134 while(sum_E<(this->m_Etot)){
135 event.push_back(this->generateFourVector());
136 sum_E += (event.back()).e();
137 }
138
139 // reballance momenta
140 int len = event.size();
141 double sum_p, correction;
142 for(int i = 1;i<4;i++){ // loop over 3 carthesian directions
143
144 sum_p = 0.0;
145 for(int n=0;n<len;n++){
146 sum_p+=event[n][i];
147 }
148 correction=-1.0*sum_p/len;
149
150 for(int n=0;n<len;n++){
151 event[n][i] += correction;
152 }
153 }
154
155 //Shield against an exception in the calculation of "p_scale" further down. If it fails, abort the event.
156 if(Suep_shower::reballance_func(2.0,event)<0.0){
157 // failed to balance energy.
158 event.clear();
159 return event;
160 }
161
162 // finally, ballance the total energy, without destroying momentum conservation
163 tolerance tol = 0.00001;
164 double p_scale;
165 try {
166 p_scale = (bisect(std::bind(&Suep_shower::reballance_func, this, std::placeholders::_1, event),0.0,2.0, tol)).first;
167 } catch (std::exception &e) {
168 //in some rare circumstances, this balancing might fail
169 std::cout << "[SUEP_SHOWER] WARNING: Failed to rebalance the following event; Printing for debug and throw exception" << std::endl;
170 std::cout << e.what() << std::endl;
171 std::cout << "N. Particle, px, py, pz, E" << std::endl;
172 for (size_t jj=0; jj < event.size(); jj++) {
173 //print out event
174 std::cout << jj << ": " << event[jj].px() << ", " << event[jj].py() << ", " << event[jj].pz() << ", " << event[jj].e() << std::endl;
175 }
176 throw e;
177 }
178
179 for(int n=0;n<len;n++){
180 event[n].px(p_scale*event[n].px());
181 event[n].py(p_scale*event[n].py());
182 event[n].pz(p_scale*event[n].pz());
183 // force the energy with the on-shell condition
184 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)));
185 }
186
187 return event;
188}
#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:81
double fp(double p)
Derivative of Maxwell-Boltzmann.
double m_q_plus
solutions for shower generation.
Definition suep_shower.h:87
double m_p_minus
Definition suep_shower.h:83
Pythia8::Vec4 generateFourVector()
generate one random 4 vector from the thermal distribution
double m_q_minus
Definition suep_shower.h:87
double m_m
Mass of the dark mesons to be generated in the shower.
Definition suep_shower.h:51
Pythia8::Rndm * m_rndmEngine
Random number generator, if not provided will use rand().
Definition suep_shower.h:48
double m_p_plus
solutions for shower generation.
Definition suep_shower.h:83
double f(double p)
Maxwell-Boltzman distribution, slightly massaged.
double m_lambda_minus
Definition suep_shower.h:85
double m_Etot
Total energy of the system.
Definition suep_shower.h:57
double m_Temp
Temperature parameter.
Definition suep_shower.h:54
double m_lambda_plus
solutions in Lambda for shower generation
Definition suep_shower.h:85
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:87
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:79
Author: James Monk (jmonk@cern.ch).