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