LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
GPowerSpectrumAtmoFlux.cxx
Go to the documentation of this file.
1 #include <cmath>
2 #include <fstream>
3 
4 #include <TMath.h>
5 #include <TLorentzVector.h>
6 
8 #include "GENIE/Framework/Numerical/RandomGen.h"
9 #include "GENIE/Framework/Conventions/Constants.h"
10 #include "GENIE/Framework/Utils/PrintUtils.h"
11 #include "GENIE/Tools/Flux/GFluxDriverFactory.h"
12 #include "GENIE/Framework/Messenger/Messenger.h"
13 #include "Framework/ParticleData/PDGCodeList.h"
14 #include "Framework/ParticleData/PDGCodes.h"
15 #include "Framework/ParticleData/PDGUtils.h"
16 #include "Framework/ParticleData/PDGLibrary.h"
17 #include "TFile.h"
18 #include "TH3D.h"
19 #include "TH2.h"
20 
22 
23 using namespace genie;
24 using namespace genie::flux;
25 using namespace genie::constants;
26 
28 {
29  LOG("Flux", pNOTICE)
30  << "Instantiating the GENIE Power Spectrum atmospheric neutrino flux driver";
31  this->Initialize();
32 }
33 
34 //________________________________________________________________________________________
35 
36 GPowerSpectrumAtmoFlux::~GPowerSpectrumAtmoFlux()
37 {
38 
39 }
40 
41 
42 //__________________________________________________________________________________________________
43 
44 const PDGCodeList &GPowerSpectrumAtmoFlux::FluxParticles (void)
45 {
46  return *fPdgCList;
47 }
48 
49 //_________________________________________________________________
50 
52 {
53  return fMaxEvCut;
54 }
55 
56 //__________________________________________________________________
57 
59 {
60  return fMinEvCut;
61 }
62 
63 //_________________________________________________________________________
64 
66 {
67  // Reset previously generated neutrino code / 4-p / 4-x
68  this->ResetSelection();
69 
70  // Get a RandomGen instance
71  RandomGen * rnd = RandomGen::Instance();
72 
73  // Generate (Ev, costheta, phi)
74  double Ev = 0.;
75  double costheta = 0.;
76  double phi = 0;
77  double weight = 0;
78  int nu_pdg = 0;
79 
80  // generate events according to a power law spectrum,
81  // then weight events by inverse power law
82  // (note: cannot use index alpha=1)
83  double alpha = fSpectralIndex;
84 
85  double emin = TMath::Power(this->MinEnergy(),1.0-alpha);
86  double emax = TMath::Power(this->MaxEnergy(),1.0-alpha);
87  Ev = TMath::Power(emin+(emax-emin)*rnd->RndFlux().Rndm(),1.0/(1.0-alpha));
88  costheta = -1+2*rnd->RndFlux().Rndm();
89  phi = 2.*kPi* rnd->RndFlux().Rndm();
90 
91  unsigned int nnu = fPdgCList->size();
92  unsigned int inu = rnd->RndFlux().Integer(nnu);
93  nu_pdg = (*fPdgCList)[inu];
94  weight = this->ComputeWeight(nu_pdg, Ev, costheta, phi);
95 
96  // Compute etc trigonometric numbers
97  double sintheta = TMath::Sqrt(1-costheta*costheta);
98  double cosphi = TMath::Cos(phi);
99  double sinphi = TMath::Sin(phi);
100 
101  // Set the neutrino pdg code
102  fgPdgC = nu_pdg;
103 
104  // Set the neutrino weight
105  fWeight = weight;
106 
107  // Compute the neutrino momentum
108  // The `-1' means it is directed towards the detector.
109  double pz = -1.* Ev * costheta;
110  double py = -1.* Ev * sintheta * sinphi;
111  double px = -1.* Ev * sintheta * cosphi;
112 
113  // Default vertex is at the origin
114  double z = 0.0;
115  double y = 0.0;
116  double x = 0.0;
117 
118  // Shift the neutrino position onto the flux generation surface.
119  // The position is computed at the surface of a sphere with R=fRl
120  // at the topocentric horizontal (THZ) coordinate system.
121  if( fRl>0.0 ){
122  z += fRl * costheta;
123  y += fRl * sintheta * sinphi;
124  x += fRl * sintheta * cosphi;
125  }
126 
127  // Apply user-defined rotation from THZ -> user-defined topocentric
128  // coordinate system.
129  if( !fRotTHz2User.IsIdentity() )
130  {
131  TVector3 tx3(x, y, z );
132  TVector3 tp3(px,py,pz);
133 
134  tx3 = fRotTHz2User * tx3;
135  tp3 = fRotTHz2User * tp3;
136 
137  x = tx3.X();
138  y = tx3.Y();
139  z = tx3.Z();
140  px = tp3.X();
141  py = tp3.Y();
142  pz = tp3.Z();
143  }
144 
145  // If the position is left as is, then all generated neutrinos
146  // would point towards the origin.
147  // Displace the position randomly on the surface that is
148  // perpendicular to the selected point P(xo,yo,zo) on the sphere
149  if( fRt>0.0 ){
150  TVector3 vec(x,y,z); // vector towards selected point
151  TVector3 dvec1 = vec.Orthogonal(); // orthogonal vector
152  TVector3 dvec2 = dvec1; // second orthogonal vector
153  dvec2.Rotate(-kPi/2.0,vec); // rotate second vector by 90deg,
154  // now forming a new orthogonal cartesian coordinate system
155  double psi = 2.*kPi* rnd->RndFlux().Rndm(); // rndm angle [0,2pi]
156  double random = rnd->RndFlux().Rndm(); // rndm number [0,1]
157  dvec1.SetMag(TMath::Sqrt(random)*fRt*TMath::Cos(psi));
158  dvec2.SetMag(TMath::Sqrt(random)*fRt*TMath::Sin(psi));
159  x += dvec1.X() + dvec2.X();
160  y += dvec1.Y() + dvec2.Y();
161  z += dvec1.Z() + dvec2.Z();
162  }
163 
164  // Set the neutrino momentum and position 4-vectors with values
165  // calculated at previous steps.
166  fgP4.SetPxPyPzE(px, py, pz, Ev);
167  fgX4.SetXYZT (x, y, z, 0.);
168 
169  // Increment flux neutrino counter used for sample normalization purposes.
170  fNNeutrinos++;
171 
172  // Report and exit
173  LOG("Flux", pINFO)
174  << "Generated neutrino: "
175  << "\n pdg-code: " << fgPdgC
176  << "\n p4: " << utils::print::P4AsShortString(&fgP4)
177  << "\n x4: " << utils::print::X4AsString(&fgX4);
178 
179  return true;
180 }
181 
182 //________________________________________________________________
183 
185 {
186 // initializing running neutrino pdg-code, 4-position, 4-momentum
187 
188  fgPdgC = 0;
189  fgP4.SetPxPyPzE (0.,0.,0.,0.);
190  fgX4.SetXYZT (0.,0.,0.,0.);
191  fWeight = 0;
192 }
193 
194 //________________________________________________________________
195 
197 {
198  return fgPdgC;
199 }
200 
201 //________________________________________________________________
202 
204 {
205  return fWeight;
206 }
207 
208 //________________________________________________________________
209 
210 const TLorentzVector& GPowerSpectrumAtmoFlux::Momentum(void)
211 {
212  return fgP4;
213 }
214 
215 //________________________________________________________________
216 
217 const TLorentzVector& GPowerSpectrumAtmoFlux::Position(void)
218 {
219  return fgX4;
220 }
221 
222 //________________________________________________________________
223 
225 {
226  return false;
227 }
228 
229 //________________________________________________________________
230 
232 {
233  return -1;
234 }
235 
236 //________________________________________________________________
237 
239 {
240  fNNeutrinos = 0;
241 }
242 
243 //________________________________________________________________
244 
245 void GPowerSpectrumAtmoFlux::Clear(Option_t * opt)
246 {
247  LOG("Flux", pWARN) << "GPowerSpectrumAtmoFlux::Clear(" << opt << ") called";
248  this->ResetNFluxNeutrinos();
249 }
250 
251 //________________________________________________________________________
252 
254 {
255 // Dummy clear method needed to conform to GFluxI interface
256 //
257  LOG("Flux", pERROR) <<
258  "The neutrinos are always generated weighted with this implementation!! GenerateWeighted method not implemented.";
259 }
260 
261 //______________________________________________________________________________________________________________________
262 
264 {
265  if( index != 1.0 ){
266  fSpectralIndex = index;
267  this->InitializeWeight(); //Recompute the global weight
268  }
269  else {
270  LOG("Flux", pWARN) << "Warning: cannot use a spectral index of unity";
271  }
272  LOG("Flux", pNOTICE) << "Using Spectral Index = " << index;
273 }
274 
275 //____________________________________________________________________________________
276 
278 {
279  fRotTHz2User = rotation;
280 }
281 
282 //__________________________________________________________________________________
283 
285 {
286  LOG("Flux", pNOTICE) << "Initializing power spectrum atmospheric flux driver";
287 
288  bool allow_dup = false;
289  fPdgCList = new PDGCodeList(allow_dup);
290 
291  fSpectralIndex = 2.0;
292 
293  fMinEvCut = 0.01;
294  fMaxEvCut = 9999999999;
295 
296  // Default radii
297  fRl = 0.0;
298  fRt = 0.0;
299  fAgen = 0.0;
300 
301  // Default detector coord system: Topocentric Horizontal Coordinate system
302  fRotTHz2User.SetToIdentity();
303 
304  // Reset `current' selected flux neutrino
305  this->ResetSelection();
306 
307  // Reset number of neutrinos thrown so far
308  fNNeutrinos = 0;
309 
310  // Init the global gen weight
311  this->InitializeWeight();
312 }
313 
314 //_________________________________________________________________________________
315 
316 void GPowerSpectrumAtmoFlux::SetRadii(double Rlongitudinal, double Rtransverse)
317 {
318  LOG ("Flux", pNOTICE) << "Setting R[longitudinal] = " << Rlongitudinal;
319  LOG ("Flux", pNOTICE) << "Setting R[transverse] = " << Rtransverse;
320 
321  fRl = Rlongitudinal;
322  fRt = Rtransverse;
323 
324  fAgen = kPi*fRt*fRt;
325 }
326 
327 //________________________________________________________________________________
328 
329 void GPowerSpectrumAtmoFlux::SetFlavors(std::vector<int> flavors)
330 {
331  fPdgCList->clear();
332  for(int flavor : flavors){
333  fPdgCList->push_back(flavor);
334  }
335 }
336 
337 //________________________________________________________________________________
338 
340 {
341  LOG("Flux", pNOTICE) << "Cleaning up...";
342 
343  if (fPdgCList) delete fPdgCList;
344 }
345 
346 //________________________________________________________________________________
347 
349 {
350  if(Emin > 0){
351  fMinEvCut = Emin;
352  this->InitializeWeight(); //Recompute the global weight
353  }
354 }
355 
356 //_________________________________________________________________________________
357 
359  fMaxEvCut = Emax;
360  this->InitializeWeight(); //Recompute the global weight
361 }
362 
363 //_________________________________________________________________________________
364 
366 {
367  return fNNeutrinos;
368 }
369 
370 //_________________________________________________________________________________
371 
372 bool GPowerSpectrumAtmoFlux::FillFluxHisto(int nu_pdg, string filename){
373  LOG("Flux", pNOTICE)
374  << "Loading fine grained flux for neutrino: " << nu_pdg
375  << " from file: " << filename;
376 
377  TH3D* histo = nullptr;
378 
379  TFile *f = new TFile(filename.c_str(), "READ");
380  f->GetObject("flux", histo);
381 
382  if(!histo) {
383  LOG("Flux", pERROR) << "Null flux histogram!";
384  f->Close();
385  return false;
386  }
387 
388  TH3D* h = static_cast<TH3D*>(histo->Clone());
389  f->Close();
390 
391  fRawFluxHistoMap.insert(std::make_pair(nu_pdg, h));
392 
393  TH2D* h2 = static_cast<TH2D*>(h->Project3D("yx"));
394 
395  fRawFluxHistoMap2D.insert(std::make_pair(nu_pdg, h2));
396 
397  return true;
398 }
399 
400 //_________________________________________________________________________________
401 
402 void GPowerSpectrumAtmoFlux::AddFluxFile(int nu_pdg, string filename)
403 {
404  // Check file exists
405  std::ifstream f(filename.c_str());
406  if (!f.good()) {
407  LOG("Flux", pFATAL) << "Flux file does not exist "<<filename;
408  exit(-1);
409  }
410  if ( pdg::IsNeutrino(nu_pdg) || pdg::IsAntiNeutrino(nu_pdg) ) {
411  fFluxFlavour.push_back(nu_pdg);
412  fFluxFile.push_back(filename);
413  } else {
414  LOG ("Flux", pWARN)
415  << "Input particle code: " << nu_pdg << " not a neutrino!";
416  }
417 }
418 
419 //_________________________________________________________________________________
420 
422 {
423  LOG("Flux", pNOTICE)
424  << "Loading atmospheric neutrino flux simulation data";
425 
426  fPdgCList->clear();
427 
428  bool loading_status = true;
429 
430  for( unsigned int n=0; n<fFluxFlavour.size(); n++ ){
431  int nu_pdg = fFluxFlavour.at(n);
432  string filename = fFluxFile.at(n);
433  string pname = PDGLibrary::Instance()->Find(nu_pdg)->GetName();
434 
435  LOG("Flux", pNOTICE) << "Loading data for: " << pname;
436 
437  bool loaded = this->FillFluxHisto(nu_pdg, filename);
438 
439  loading_status = loading_status && loaded;
440 
441  if (!loaded) {
442  LOG("Flux", pERROR)
443  << "Error loading atmospheric neutrino flux simulation data from " << filename;
444  break;
445  }
446  }
447 
448  if(loading_status) {
449  map<int,TH3D*>::iterator hist_iter = fRawFluxHistoMap.begin();
450  for ( ; hist_iter != fRawFluxHistoMap.end(); ++hist_iter) {
451  int nu_pdg = hist_iter->first;
452  fPdgCList->push_back(nu_pdg);
453  }
454 
455  LOG("Flux", pNOTICE)
456  << "Atmospheric neutrino flux simulation data loaded!";
457  return true;
458  }
459 
460  LOG("Flux", pERROR)
461  << "Error loading atmospheric neutrino flux simulation data";
462  return false;
463 }
464 
465 
466 //_________________________________________________________________________
467 
468 double GPowerSpectrumAtmoFlux::GetFlux(int flavour, double energy, double costh, double phi)
469 {
470  TH3D* flux_hist = nullptr;
472  if(it != fRawFluxHistoMap.end())
473  {
474  flux_hist = it->second;
475  }
476 
477  LOG("Flux", pERROR) << "flux_hist: " << flux_hist;
478 
479  if(!flux_hist) return 0.0;
480 
481  if(flux_hist->GetZaxis()->GetNbins() == 1){ //no binning in phi, bilinear interpolation only so using the 2D hist
482  TH2D* h2 = fRawFluxHistoMap2D[it->first];
483  return h2->Interpolate(energy, costh);
484  }
485  else {
486  return flux_hist->Interpolate(energy, costh, phi);
487  }
488 }
489 
490 //_________________________________________________________________________
491 
492 double GPowerSpectrumAtmoFlux::ComputeWeight(int flavour, double energy, double costh, double phi)
493 {
494  double flux = this->GetFlux(flavour, energy, costh, phi);
495 
496  return flux*fAgen*fGlobalGenWeight*pow(energy, fSpectralIndex);
497 }
498 
499 //_________________________________________________________________________
500 
502 {
503  double IE = 1.;
504 
505  if(fSpectralIndex!=1){
506  IE = (pow(fMaxEvCut,(1.-fSpectralIndex))-pow(fMinEvCut,(1.-fSpectralIndex)))/(1.-fSpectralIndex);
507  }
508 
509  double ITheta = 4*kPi;
510 
511  fGlobalGenWeight=IE*ITheta;
512 }
Float_t x
Definition: compare.C:6
long int fNNeutrinos
number of flux neutrinos thrown so far
intermediate_table::iterator iterator
long int Index(void) override
returns corresponding index for current flux neutrino (e.g. for a flux ntuple returns the current ent...
double fAgen
current generation area
GENIE neutrino interaction simulation objects.
Definition: GENIE2ART.h:19
map< int, TH3D * > fRawFluxHistoMap
flux = f(Ev,cos8,phi) for each neutrino species
TLorentzVector fgP4
current generated nu 4-momentum
Float_t y
Definition: compare.C:6
const TLorentzVector & Position(void) override
returns the flux neutrino 4-position (note: expect SI rather than physical units) ...
void Initialize()
Definition: errprop.cc:100
Double_t z
Definition: plot.C:276
const PDGCodeList & FluxParticles(void) override
declare list of flux neutrinos that can be generated (for init. purposes)
void GenerateWeighted(bool gen_weighted) override
set whether to generate weighted or unweighted neutrinos
A driver for a power spectrum atmospheric neutrino flux. Elements extensively reused from GAtmoFlux...
int PdgCode(void) override
returns the flux neutrino pdg code
double fSpectralIndex
power law function
bool GenerateNext(void) override
generate the next flux neutrino (return false in err)
double fRl
defining flux neutrino generation surface: longitudinal radius
double fRt
defining flux neutrino generation surface: transverse radius
bool FillFluxHisto(int nu_pdg, string filename)
void SetFlavors(std::vector< int > flavors)
TFile f
Definition: plotHisto.C:6
void AddFluxFile(int neutrino_pdg, string filename)
TRotation fRotTHz2User
coord. system rotation: THZ -> Topocentric user-defined
double ComputeWeight(int flavour, double energy, double costh, double phi)
double fGlobalGenWeight
global generation weight to apply to all events
void Clear(Option_t *opt) override
reset state variables based on opt
double energy
Definition: plottest35.C:25
double fMinEvCut
user-defined cut: minimum energy
double Weight(void) override
returns the flux neutrino weight (if any)
TH1F * h2
Definition: plot.C:44
vector< int > fFluxFlavour
input flux file for each neutrino species
int fgPdgC
current generated nu pdg-code
bool End(void) override
true if no more flux nu&#39;s can be thrown (eg reaching end of beam sim ntuples)
double fWeight
current generated nu weight
double weight
Definition: plottest35.C:25
map< int, TH2D * > fRawFluxHistoMap2D
flux = f(Ev,cos8) for each neutrino species
TLorentzVector fgX4
current generated nu 4-position
double MaxEnergy(void) override
declare the max flux neutrino energy that can be generated (for init. purposes)
PDGCodeList * fPdgCList
input list of neutrino pdg-codes
void SetRadii(double Rlongitudinal, double Rtransverse)
double fMaxEvCut
user-defined cut: maximum energy
vector< string > fFluxFile
input flux file for each neutrino species
Char_t n[5]
const TLorentzVector & Momentum(void) override
returns the flux neutrino 4-momentum
double GetFlux(int flavour, double energy, double costh, double phi)