GENIEGenerator
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
NuSmear.h
Go to the documentation of this file.
1 //____________________________________________________________________________
2 /*
3 \name NuSmear smearing system
4 \brief Provides preliminary simulation of energy smearing and angular
5  smearing for neutrino-nucleon interactions via parameterized
6  model-based presets in the DUNE-CDR and Default models.
7 
8  To see the full NuSmear paper, visit:
9  https://inspirehep.net/literature/2150455
10 
11 \author Ishaan Vohra <ivohra@exeter.edu / ishaanklv@gmail.com>
12  Phillips Exeter Academy
13 \created August 16, 2022
14 */
15 //____________________________________________________________________________
16 
17 #include <iostream>
18 #include <string>
19 #include <map>
20 #include <random>
21 #include "GHepParticle.h"
22 #include "PDGCodes.h"
23 #include "TVector3.h"
24 #include "PDGUtils.h"
25 
26 #ifndef _NUSMEAR_H
27 #define _NUSMEAR_H
28 
29 using namespace genie;
30 
31 // DUNE-CDR resolution functions
32 
33 double PiP_Res_duneCdr(double myE, double myKE, double myPmag)
34 {
35  if (myKE >= 0.1)
36  {
37  return 0.15;
38  }
39  else
40  {
41  return -1;
42  }
43 }
44 
45 double PiM_Res_duneCdr(double myE, double myKE, double myPmag)
46 {
47  if (myKE >= 0.1)
48  {
49  return 0.15;
50  }
51  else
52  {
53  return -1;
54  }
55 }
56 
57 double Pi0_Res_duneCdr(double myE, double myKE, double myPmag)
58 {
59  if (myKE >= 0.05)
60  {
61  return pow((pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2)), 0.5);
62  }
63  else
64  {
65  return -1;
66  }
67 }
68 
69 double KP_Res_duneCdr(double myE, double myKE, double myPmag)
70 {
71  if (myKE >= 0.05)
72  {
73  return pow((pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2)), 0.5);
74  }
75  else
76  {
77  return -1;
78  }
79 }
80 
81 double KM_Res_duneCdr(double myE, double myKE, double myPmag)
82 {
83  if (myKE >= 0.05)
84  {
85  return pow(pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2), 0.5);
86  }
87  else
88  {
89  return -1;
90  }
91 }
92 
93 double Gamma_Res_duneCdr(double myE, double myKE, double myPmag)
94 {
95  if (myKE >= 0.03)
96  {
97  return pow(pow(0.02, 2) + pow(0.15 / (pow(myE, 0.5)), 2), 0.5);
98  }
99  else
100  {
101  return -1;
102  }
103 }
104 
105 double Proton_Res_duneCdr(double myE, double myKE, double myPmag)
106 {
107  if (myKE >= 0.05)
108  {
109  if (myPmag < 0.4)
110  {
111  return 0.1;
112  }
113  else
114  {
115  return pow(pow(0.05, 2) + pow(0.3 / (pow(myKE, 0.5)), 2), 0.5);
116  }
117  }
118  else
119  {
120  return -1;
121  }
122 }
123 
124 double Electron_Res_duneCdr(double myE, double myKE, double myPmag)
125 {
126  if (myKE >= 0.03)
127  {
128  return pow(pow(0.02, 2) + pow(0.15 / (pow(myE, 0.5)), 2), 0.5);
129  }
130  else
131  {
132  return -1;
133  }
134 }
135 
136 double Positron_Res_duneCdr(double myE, double myKE, double myPmag)
137 {
138  if (myKE >= 0.03)
139  {
140  return pow(pow(0.02, 2) + pow(0.15 / (pow(myE, 0.5)), 2), 0.5);
141  }
142  else
143  {
144  return -1;
145  }
146 }
147 
148 double Muon_Res_duneCdr(double myE, double myKE, double myPmag)
149 {
150  if (myKE >= 0.03)
151  {
152  return 0.15;
153  }
154  else
155  {
156  return -1;
157  }
158 }
159 
160 double AntiMuon_Res_duneCdr(double myE, double myKE, double myPmag)
161 {
162  if (myKE >= 0.03)
163  {
164  return 0.15;
165  }
166  else
167  {
168  return -1;
169  }
170 }
171 
172 double Neutron_Res_duneCdr(double myE, double myKE, double myPmag)
173 {
174  if (myKE >= 0.05)
175  {
176  return 0.4 / (pow(myKE, 0.5));
177  }
178  else
179  {
180  return -1;
181  }
182 }
183 
184 double K0_Res_duneCdr(double myE, double myKE, double myPmag)
185 {
186  if (myKE >= 0.05)
187  {
188  return pow((pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2)), 0.5);
189  }
190  else
191  {
192  return -1;
193  }
194 }
195 
196 double AntiK0_Res_duneCdr(double myE, double myKE, double myPmag)
197 {
198  if (myKE >= 0.05)
199  {
200  return pow((pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2)), 0.5);
201  }
202  else
203  {
204  return -1;
205  }
206 }
207 
208 double Lambda_Res_duneCdr(double myE, double myKE, double myPmag)
209 {
210  if (myKE >= 0.05)
211  {
212  return pow((pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2)), 0.5);
213  }
214  else
215  {
216  return -1;
217  }
218 }
219 
220 double SigmaP_Res_duneCdr(double myE, double myKE, double myPmag)
221 {
222  if (myKE >= 0.05)
223  {
224  return pow((pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2)), 0.5);
225  }
226  else
227  {
228  return -1;
229  }
230 }
231 
232 double Sigma0_Res_duneCdr(double myE, double myKE, double myPmag)
233 {
234  if (myKE >= 0.05)
235  {
236  return pow((pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2)), 0.5);
237  }
238  else
239  {
240  return -1;
241  }
242 }
243 
244 double SigmaM_Res_duneCdr(double myE, double myKE, double myPmag)
245 {
246  if (myKE >= 0.05)
247  {
248  return pow((pow(0.05, 2) + pow((0.3 / (pow(myE, 0.5))), 2)), 0.5);
249  }
250  else
251  {
252  return -1;
253  }
254 }
255 
256 // Mersenne twister pseudo-random number generation
257 
258 std::random_device rd;
259 std::mt19937 gen(rd());
260 
261 // Energy smearing function
262 
263 double smearE(int myPdg, double myE, double myKE, double myPx, double myPy, double myPz, std::string model)
264 {
265  std::map<int, int> myMap;
266 
267  myMap[kPdgPiP] = 0;
268  myMap[kPdgPiM] = 1;
269  myMap[kPdgPi0] = 2;
270  myMap[kPdgKP] = 3;
271  myMap[kPdgKM] = 4;
272  myMap[kPdgGamma] = 5;
273  myMap[kPdgProton] = 6;
274  myMap[kPdgElectron] = 7;
275  myMap[kPdgPositron] = 8;
276  myMap[kPdgMuon] = 9;
277  myMap[kPdgAntiMuon] = 10;
278  myMap[kPdgNeutron] = 11;
279  myMap[kPdgK0] = 12;
280  myMap[kPdgAntiK0] = 13;
281  myMap[kPdgLambda] = 14;
282  myMap[kPdgSigmaP] = 15;
283  myMap[kPdgSigma0] = 16;
284  myMap[kPdgSigmaM] = 17;
285 
286  TVector3 P(myPx, myPy, myPz);
287  TVector3 Z(0, 0, 1);
288  double myPmag = P.Mag();
289 
290  int in = myMap.find(myPdg)->second;
291 
292  if (model == "duneCdr")
293  {
294 
295  double (*resolution_ptr_duneCdr[18])(double, double, double) = {
314 
315  double resolution = (*resolution_ptr_duneCdr[in])(myE, myKE, myPmag);
316 
317  if (resolution == -1)
318  {
319  return 0;
320  }
321  else
322  {
323  double var = 0;
324  double eSq = 0;
325 
326  if (pdg::IsNeutronOrProton(myPdg))
327  {
328  var += pow((resolution * myKE), 2);
329  eSq += pow(myKE, 2);
330  }
331  else
332  {
333  var += pow((resolution * myE), 2);
334  eSq += pow(myE, 2);
335  }
336 
337  double m = log(eSq / (pow(var + eSq, 0.5)));
338  double s = pow(log(1 + (var / eSq)), 0.5);
339 
340  std::lognormal_distribution<double> distLognorm(m, s);
341 
342  if (myPdg == kPdgNeutron)
343  {
344  if (myPmag < 1)
345  {
346  std::uniform_real_distribution<double> distUni(0, 1);
347 
348  if (distUni(gen) < 0.1)
349  {
350  return 0;
351  }
352  else
353  {
354  return 0.6 * (distLognorm(gen));
355  }
356  }
357  else
358  {
359  return 0.6 * (distLognorm(gen));
360  }
361  }
362  else
363  {
364  return distLognorm(gen);
365  }
366  }
367  }
368 
369  // Default model resolutions and particle detection dependencies
370 
371  else if (model == "default")
372  {
373  double info[18][2] = {
374 
375  {0.15, 1},
376  {0.15, 1},
377  {0.15, 1},
378  {0.2, 1},
379  {0.2, 1},
380  {0.3, 0.5},
381  {0.4, 1},
382  {0.4, 1},
383  {0.4, 1},
384  {0.15, 1},
385  {0.15, 1},
386  {0.5, 0.5},
387  {0.2, 1},
388  {0.2, 1},
389  {0.3, 1},
390  {0.3, 1},
391  {0.3, 1},
392  {0.3, 1}};
393 
394  double resolution = info[in][0];
395  double chanceToSee = info[in][1];
396  double var = 0;
397  double eSq = 0;
398 
399  if (pdg::IsNeutronOrProton(myPdg))
400  {
401  var += pow((resolution * myKE), 2);
402  eSq += pow(myKE, 2);
403  }
404  else
405  {
406  var += pow((resolution * myE), 2);
407  eSq += pow(myE, 2);
408  }
409 
410  double m = log(eSq / (pow(var + eSq, 0.5)));
411  double s = pow(log(1 + (var / eSq)), 0.5);
412 
413  std::lognormal_distribution<double> distLognorm(m, s);
414  std::uniform_real_distribution<double> distUni(0, 1);
415 
416  if (distUni(gen) < chanceToSee)
417  {
418  if (myKE > 0.05)
419  {
420  return distLognorm(gen);
421  }
422  else
423  {
424  return 0;
425  }
426  }
427  else
428  {
429  return 0;
430  }
431  }
432  else
433  {
434  std::cout << "Error: Resolution model not found./n";
435  }
436 }
437 
438 // Angular smearing function
439 
440 double smearA(int myPdg, double myPx, double myPy, double myPz, std::string model)
441 {
442  std::map<int, int> myMap;
443 
444  myMap[kPdgPiP] = 0;
445  myMap[kPdgPiM] = 1;
446  myMap[kPdgPi0] = 2;
447  myMap[kPdgKP] = 3;
448  myMap[kPdgKM] = 4;
449  myMap[kPdgGamma] = 5;
450  myMap[kPdgProton] = 6;
451  myMap[kPdgElectron] = 7;
452  myMap[kPdgPositron] = 8;
453  myMap[kPdgMuon] = 9;
454  myMap[kPdgAntiMuon] = 10;
455  myMap[kPdgNeutron] = 11;
456  myMap[kPdgK0] = 12;
457  myMap[kPdgAntiK0] = 13;
458  myMap[kPdgLambda] = 14;
459  myMap[kPdgSigmaP] = 15;
460  myMap[kPdgSigma0] = 16;
461  myMap[kPdgSigmaM] = 17;
462 
463  TVector3 P(myPx, myPy, myPz);
464  TVector3 Z(0, 0, 1);
465  double theta = (P.Angle(Z)) / M_PI * 180;
466 
467  int in = myMap.find(myPdg)->second;
468 
469  // DUNE-CDR and Default angular smearing values
470 
471  double angularResDeg_DuneCdr[18] = {
472  1,
473  1,
474  5,
475  5,
476  5,
477  1,
478  5,
479  1,
480  1,
481  1,
482  1,
483  5,
484  5,
485  5,
486  5,
487  5,
488  5,
489  5};
490 
491  double angularResDeg_Default[18] = {
492  2,
493  2,
494  8,
495  2,
496  2,
497  3,
498  8,
499  2,
500  2,
501  2,
502  2,
503  10,
504  8,
505  8,
506  8,
507  8,
508  8,
509  8};
510 
511  double resolution = 0;
512 
513  if (model == "duneCdr")
514  {
515  resolution += (angularResDeg_DuneCdr[in]);
516  }
517  else if (model == "default")
518  {
519  resolution += (angularResDeg_Default[in]);
520  }
521 
522  std::normal_distribution<double> distNorm(theta, resolution);
523  return distNorm(gen);
524 }
525 
526 #endif
double Gamma_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:93
double smearE(int myPdg, double myE, double myKE, double myPx, double myPy, double myPz, std::string model)
Definition: NuSmear.h:263
double Proton_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:105
const int kPdgLambda
Definition: PDGCodes.h:85
double AntiMuon_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:160
double Electron_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:124
static constexpr double s
Definition: Units.h:95
const int kPdgAntiMuon
Definition: PDGCodes.h:38
double K0_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:184
const int kPdgSigma0
Definition: PDGCodes.h:88
std::mt19937 gen(rd())
std::random_device rd
Definition: NuSmear.h:258
double Sigma0_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:232
const int kPdgElectron
Definition: PDGCodes.h:35
double KP_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:69
const int kPdgK0
Definition: PDGCodes.h:174
double AntiK0_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:196
double SigmaM_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:244
double Positron_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:136
const int kPdgKM
Definition: PDGCodes.h:173
double smearA(int myPdg, double myPx, double myPy, double myPz, std::string model)
Definition: NuSmear.h:440
const int kPdgGamma
Definition: PDGCodes.h:189
const int kPdgKP
Definition: PDGCodes.h:172
const int kPdgPiP
Definition: PDGCodes.h:158
const int kPdgPi0
Definition: PDGCodes.h:160
double SigmaP_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:220
double Pi0_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:57
const int kPdgAntiK0
Definition: PDGCodes.h:175
double PiP_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:33
double Lambda_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:208
const int kPdgSigmaM
Definition: PDGCodes.h:89
double Neutron_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:172
bool IsNeutronOrProton(int pdgc)
Definition: PDGUtils.cxx:351
const int kPdgPiM
Definition: PDGCodes.h:159
const int kPdgSigmaP
Definition: PDGCodes.h:87
const int kPdgProton
Definition: PDGCodes.h:81
double PiM_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:45
double Muon_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:148
const int kPdgMuon
Definition: PDGCodes.h:37
const int kPdgPositron
Definition: PDGCodes.h:36
const int kPdgNeutron
Definition: PDGCodes.h:83
static constexpr double m
Definition: Units.h:71
Most commonly used PDG codes. A set of utility functions to handle PDG codes is provided in PDGUtils...
double KM_Res_duneCdr(double myE, double myKE, double myPmag)
Definition: NuSmear.h:81