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