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 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
112double 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}
#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)