LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
GaisserParam_module.cc
Go to the documentation of this file.
1 #ifndef EVGEN_GAISSERPARAM
13 #define EVGEN_GAISSERPARAM
14 
15 // C++ includes.
16 #include <iostream>
17 #include <sstream>
18 #include <string>
19 #include <cmath>
20 #include <memory>
21 #include <iterator>
22 #include <vector>
23 #include <utility>
24 #include <sys/stat.h>
25 #include <exception>
26 #include <map>
27 #include <vector>
28 #include <algorithm>
29 
30 // Framework includes
33 #include "fhiclcpp/ParameterSet.h"
41 #include "cetlib_except/exception.h"
42 
43 // art extensions
45 
46 // nutools includes
50 
51 // lar includes
54 
55 #include "TVector3.h"
56 #include "TDatabasePDG.h"
57 #include "TMath.h"
58 #include "TF2.h"
59 #include "TH1.h"
60 #include "TString.h"
61 #include "TFile.h"
62 #include "TAxis.h"
63 #include "TTree.h"
64 
65 #include "CLHEP/Random/RandFlat.h"
66 #include "CLHEP/Random/RandGaussQ.h"
67 
68 
69 namespace simb { class MCTruth; }
70 
71 namespace evgen {
72 
74  class GaisserParam : public art::EDProducer {
75 
76  public:
77  explicit GaisserParam(fhicl::ParameterSet const& pset);
78  virtual ~GaisserParam();
79 
80  // This is called for each event.
81  void produce(art::Event& evt);
82  void beginJob();
83  void beginRun(art::Run& run);
84  void reconfigure(fhicl::ParameterSet const& p);
85 
86  // Defining public maps.......
87  typedef std::map<double, TH1*> dhist_Map;
89  TFile* m_File;
90  dhist_Map* m_PDFmap;
91  TH1* m_thetaHist;
92 
93  private:
94 
95  void SampleOne(unsigned int i, simb::MCTruth &mct);
96  void Sample(simb::MCTruth &mct);
97 
98  std::pair<double,double> GetThetaAndEnergy(double rand1, double rand2);
99  void MakePDF();
100  void ResetMap();
101  double GaisserMuonFlux_Integrand(Double_t *x, Double_t *par);
102  double GaisserFlux(double e, double theta);
103  std::vector<double> GetBinning(const TAxis* axis, bool finalEdge=true);
104 
105 
106  static const int kGAUS = 1;
107 
108  int fMode;
109  bool fPadOutVectors;
112  std::vector<int> fPDG;
116  int fCharge;
117  std::string fInputDir;
118 
119  double fEmin;
120  double fEmax;
121  double fEmid;
122  int fEBinsLow;
124 
125  double fThetamin;
126  double fThetamax;
128 
129  double fXHalfRange;
130  double fYInput;
131  double fZHalfRange;
132 
133  double fT0;
134  double fSigmaT;
135  int fTDist;
136 
137  bool fSetParam;
138  bool fSetRead;
139  bool fSetWrite;
140  bool fSetReWrite;
141  double fEpsilon;
142 
143  //Define TFS histograms.....
144  /*
145  TH1D* fPositionX;
146  TH1D* fPositionY;
147  TH1D* fPositionZ;
148  TH1D* fTime;
149  TH1D* fMomentumHigh;
150  TH1D* fMomentum;
151  TH1D* fEnergy;
152  TH1D* fDirCosineX;
153  TH1D* fDirCosineY;
154  TH1D* fDirCosineZ;
155  TH1D* fTheta;
156  TH1D* fPhi;
157  */
158  //Define some variables....
159  double fCryoBoundaries[6];
160  double xNeg = 0;
161  double xPos = 0;
162  double zNeg = 0;
163  double zPos = 0;
164  double fCenterX= 0;
165  double fCenterZ= 0;
166 
167  // TTree
168  TTree* fTree;
169  double Time, Momentum, KinEnergy, Gamma, Energy, Theta, Phi, pnorm;
170  double XPosition, YPosition, ZPosition, DirCosineX, DirCosineY, DirCosineZ;
171  };
172 }
173 
174 namespace evgen{
175 
176  //____________________________________________________________________________
177  GaisserParam::GaisserParam(fhicl::ParameterSet const& pset)
178  {
179  this->reconfigure(pset);
180 
181  // create a default random engine; obtain the random seed from NuRandomService,
182  // unless overridden in configuration with key "Seed"
184  ->createEngine(*this, pset, "Seed");
185 
186  produces< std::vector<simb::MCTruth> >();
187  produces< sumdata::RunData, art::InRun >();
188  }
189 
190  //____________________________________________________________________________
191  GaisserParam::~GaisserParam()
192  {
193  }
194 
195  //____________________________________________________________________________
196  void GaisserParam::reconfigure(fhicl::ParameterSet const& p)
197  {
198  // do not put seed in reconfigure because we don't want to reset
199  // the seed midstream
200 
201  fPadOutVectors = p.get< bool >("PadOutVectors");
202  fMode = p.get< int >("ParticleSelectionMode");
203  fPDG = p.get< std::vector<int> >("PDG");
204 
205  fCharge = p.get< int >("Charge");
206  fInputDir = p.get< std::string >("InputDir");
207 
208  fEmin = p.get< double >("Emin");
209  fEmax = p.get< double >("Emax");
210  fEmid = p.get< double >("Emid");
211  fEBinsLow = p.get< int >("EBinsLow");
212  fEBinsHigh = p.get< int >("EBinsHigh");
213 
214  fThetamin = p.get< double >("Thetamin");
215  fThetamax = p.get< double >("Thetamax");
216  fThetaBins = p.get< int >("ThetaBins");
217 
218  fXHalfRange = p.get< double >("XHalfRange");
219  fYInput = p.get< double >("YInput");
220  fZHalfRange = p.get< double >("ZHalfRange");
221 
222  fT0 = p.get< double >("T0");
223  fSigmaT = p.get< double >("SigmaT");
224  fTDist = p.get< int >("TDist");
225 
226  fSetParam = p.get< bool >("SetParam");
227  fSetRead = p.get< bool >("SetRead");
228  fSetWrite = p.get< bool >("SetWrite");
229  fSetReWrite = p.get< bool >("SetReWrite");
230  fEpsilon = p.get< double >("Epsilon");
231 
232  return;
233  }
234 
235  //____________________________________________________________________________
237  {
238  //Work out center of cryostat(s)
240  for (unsigned int i=0; i < geom->Ncryostats() ; i++ ) {
241  geom->CryostatBoundaries(fCryoBoundaries, i);
242  if ( xNeg > fCryoBoundaries[0] ) xNeg = fCryoBoundaries[0];
243  if ( xPos < fCryoBoundaries[1] ) xPos = fCryoBoundaries[1];
244  if ( zNeg > fCryoBoundaries[4] ) zNeg = fCryoBoundaries[4];
245  if ( zPos < fCryoBoundaries[5] ) zPos = fCryoBoundaries[5];
246  }
247  fCenterX = xNeg + (xPos-xNeg)/2;
248  fCenterZ = zNeg + (zPos-zNeg)/2;
249 
250  // Make the Histograms....
252  /*
253  fPositionX = tfs->make<TH1D>("fPositionX" ,"Position (cm)" ,500,fCenterX-(fXHalfRange+10) ,fCenterX+(fXHalfRange+10));
254  fPositionY = tfs->make<TH1D>("fPositionY" ,"Position (cm)" ,500,-(fYInput+10),(fYInput+10));
255  fPositionZ = tfs->make<TH1D>("fPositionZ" ,"Position (cm)" ,500,fCenterZ-(fZHalfRange+10) ,fCenterZ+(fZHalfRange+10));
256  fTime = tfs->make<TH1D>("fTime" ,"Time (s)" ,500,0,1e6);
257  fMomentumHigh = tfs->make<TH1D>("fMomentumHigh","Momentum (GeV)",500,0,fEmax);
258  fMomentum = tfs->make<TH1D>("fMomentum" ,"Momentum (GeV)",500,0,100);
259  fEnergy = tfs->make<TH1D>("fEnergy" ,"Energy (GeV)" ,500,0,fEmax);
260 
261  fDirCosineX = tfs->make<TH1D>("fDirCosineX","Normalised Direction cosine",500,-1,1);
262  fDirCosineY = tfs->make<TH1D>("fDirCosineY","Normalised Direction cosine",500,-1,1);
263  fDirCosineZ = tfs->make<TH1D>("fDirCosineZ","Normalised Direction cosine",500,-1,1);
264 
265  fTheta = tfs->make<TH1D>("fTheta" ,"Angle (radians)",500,-365,365);
266  fPhi = tfs->make<TH1D>("fPhi" ,"Angle (radians)",500,-365,365);
267  */
268  fTree = tfs->make<TTree>("Generator","analysis tree");
269  fTree->Branch("XPosition" ,&XPosition ,"XPosition/D" );
270  fTree->Branch("YPosition" ,&YPosition ,"YPosition/D" );
271  fTree->Branch("ZPosition" ,&ZPosition ,"ZPosition/D" );
272  fTree->Branch("Time" ,&Time ,"Time/D" );
273  fTree->Branch("Momentum" ,&Momentum ,"Momentum/D" );
274  fTree->Branch("KinEnergy" ,&KinEnergy ,"KinEnergy/D" );
275  fTree->Branch("Energy" ,&Energy ,"Energy/D" );
276  fTree->Branch("DirCosineX",&DirCosineX,"DirCosineX/D");
277  fTree->Branch("DirCosineY",&DirCosineY,"DirCosineY/D");
278  fTree->Branch("DirCosineZ",&DirCosineZ,"DirCosineZ/D");
279  fTree->Branch("Theta" ,&Theta ,"Theta/D" );
280  fTree->Branch("Phi" ,&Phi ,"Phi/D" );
281  }
282 
283  //____________________________________________________________________________
284  void GaisserParam::beginRun(art::Run& run)
285  {
286  // grab the geometry object to see what geometry we are using
288  std::unique_ptr<sumdata::RunData> runcol(new sumdata::RunData(geo->DetectorName()));
289 
290  // Check fcl parameters were set correctly
291  if ( fThetamax > M_PI/2 + 0.01 ) throw cet::exception("GaisserParam")<< "\nThetamax has to be less than " << M_PI/2 << ", but was entered as " << fThetamax << ", this cause an error so leaving program now...\n\n";
292  if ( fThetamin < 0 ) throw cet::exception("GaisserParam")<< "\nThetamin has to be more than 0, but was entered as " << fThetamin << ", this cause an error so leaving program now...\n\n" << std::endl;
293  if ( fThetamax < fThetamin ) throw cet::exception("GaisserParam")<< "\nMinimum angle is bigger than maximum angle....causes an error so leaving program now....\n\n" << std::endl;
294 
295  run.put(std::move(runcol));
296  MakePDF ();
297 
298  return;
299  }
300 
301  //____________________________________________________________________________
302  void GaisserParam::produce(art::Event& evt)
303  {
305  std::unique_ptr< std::vector<simb::MCTruth> > truthcol(new std::vector<simb::MCTruth>);
306 
307  simb::MCTruth truth;
309 
310  Sample(truth);
311 
312  LOG_DEBUG("GaisserParam") << truth;
313 
314  truthcol->push_back(truth);
315 
316  evt.put(std::move(truthcol));
317 
318  return;
319  }
320 
321  //____________________________________________________________________________
322  // Draw the type, momentum and position of a single particle from the
323  // FCIHL description
324  void GaisserParam::SampleOne(unsigned int i, simb::MCTruth &mct){
325 
326  // get the random number generator service and make some CLHEP generators
328  CLHEP::HepRandomEngine &engine = rng->getEngine();
329  CLHEP::RandFlat flat(engine);
330  CLHEP::RandGaussQ gauss(engine);
331 
332  Time = Momentum = KinEnergy = Gamma = Energy = Theta = Phi = pnorm = 0.0;
333  XPosition = YPosition = ZPosition = DirCosineX = DirCosineY = DirCosineZ = 0.0;
334 
335  TVector3 x;
336  TVector3 pmom;
337 
338  // set track id to -i as these are all primary particles and have id <= 0
339  int trackid = -1*(i+1);
340  std::string primary("primary");
341 
342  // Work out whether particle/antiparticle, and mass...
343  double m =0.0;
344  fPDG[i] = 13;
345  if (fCharge == 0 ) {
346  if(1.0-2.0*flat.fire() > 0) fPDG[i]=-fPDG[i];
347  }
348  else if ( fCharge == 1 ) fPDG[i] = 13;
349  else if ( fCharge == 2 ) fPDG[i] = -13;
350  static TDatabasePDG pdgt;
351  TParticlePDG* pdgp = pdgt.GetParticle(fPDG[i]);
352  if (pdgp) m = pdgp->Mass();
353 
354  // Work out T0...
355  if(fTDist==kGAUS){
356  Time = gauss.fire(fT0, fSigmaT);
357  }
358  else {
359  Time = fT0 + fSigmaT*(2.0*flat.fire()-1.0);
360  }
361 
362  // Work out Positioning.....
363  x[0] = (1.0 - 2.0*flat.fire())*fXHalfRange + fCenterX;
364  x[1] = fYInput;
365  x[2] = (1.0 - 2.0*flat.fire())*fZHalfRange + fCenterZ;
366 
367  // Make Lorentz vector for x and t....
368  TLorentzVector pos(x[0], x[1], x[2], Time);
369 
370  // Access the pdf map which has been loaded.....
371  if(m_PDFmap) {
372 
373  //---- get the muon theta and energy from histograms using 2 random numbers
374  std::pair<double,double> theta_energy; //---- muon theta and energy
375  theta_energy = GetThetaAndEnergy(flat.fire(),flat.fire());
376 
377  //---- Set theta, phi
378  Theta = theta_energy.first; // Angle returned by GetThetaAndEnergy between 0 and pi/2
379  Phi = M_PI*( 1.0-2.0*flat.fire() ); // Randomly generated angle between -pi and pi
380 
381  //---- Set KE, E, p
382  KinEnergy = theta_energy.second; // Energy returned by GetThetaAndEnergy
383  Gamma = 1 + (KinEnergy/m);
384  Energy = Gamma * m;
385  Momentum = std::sqrt(Energy*Energy-m*m); // Get momentum
386 
387  pmom[0] = Momentum*std::sin(Theta)*std::cos(Phi);
388  pmom[1] = -Momentum*std::cos(Theta);
389  pmom[2] = Momentum*std::sin(Theta)*std::sin(Phi);
390 
391  pnorm = std::sqrt( pmom[0]*pmom[0] + pmom[1]*pmom[1] + pmom[2]*pmom[2] );
392  DirCosineX = pmom[0] / pnorm;
393  DirCosineY = pmom[1] / pnorm;
394  DirCosineZ = pmom[2] / pnorm;
395  }
396  else {
397  std::cout << "MuFlux map hasn't been initialised, aborting...." << std::endl;
398  return;
399  }
400 
401  TLorentzVector pvec(pmom[0], pmom[1], pmom[2], Energy );
402 
403  simb::MCParticle part(trackid, fPDG[i], primary);
404  part.AddTrajectoryPoint(pos, pvec);
405  /*
406  fTree->Branch();
407  fTree->Branch();
408  fTree->Branch();
409  fPositionX ->Fill (x[0]);
410  fPositionY ->Fill (x[1]);
411  fPositionZ ->Fill (x[2]);
412  fTime ->Fill (Time);
413  fMomentumHigh ->Fill (Momentum);
414  fMomentum ->Fill (Momentum);
415  fEnergy ->Fill (Energy);
416  fDirCosineX ->Fill (DirCosineX);
417  fDirCosineY ->Fill (DirCosineY);
418  fDirCosineZ ->Fill (DirCosineZ);
419  fTheta ->Fill (Theta*180/M_PI);
420  fPhi ->Fill (Phi *180/M_PI);
421  */
422  XPosition = x[0];
423  YPosition = x[1];
424  ZPosition = x[2];
425 
426  std::cout << "Theta: " << Theta << " Phi: " << Phi << " KineticEnergy: " << KinEnergy << " Energy: " << Energy << " Momentum: " << Momentum << std::endl;
427  std::cout << "x: " << pos.X() << " y: " << pos.Y() << " z: " << pos.Z() << " time: " << pos.T() << std::endl;
428  std::cout << "Px: " << pvec.Px() << " Py: " << pvec.Py() << " Pz: " << pvec.Pz() << std::endl;
429  std::cout << "Normalised..." << DirCosineX << " " << DirCosineY << " " << DirCosineZ << std::endl;
430 
431  fTree->Fill();
432  mct.Add(part);
433  }
434 
435  //____________________________________________________________________________
436  void GaisserParam::Sample(simb::MCTruth &mct)
437  {
438  switch (fMode) {
439  case 0: // List generation mode: every event will have one of each
440  // particle species in the fPDG array
441  for (unsigned int i=0; i<fPDG.size(); ++i) {
442  SampleOne(i,mct);
443  }//end loop over particles
444  break;
445  case 1: // Random selection mode: every event will exactly one particle
446  // selected randomly from the fPDG array
447  {
449  CLHEP::HepRandomEngine &engine = rng->getEngine();
450  CLHEP::RandFlat flat(engine);
451 
452  unsigned int i=flat.fireInt(fPDG.size());
453  SampleOne(i,mct);
454  }
455  break;
456  default:
457  mf::LogWarning("UnrecognizeOption") << "GaisserParam does not recognize ParticleSelectionMode "
458  << fMode;
459  break;
460  } // switch on fMode
461 
462  return;
463  }
464 
465  //__________________________________
466  std::pair<double,double> GaisserParam::GetThetaAndEnergy(double rand1, double rand2)
467  {
468  if(rand1 < 0 || rand1 > 1) std::cerr << "GetThetaAndEnergy:\tInvalid random number " << rand1 << std::endl;
469  if(rand2 < 0 || rand2 > 1) std::cerr << "GetThetaAndEnergy:\tInvalid random number " << rand2 << std::endl;
470 
471  int thetaBin = 0;
472  m_thetaHist->GetBinWithContent(double(rand1),thetaBin,1,m_thetaHist->GetNbinsX(),1.0);
473  if(m_thetaHist->GetBinContent(thetaBin) < rand1) thetaBin += 1;
474  double drand1 = (m_thetaHist->GetBinContent(thetaBin) - rand1)/(m_thetaHist->GetBinContent(thetaBin) - m_thetaHist->GetBinContent(thetaBin-1));
475  double thetaLow = m_thetaHist->GetXaxis()->GetBinLowEdge(thetaBin);
476  double thetaUp = m_thetaHist->GetXaxis()->GetBinUpEdge(thetaBin);
477  double theta = drand1*(thetaUp-thetaLow) + thetaLow;
478 
479  int energyBin = 0;
480  TH1* energyHist = 0;
481  bool notFound = true;
482  for(dhist_Map_it mapit=m_PDFmap->begin(); mapit!=m_PDFmap->end(); mapit++){
483  if( fabs(mapit->first+thetaLow)<0.000001 ) {
484  energyHist = mapit->second;
485  notFound = false;
486  break;
487  }
488  }
489  if(notFound) std::cout << "GetThetaAndEnergy: ERROR:\tInvalid theta!" << std::endl;
490  // MSG("string = " << To_TString(thetaLow) << ", double = " << thetaLow );
491 
492  energyHist->GetBinWithContent(double(rand2),energyBin,1,energyHist->GetNbinsX(),1.0);
493  if(energyHist->GetBinContent(energyBin) < rand2) energyBin += 1;
494  double drand2 = (energyHist->GetBinContent(energyBin) - rand2)/(energyHist->GetBinContent(energyBin) - energyHist->GetBinContent(energyBin-1));
495  double energyLow = energyHist->GetXaxis()->GetBinLowEdge(energyBin);
496  double energyUp = energyHist->GetXaxis()->GetBinUpEdge(energyBin);
497  double energy = drand2*(energyUp-energyLow) + energyLow;
498  // MSG("MuFlux::GetThetaEnergy()\te = " << energy*1000. );
499 
500  return std::make_pair(theta,energy);
501  }
502 
503  //____________________________________________________________________________
504  void GaisserParam::MakePDF()
505  {
506  std::cout << "In my function MakePDF" << std::endl;
507  m_File=0;
508  m_PDFmap=0;
509  m_thetaHist=0;
510  double TotalMuonFlux=0;
511 
512  if(m_PDFmap){
513  std::cout << "PDFMAP" << std::endl;
514  if(m_PDFmap->size()>0 && !fSetReWrite){
515  std::cout << "MakePDF: Map has already been initialised. " << std::endl;
516  std::cout << "Do fSetReWrite - true if you really want to override this map." << std::endl;
517  return;
518  }
519  std::cout << fSetReWrite << std::endl;
520  if(fSetReWrite) ResetMap();
521  }
522  else{
523  m_PDFmap = new dhist_Map;
524  std::cout << "Making new dhist_Map called m_PDFmap....." << std::endl;
525  }
526 
527  TF2* muonSpec = new TF2("muonSpec", this,
529  fEmin, fEmax, fThetamin, fThetamax, 0,
530  "GaisserParam", "GaisserMuonFlux_Integrand"
531  );
532  //--------------------------------------------
533  //------------ Compute the pdfs
534 
535  //---- compute pdf for the theta
536  TotalMuonFlux = muonSpec->Integral(fEmin, fEmax, fThetamin, fThetamax, fEpsilon ); // Work out the muon flux at the surface
537  std::cout << "Surface flux of muons = " << TotalMuonFlux << " cm-2 s-1" << std::endl;
538 
539  //---- work out if we're reading a file, writing to file, or neither
540  std::ostringstream pdfFile;
541  pdfFile << "GaisserPDF_"<<fEmin<<"-"<<fEmid<<"-"<<fEmax<<"-"<< fEBinsLow<<"-"<<fEBinsHigh<<"-"<<fThetamin<<"-"<<fThetamax<<"-"<<fThetaBins<<".root";
542  std::string tmpfileName = pdfFile.str();
543  std::replace(tmpfileName.begin(),tmpfileName.end(),'+','0');
544  if (tmpfileName == "GaisserPDF_0-100-100100-1000-10000-0-1.5708-100.root") tmpfileName = "GaisserPDF_DefaultBins.root";
545  else if (tmpfileName == "GaisserPDF_0-100-4000-1000-1000-0-1.5708-100.root") tmpfileName = "GaisserPDF_LowEnergy.root";
546  else if (tmpfileName == "GaisserPDF_4000-10000-100000-1000-10000-0-1.5708-100.root") tmpfileName = "GaisserPDF_MidEnergy.root";
547  else if (tmpfileName == "GaisserPDF_100000-500000-1e007-10000-100000-0-1.5708-100.root") tmpfileName = "GaisserPDF_HighEnergy.root";
548 
549  std::ostringstream pdfFilePath;
550  pdfFilePath << fInputDir << tmpfileName;
551  std::string fileName = pdfFilePath.str();
552 
553  // fTemplateFile = pset.get< std::string >("TemplateFile");
554  // //fCalorimetryModuleLabel = pset.get< std::string >("CalorimetryModuleLabel");
555 
556  cet::search_path sp("FW_SEARCH_PATH");
557  std::string fROOTfile; //return /lbne/data/0-100-1.57.root
558  if( sp.find_file(tmpfileName, fROOTfile) ) fileName = fROOTfile;
559 
560  std::cout << "File path; " << fileName << std::endl;
561 
562  if(fSetRead){
563  struct stat buffer;
564  fSetRead = stat(fileName.c_str(), &buffer) == 0; // Check if file exists already
565  if(!fSetRead) std::cout << "WARNING- "+fileName+" does not exist." << std::endl;
566  else{
567  std::cout << "Reading PDF from file "+fileName << std::endl;
568  m_File = new TFile(fileName.c_str()); // Open file
569  if(m_File->IsZombie() || m_File->TestBit(TFile::kRecovered)){ // Check that file is not corrupted
570  std::cout << "WARNING- "+fileName+" is corrupted or cannot be read." << std::endl;
571  fSetRead = false;
572  }
573  }
574  }
575 
576  if(fSetRead){ // If the file exists then read it....
577  std::cout << "Now going to read file...." << std::endl;
578  fSetWrite = false; // Don't want to write as already exists
579  double thetalow = fThetamin;
580  m_thetaHist = (TH1D*) m_File->Get("pdf_theta");
581  for(int i=1; i<=fThetaBins; i++){
582  std::ostringstream pdfEnergyHist;
583  pdfEnergyHist << "pdf_energy_"<<i;
584  std::string pdfEnergyHiststr = pdfEnergyHist.str();
585 
586  TH1* pdf_hist = (TH1D*) m_File->Get( pdfEnergyHiststr.c_str() ); // Get the bin
587  m_PDFmap->insert(std::make_pair(-thetalow,pdf_hist)); //---- -ve theta for quicker sorting
588  thetalow = double(i)*(fThetamax)/double(fThetaBins); //---- increment the value of theta
589  }
590  } // ------------------------------------------
591  else { // File doesn't exist so want to make it.....
592  // ------------------------------------------
593  std::cout << "Generating a new muon flux PDF" << std::endl;
594  if(fSetWrite){
595  std::cout << "Writing to PDF to file "+fileName << std::endl;
596  m_File = new TFile(fileName.c_str(),"RECREATE");
597  }
598 
599  double dnbins_theta = double(fThetaBins);
600  m_thetaHist = new TH1D("pdf_theta", "pdf_theta", fThetaBins, fThetamin, fThetamax);
601  for(int i=1; i<=fThetaBins; i++){
602  double di = i==0 ? 0.1 : double(i);
603  double theta = di*(fThetamax)/dnbins_theta;
604  double int_i = muonSpec->Integral(fEmin, fEmax, fThetamin, theta, fEpsilon);
605  m_thetaHist->SetBinContent(i, int_i/TotalMuonFlux);
606  }
607  if(fSetWrite) m_thetaHist->Write();
608  std::cout << "theta PDF complete... now making the energy PDFs (this will take a little longer)... " << std::endl;
609 
610  //---- now compute the energy pdf
611  double thetalow = fThetamin;
612  for(int i=1; i<=fThetaBins; i++){
613 
614  double di = double(i);
615  double theta = di*(fThetamax)/fThetaBins;
616 
617  //---- compute the total integral
618  double int_tot = muonSpec->Integral(fEmin, fEmax, thetalow, theta, fEpsilon);
619 
620  //---- compute pdf for the low energy
621  int nbins = fEBinsLow;
622  TH1* pdf_lowenergy = new TH1D("pdf_lowenergy", "pdf_lowenergy", nbins, fEmin, fEmid);
623  double dnbins = double(nbins);
624  for(int j=1; j<=nbins; j++){
625  double dj = double(j);
626  double int_j = muonSpec->Integral(fEmin, fEmin + dj*(fEmid-fEmin)/dnbins, thetalow, theta, fEpsilon);
627  // std::std::cout << j << "(" << m_emin << " --> " << m_emin + dj*m_emid/dnbins << ") = " << int_j/int_tot << std::std::endl;
628  // std::std::cout << j << "(" << m_emin << " --> " << m_emin + dj*(m_emid-m_emin)/dnbins << ") = " << int_j/int_tot << std::std::endl;
629  pdf_lowenergy->SetBinContent(j, int_j/int_tot);
630  }
631 
632  //---- compute pdf for the high energy
633  nbins = fEBinsHigh;
634  dnbins=double(nbins);
635  TH1* pdf_highenergy = new TH1D("pdf_highenergy", "pdf_highenergy", nbins, fEmid, fEmax);
636  for(int j=1; j<=nbins; j++){
637  double dj = double(j);
638  double int_j = muonSpec->Integral(fEmin, fEmid + dj*(fEmax-fEmid)/dnbins, thetalow, theta, fEpsilon);
639  // std::cout << j << "(" << m_emin << " --> " << m_emid + dj*(m_emax-m_emid)/dnbins << ") = " << int_j/int_tot << std::endl;
640  pdf_highenergy->SetBinContent(j, int_j/int_tot);
641  }
642 
643  //---- now combine the two energy hists
644  std::vector<double> vxbins = GetBinning(pdf_lowenergy->GetXaxis(),false);
645  std::vector<double> vxbins2 = GetBinning(pdf_highenergy->GetXaxis());
646  vxbins.insert(vxbins.end(), vxbins2.begin(), vxbins2.end());
647 
648  int ibin = 0;
649  double* xbins = new double[vxbins.size()];
650  for(std::vector<double>::const_iterator binit=vxbins.begin(); binit!=vxbins.end(); binit++, ibin++) xbins[ibin]=(*binit);
651  TH1* pdf_energy = new TH1D("pdf_energy", "pdf_energy", vxbins.size()-1, xbins);
652  int ibin2 = 1;
653  for(ibin = 1; ibin<=pdf_lowenergy->GetNbinsX(); ibin++, ibin2++){
654  double content = pdf_lowenergy->GetBinContent(ibin);
655  if(ibin == 1) content = content - 0.00001;
656  pdf_energy->Fill(pdf_energy->GetBinCenter(ibin2), content);
657  }
658  for(ibin = 1; ibin<=pdf_highenergy->GetNbinsX(); ibin++, ibin2++){
659  pdf_energy->Fill(pdf_energy->GetBinCenter(ibin2), pdf_highenergy->GetBinContent(ibin));
660  }
661 
662  //---- and remove any negative bins
663  std::ostringstream Clonestr;
664  Clonestr << "pdf_energy_"<<i;
665  TH1* pdf_energy_noneg = (TH1D*) pdf_energy->Clone( Clonestr.str().c_str() );
666  pdf_energy_noneg->Reset();
667 
668  double PDF = 0.0;
669  double lastPD = 0.0;
670  int nSkip=0;
671  for(ibin = 1; ibin<=pdf_energy->GetNbinsX(); ibin++){
672  double newPD = pdf_energy->GetBinContent(ibin);
673  double probDiff = newPD - lastPD;
674  if(probDiff<0){
675  if(ibin!=pdf_energy->GetNbinsX()){
676  nSkip++;
677  continue;
678  }
679  else probDiff = 0;
680  }
681  else PDF += probDiff;
682  if(PDF > 1) PDF = 1;
683  for(int iskip=0; iskip <= nSkip; iskip++) pdf_energy_noneg->Fill(pdf_energy_noneg->GetBinCenter(ibin-iskip), PDF);
684  nSkip=0;
685  lastPD = newPD;
686  }
687 
688 
689  //---- add this hist, increment thetalow and delete unwanted TH1s
690  if(fSetWrite) pdf_energy_noneg->Write();
691  m_PDFmap->insert(std::make_pair(-thetalow,pdf_energy_noneg)); //---- -ve theta for quicker sorting
692 
693  //---- increment the value of theta
694  thetalow = theta;
695 
696  //---- free up memory from unwanted hists
697  delete pdf_lowenergy;
698  delete pdf_highenergy;
699  delete pdf_energy;
700 
701  std::cout << "\r===> " << 100.0*double(i)/double(fThetaBins) << "% complete... " << std::endl;
702  } // ThetaBins
703  std::cout << "finished the energy pdfs." << std::endl;
704  }//---- if(!m_doRead)
705 
706  delete muonSpec;
707  return;
708  } // Make PDF
709 
710  //_____________________________________________________________________________
711  double GaisserParam::GaisserFlux(double e, double theta){
712 
713  double ct = cos(theta);
714  double di;
715  if(fSetParam){
716  // double gamma=2.77; // LVD spectrum: spectral index
717  // double A=1.84*0.14; // normalisation
718  double gamma = 2.7;
719  double A = 0.14;
720  double rc = 1.e-4; // fraction of prompt muons
721  double c1 = sqrt(1.-(1.-pow(ct,2.0))/pow( (1.+32./6370.) ,2.0)); // Earth curvature
722  double deltae = 2.06e-3 * (1030. / c1 - 120.); // muon energy loss in atmosphere
723  double em = e + deltae/2.;
724  double e1 = e + deltae;
725  double pdec = pow( (120. / (1030. / c1)), (1.04 / c1 / em)); // muon decay
726  di=A*pow(e1,-gamma)*(1./(1.+1.1*e1*c1/115.) + 0.054/(1.+1.1*e1*c1/850.) + rc)*pdec;
727  }
728  else{
729  double gamma=2.7; // spectral index
730  double A=0.14; // normalisation
731  double C = 3.64;
732  double gamma2 = 1.29;
733  double ct_star = sqrt( (pow(ct,2) + 0.102573*0.102573 - 0.068287*pow(ct,0.958633)
734  + 0.0407253*pow(ct,0.817285) )/(1.0 + 0.102573*0.102573 - 0.068287 + 0.0407253) );
735  double eMod = e*(1.0+C/(e*pow(ct_star,gamma2)));
736  di=A*pow(eMod,-gamma)*(1./(1.+1.1*e*ct_star/115.) + 0.054/(1.+1.1*e*ct_star/850.));
737  }
738 
739  return di;
740  } // GaisserFlux
741 
742  //______________________________________________________________________________
743  double GaisserParam::GaisserMuonFlux_Integrand(Double_t *x, Double_t*){
744 
745  //---- calculate the flux
746  double flux = 2.0*M_PI*sin(x[1])*GaisserFlux(x[0],x[1]);
747 
748  return flux;
749  } // MuonFluxIntegrand
750 
751  //__________________________________
752  std::vector<double> GaisserParam::GetBinning(const TAxis* axis, bool finalEdge){
753  std::vector<double> vbins;
754  for(int ibin=1; ibin<=axis->GetNbins()+1; ibin++){
755  if(ibin<=axis->GetNbins()) vbins.push_back(axis->GetBinLowEdge(ibin));
756  else if(finalEdge) vbins.push_back(axis->GetBinLowEdge(ibin) + axis->GetBinWidth(ibin));
757  }
758  return vbins;
759  } // Get Binning
760 
761  //__________________________________
762  void GaisserParam::ResetMap(){
763  if(m_thetaHist) delete m_thetaHist;
764  if(m_PDFmap){
765  for(dhist_Map_it mapit=m_PDFmap->begin(); mapit!=m_PDFmap->end(); mapit++){
766  if(mapit->second) delete mapit->second;
767  }
768  m_PDFmap->clear();
769  delete m_PDFmap;
770  std::cout << "Reset PDFmap and thetaHist..." << std::endl;
771  }
772  } // ResetMap
773 
774 }//end namespace evgen
775 
776 namespace evgen{
777 
779 
780 }//end namespace evgen
781 
782 #endif
783 
Float_t x
Definition: compare.C:6
double fEpsilon
Minimum integration sum....
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
Definition: MCParticle.h:261
double fThetamax
Maximum theta.
void SetOrigin(simb::Origin_t origin)
Definition: MCTruth.h:78
module to produce single or multiple specified particles in the detector
intermediate_table::iterator iterator
double fYInput
Max Y position.
int fThetaBins
Number of theta Bins.
double fEmid
Energy to go from low to high (GeV)
bool fSetReWrite
Whether to ReWrite pdfs.
art::ProductID put(std::unique_ptr< PROD > &&)
Definition: Run.h:148
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
Particle class.
void Add(simb::MCParticle &part)
Definition: MCTruth.h:77
std::string fInputDir
Input Directory.
void CryostatBoundaries(double *boundaries, geo::CryostatID const &cid) const
Returns the boundaries of the specified cryostat.
Definition: Run.h:30
int fEBinsLow
Number of low energy Bins.
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
base_engine_t & getEngine() const
TCanvas * c1
Definition: plotHisto.C:7
intermediate_table::const_iterator const_iterator
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
void beginJob()
Definition: Breakpoints.cc:14
std::map< double, TH1 * > dhist_Map
std::string DetectorName() const
Returns a string with the name of the detector, as configured.
single particles thrown at the detector
Definition: MCTruth.h:24
T get(std::string const &key) const
Definition: ParameterSet.h:231
TString part[npart]
Definition: Style.C:32
double fEmin
Minimum Kinetic Energy (GeV)
double energy
Definition: plottest35.C:25
double fSigmaT
Variation in t position (ns)
bool fSetParam
Which version of Gaissers Param.
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
double fEmax
Maximum Kinetic Energy (GeV)
Framework includes.
double fXHalfRange
Max X position.
T * make(ARGS...args) const
int fEBinsHigh
Number of high energy Bins.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
#define LOG_DEBUG(id)
bool fSetRead
Whether to Read.
double fThetamin
Minimum theta.
double GaisserMuonFlux_Integrand(Double_t *x, Double_t *par)
int fTDist
How to distribute t (gaus, or uniform)
Event generator information.
Definition: MCTruth.h:30
double fT0
Central t position (ns) in world coordinates.
Float_t e
Definition: plot.C:34
std::map< double, TH1 * >::iterator dhist_Map_it
Namespace collecting geometry-related classes utilities.
Event Generation using GENIE, cosmics or single particles.
bool fSetWrite
Whether to Write.
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
double fZHalfRange
Max Z position.