Gen311_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Event generator for the 311 (Can be also used for ProtoDUNE) with realistic
4 // muon trigger
5 //
6 //
7 ////////////////////////////////////////////////////////////////////////
8 
9 // ROOT includes
10 #include "TRandom3.h"
11 #include "TDatabasePDG.h"
12 #include "TString.h"
13 #include "TSystem.h" //need BaseName and DirName
14 #include "TFile.h"
15 #include "TH2D.h"
16 #include "TTree.h"
17 #include "TVector3.h"
18 
19 // Framework includes
23 #include "fhiclcpp/ParameterSet.h"
27 #include "art_root_io/TFileService.h"
28 #include "art_root_io/TFileDirectory.h"
30 
31 // art extensions
32 #include "nurandom/RandomUtils/NuRandomService.h"
33 
34 // larsoft includes
37 #include "nugen/EventGeneratorBase/evgenbase.h"
42 
43 #include "CLHEP/Random/RandFlat.h"
44 #include "CLHEP/Random/RandPoissonQ.h"
45 #include "ifdh.h" //to handle flux files
46 
47 // c/c++ includes
48 #include <sqlite3.h>
49 #include <memory>
50 #include <stdio.h>
51 #include <dirent.h>
52 
53 namespace evgendp{
54 
55  class Gen311 : public art::EDProducer {
56 
57  public:
58  explicit Gen311(fhicl::ParameterSet const & p);
59  virtual ~Gen311();
60 
61  Gen311(Gen311 const &) = delete;
62  Gen311(Gen311 &&) = delete;
63  Gen311 & operator = (Gen311 const &) = delete;
64  Gen311 & operator = (Gen311 &&) = delete;
65 
66  void produce(art::Event & e) override;
67 
68  void reconfigure(fhicl::ParameterSet const& p);
69  void beginJob() override;
70  void beginRun(art::Run& run) override;
71 
72  private:
73 
74  int fShowerInputs=0; ///< Number of shower inputs to process from
75  std::vector<double> fNShowersPerEvent; ///< Number of showers to put in each event of duration fSampleTime; one per showerinput
76  std::vector<int> fMaxShowers; //< Max number of showers to query, one per showerinput
77  double fShowerBounds[6]={0.,0.,0.,0.,0.,0.}; ///< Boundaries of area over which showers are to be distributed
78  double fToffset_corsika=0.; ///< Timing offset to account for propagation time through atmosphere, populated from db
79  ifdh_ns::ifdh* fIFDH=0; ///< (optional) flux file handling
80 
81  //fcl parameters
82  double fProjectToHeight=0.; ///< Height to which particles will be projected [cm]
83  std::vector< std::string > fShowerInputFiles; ///< Set of CORSIKA shower data files to use
84  std::vector< double > fShowerFluxConstants; ///< Set of flux constants to be associated with each shower data file
85  double fSampleTime=0.; ///< Duration of sample [s]
86  double fToffset=0.; ///< Time offset of sample, defaults to zero (no offset) [s]
87  std::vector<double> fBuffBox; ///< Buffer box extensions to cryostat in each direction (6 of them: x_lo,x_hi,y_lo,y_hi,z_lo,z_hi) [cm]
88  double fShowerAreaExtension=0.; ///< Extend distribution of corsika particles in x,z by this much (e.g. 1000 will extend 10 m in -x, +x, -z, and +z) [cm]
89  sqlite3* fdb[5]; ///< Pointers to sqlite3 database object, max of 5
90  double fRandomYZShift=0.; ///< Each shower will be shifted by a random amount in xz so that showers won't repeatedly sample the same space [cm]
91  std::vector<double> fActiveVolumeCut; ///< Active volume cut
92  std::vector< double > fLeadingParticlesList; /// < List of pdg codes for particles that can be potentially used as triggers
93  bool fUseIFDH; ///<< use ifdh protocol
94 
95  int fRun;
96  int fEvent;
97 
98  double fTheta;
99  double fPhi;
100  double fMomX;
101  double fMomY;
102  double fMomZ;
103  double fMomT;
104  double fStartX;
105  double fStartY;
106  double fStartZ;
107  TTree *fTree;
108 
110  CLHEP::HepRandomEngine& fGenEngine;
111  CLHEP::HepRandomEngine& fPoisEngine;
112 
113  void openDBs();
114  void populateNShowers();
115  void populateTOffset();
116 
117  bool InTPC(const simb::MCParticle particle);
118  double wrapvar( const double var, const double low, const double high);
119  double wrapvarBoxNo( const double var, const double low, const double high, int& boxno);
120  void GetSample(simb::MCTruth&);
121 
122  };
123 
124  class Trigger{
125 
126  public:
127  Trigger();
128  ~Trigger();
129 
130  //setter
131  void AddMuon( simb::MCParticle particle ){
132  fMuonList.push_back(particle); return;
133  };
134 
135  //getters
137  return fTriggerID;
138  };
139 
141  return fTriggerOffsetX;
142  };
143 
145  return fTriggerOffsetY;
146  };
147 
149  return fTriggerOffsetZ;
150  };
151 
153  return fTriggerOffsetT;
154  };
155 
156  TLorentzVector GetTriggerPos(){
157  return fTriggerPos;
158  };
159 
160  double GetTriggerPosX(){
161  return fTriggerPosX;
162  };
163 
164  double GetTriggerPosY(){
165  return fTriggerPosY;
166  };
167 
168  double GetTriggerPosZ(){
169  return fTriggerPosZ;
170  };
171 
172  double GetTriggerPosT(){
173  return fTriggerPosT;
174  };
175 
176  TLorentzVector GetTriggerMom(){
177  return fTriggerMu.Momentum();
178  };
179 
180  double GetTriggerMomX(){
181  return fTriggerMu.Momentum().X();
182  };
183 
184  double GetTriggerMomY(){
185  return fTriggerMu.Momentum().Y();
186  };
187 
188  double GetTriggerMomZ(){
189  return fTriggerMu.Momentum().Z();
190  };
191 
192  double GetTriggerMomT(){
193  return fTriggerMu.Momentum().T();
194  };
195 
196  //Find the trigger particle
197  void MakeTrigger(CLHEP::HepRandomEngine& engine);
198 
199  //geo utilities
200  double GetPhi( const double py, const double pz );
201  void GetMatrix( double theta, double phi, double (*p_R)[3][3] );
202  void DoRotation( double urv[], double dir[], double theta, double phi );
203  bool Intersect(const double x0[], const double dx[], const double bounds[]);
204  void ProjectToBoxEdge( const double xyz[],
205  const double indxyz[],
206  const double xlo,
207  const double xhi,
208  const double ylo,
209  const double yhi,
210  const double zlo,
211  const double zhi,
212  double xyzout[]
213  );
214  void GetTPCSize( double tpc[]);
215  void GetCryoSize( double cryo[]);
216  void SetCryoBuffer( std::vector<double> buffer ){
217  for(int i=0; i<6; i++){ fCryoBuffer.assign( buffer.begin(), buffer.end() ); }
218  }
219  void SetTPCBuffer( std::vector<double> buffer ){
220  for(int i=0; i<6; i++){ fTPCBuffer.assign( buffer.begin(), buffer.end() ); }
221  }
222 
223 
224  private:
225 
227 
228  std::vector<simb::MCParticle> fMuonList;
230  TLorentzVector fTriggerPos;
231  double fTriggerID = -999;
232  double fTriggerPosX;
233  double fTriggerPosY;
234  double fTriggerPosZ;
235  double fTriggerPosT;
240  std::vector<double> fTPCBuffer;
241  std::vector<double> fCryoBuffer;
242  };
243 
244 }//end namespace
245 
246 
248  : EDProducer{p},
249  fProjectToHeight(p.get< double >("ProjectToHeight",0.)),
250  fShowerInputFiles(p.get< std::vector< std::string > >("ShowerInputFiles")),
251  fShowerFluxConstants(p.get< std::vector< double > >("ShowerFluxConstants")),
252  fSampleTime(p.get< double >("SampleTime",0.)),
253  fToffset(p.get< double >("TimeOffset",0.)),
254  fBuffBox(p.get< std::vector< double > >("BufferBox",{0.0, 0.0, 0.0, 0.0, 0.0, 0.0})),
255  fShowerAreaExtension(p.get< double >("ShowerAreaExtension",0.)),
256  fRandomYZShift(p.get< double >("RandomYZShift",0.)),
257  fActiveVolumeCut(p.get< std::vector< double > >("ActiveVolumeCut")),
258  fLeadingParticlesList(p.get< std::vector< double > >("LeadingParticlesList")),
259  fUseIFDH(p.get< bool >("UseIFDH")),
260  // create a default random engine; obtain the random seed from NuRandomService,
261  // unless overridden in configuration with key "Seed"
263  ->createEngine(*this, "HepJamesRandom", "gen", p, { "Seed", "SeedGenerator" })),
265  ->createEngine(*this, "HepJamesRandom", "pois", p, "SeedPoisson"))
266  {
267 
268  if(fShowerInputFiles.size() != fShowerFluxConstants.size() || fShowerInputFiles.size()==0 || fShowerFluxConstants.size()==0)
269  throw cet::exception("Gen311") << "ShowerInputFiles and ShowerFluxConstants have different or invalid sizes!"<<"\n";
271 
272  if(fSampleTime==0.) throw cet::exception("Gen311") << "SampleTime not set!";
273 
274  if(fProjectToHeight==0.) mf::LogInfo("Gen311")<<"Using 0. for fProjectToHeight!"
275  ;
276 
277  this->reconfigure(p);
278 
279  this->openDBs();
280  this->populateNShowers();
281  this->populateTOffset();
282 
283  produces< std::vector<simb::MCTruth> >();
284  produces< sumdata::RunData, art::InRun >();
285  }
286 
288  for(int i=0; i<fShowerInputs; i++){
289  sqlite3_close(fdb[i]);
290  }
291  //cleanup temp files
292  fIFDH->cleanup();
293  }
294 
296 
297  return;
298  }
299 
301 
302 
304 
305  fTree = tfs->make<TTree>("entries", "entries tree");
306  fTree->Branch("Run", &fRun, "Run/I");
307  fTree->Branch("Event", &fEvent, "Event/I");
308  fTree->Branch("Theta", &fTheta, "Theta/D");
309  fTree->Branch("Phi", &fPhi, "Phi/D");
310  fTree->Branch("MomX", &fMomX, "MomX/D");
311  fTree->Branch("MomY", &fMomY, "MomY/D");
312  fTree->Branch("MomZ", &fMomZ, "MomZ/D");
313  fTree->Branch("MomT", &fMomT, "MomT/D");
314  fTree->Branch("StartX", &fStartX, "StartX/D");
315  fTree->Branch("StartY", &fStartY, "StartY/D");
316  fTree->Branch("StartZ", &fStartZ, "StartZ/D");
317 
318  }
319 
321  // grab the geometry object to see what geometry we are using
323  std::unique_ptr<sumdata::RunData> runcol(new sumdata::RunData(geo->DetectorName()));
324  run.put(std::move(runcol));
325  return;
326  }
327 
328 
330  //choose files based on fShowerInputFiles, copy them with ifdh, open them
331  //sqlite3_stmt *statement;
332  CLHEP::RandFlat flat(fGenEngine);
333 
334  if(fUseIFDH){
335  //setup ifdh object
336  if ( ! fIFDH ) fIFDH = new ifdh_ns::ifdh;
337  const char* ifdh_debug_env = std::getenv("IFDH_DEBUG_LEVEL");
338  if ( ifdh_debug_env ) {
339  mf::LogInfo("CORSIKAGendp") << "IFDH_DEBUG_LEVEL: " << ifdh_debug_env<<"\n";
340  fIFDH->set_debug(ifdh_debug_env);
341  }
342  }
343 
344  //setup ifdh object
345  if ( ! fIFDH ) fIFDH = new ifdh_ns::ifdh;
346  const char* ifdh_debug_env = std::getenv("IFDH_DEBUG_LEVEL");
347  if ( ifdh_debug_env ) {
348  mf::LogInfo("CORSIKAGendp") << "IFDH_DEBUG_LEVEL: " << ifdh_debug_env<<"\n";
349  fIFDH->set_debug(ifdh_debug_env);
350  }
351 
352  std::vector<std::pair<std::string,long>> selectedflist;
353  for(int i=0; i<fShowerInputs; i++){
354  if(fShowerInputFiles[i].find("*")==std::string::npos){
355  //if there are no wildcards, don't call findMatchingFiles
356  selectedflist.push_back(std::make_pair(fShowerInputFiles[i],0));
357  mf::LogInfo("Gen311") << "Selected"<<selectedflist.back().first<<"\n";
358  }else{
359  //read all the file mathching the pattern
360  std::vector<std::pair<std::string,long>> flist;
361  std::string path(gSystem->DirName(fShowerInputFiles[i].c_str()));
362  std::string pattern(gSystem->BaseName(fShowerInputFiles[i].c_str()));
363 
364  if(fUseIFDH){
365  //acess the files using ifdh
366  flist = fIFDH->findMatchingFiles(path,pattern);
367  }else{
368  //access the files using drent
369  auto wildcardPosition = pattern.find("*");
370  pattern = pattern.substr( 0, wildcardPosition );
371 
372  DIR *dir;
373  struct dirent *ent;
374  int index=0;
375  if ((dir = opendir( path.c_str() )) != NULL) {
376  while ((ent = readdir (dir)) != NULL) {
377  index++;
378  std::pair<std::string,long> name;
379  std::string parsename(ent->d_name);
380 
381  if( parsename.substr(0, wildcardPosition) == pattern ){
382  name.first= path+"/"+parsename;
383  name.second = index;
384  flist.push_back( name );
385  }
386  }
387  closedir (dir);
388  }else {
389  throw cet::exception("Gen311") << "Can't open directory with pattern: "<<path<<":"<<pattern<<std::endl;
390  }
391  }
392 
393  unsigned int selIndex=-1;
394  if(flist.size()==1){ //0th element is the search path:pattern
395  selIndex=0;
396  }else if(flist.size()>1){
397  selIndex= (unsigned int) (flat()*(flist.size()-1)+0.5); //rnd with rounding, dont allow picking the 0th element
398  }else{
399  throw cet::exception("Gen311") << "No files returned for path:pattern: "<<path<<":"<<pattern<<std::endl;
400  }
401  selectedflist.push_back(flist[selIndex]);
402  mf::LogInfo("Gen311") << "For "<<fShowerInputFiles[i]<<":"<<pattern
403  <<"\nFound "<< flist.size() << " candidate files"
404  <<"\nChoosing file number "<< selIndex << "\n"
405  <<"\nSelected "<<selectedflist.back().first<<"\n";
406  }
407  }
408 
409  //open the files in fShowerInputFilesLocalPaths with sqlite3
410  std::vector<std::string> locallist;
411  for(unsigned int i=0; i<selectedflist.size(); i++){
412  mf::LogInfo("Gen311")
413  << "Fetching: "<<selectedflist[i].first<<" "<<selectedflist[i].second<<"\n";
414  std::string fetchedfile(selectedflist[i].first);
415  MF_LOG_DEBUG("Gen311") << "Fetched; local path: "<<fetchedfile;
416  locallist.push_back(fetchedfile);
417  }
418 
419  for(unsigned int i=0; i<locallist.size(); i++){
420  //prepare and execute statement to attach db file
421  int res=sqlite3_open(locallist[i].c_str(),&fdb[i]);
422  if (res!= SQLITE_OK)
423  throw cet::exception("Gen311") << "Error opening db: (" <<locallist[i].c_str()<<") ("<<res<<"): " << sqlite3_errmsg(fdb[i]) << "; memory used:<<"<<sqlite3_memory_used()<<"/"<<sqlite3_memory_highwater(0)<<"\n";
424  else
425  mf::LogInfo("Gen311")<<"Attached db "<< locallist[i]<<"\n";
426  }
427  }//end openDBs
428 
429 /*
430 void evgendp::Gen311::openDBs(){
431  //choose files based on fShowerInputFiles, copy them with ifdh, open them
432  //sqlite3_stmt *statement;
433  CLHEP::RandFlat flat(fGenEngine);
434 
435  //setup ifdh object
436  if ( ! fIFDH ) fIFDH = new ifdh_ns::ifdh;
437  const char* ifdh_debug_env = std::getenv("IFDH_DEBUG_LEVEL");
438  if ( ifdh_debug_env ) {
439  mf::LogInfo("CORSIKAGendp") << "IFDH_DEBUG_LEVEL: " << ifdh_debug_env<<"\n";
440  fIFDH->set_debug(ifdh_debug_env);
441  }
442 
443  //get ifdh path for each file in fShowerInputFiles, put into selectedflist
444  //if 1 file returned, use that file
445  //if >1 file returned, randomly select one file
446  //if 0 returned, make exeption for missing files
447  std::vector<std::pair<std::string,long>> selectedflist;
448  for(int i=0; i<fShowerInputs; i++){
449  if(fShowerInputFiles[i].find("*")==std::string::npos){
450  //if there are no wildcards, don't call findMatchingFiles
451  selectedflist.push_back(std::make_pair(fShowerInputFiles[i],0));
452  mf::LogInfo("CorsikaGendp") << "Selected"<<selectedflist.back().first<<"\n";
453  }else{
454  //use findMatchingFiles
455  std::vector<std::pair<std::string,long>> flist;
456  std::string path(gSystem->DirName(fShowerInputFiles[i].c_str()));
457  std::string pattern(gSystem->BaseName(fShowerInputFiles[i].c_str()));
458  //pattern="/"+pattern;
459 
460 
461  std::cout << path << " " << pattern << std::endl;
462 
463  flist = fIFDH->findMatchingFiles(path,pattern);
464  unsigned int selIndex=-1;
465  if(flist.size()==1){ //0th element is the search path:pattern
466  selIndex=0;
467  }else if(flist.size()>1){
468  selIndex= (unsigned int) (flat()*(flist.size()-1)+0.5); //rnd with rounding, dont allow picking the 0th element
469  }else{
470  throw cet::exception("CORSIKAGendp") << "No files returned for path:pattern: "<<path<<":"<<pattern<<std::endl;
471  }
472 
473  selectedflist.push_back(flist[selIndex]);
474  mf::LogInfo("CorsikaGendp") << "For "<<fShowerInputFiles[i]<<":"<<pattern
475  <<"\nFound "<< flist.size() << " candidate files"
476 <<"\nChoosing file number "<< selIndex << "\n"
477  <<"\nSelected "<<selectedflist.back().first<<"\n";
478  }
479 
480  }
481 
482  //do the fetching, store local filepaths in locallist
483  std::vector<std::string> locallist;
484  for(unsigned int i=0; i<selectedflist.size(); i++){
485  mf::LogInfo("CorsikaGendp")
486  << "Fetching: "<<selectedflist[i].first<<" "<<selectedflist[i].second<<"\n";
487  std::string fetchedfile(fIFDH->fetchInput(selectedflist[i].first));
488  MF_LOG_DEBUG("CorsikaGendp") << "Fetched; local path: "<<fetchedfile;
489  locallist.push_back(fetchedfile);
490  }
491 
492  //open the files in fShowerInputFilesLocalPaths with sqlite3
493  for(unsigned int i=0; i<locallist.size(); i++){
494  //prepare and execute statement to attach db file
495  int res=sqlite3_open(locallist[i].c_str(),&fdb[i]);
496  if (res!= SQLITE_OK)
497  throw cet::exception("CORSIKAGendp") << "Error opening db: (" <<locallist[i].c_str()<<") ("<<res<<"): " << sqlite3_errmsg(fdb[i]) << "; memory used:<<"<<sqlite3_memory_used()<<"/"<<sqlite3_memory_highwater(0)<<"\n";
498  else
499  mf::LogInfo("CORSIKAGendp")<<"Attached db "<< locallist[i]<<"\n";
500  }
501 }
502 */
503 
505  //populate TOffset_corsika by finding minimum ParticleTime from db file
506 
507  sqlite3_stmt *statement;
508  const std::string kStatement("select min(t) from particles");
509  double t=0.;
510 
511  for(int i=0; i<fShowerInputs; i++){
512  //build and do query to get run min(t) from each db
513  if ( sqlite3_prepare(fdb[i], kStatement.c_str(), -1, &statement, 0 ) == SQLITE_OK ){
514  int res=0;
515  res = sqlite3_step(statement);
516  if ( res == SQLITE_ROW ){
517  t=sqlite3_column_double(statement,0);
518  mf::LogInfo("Gen311")<<"For showers input "<< i<<" found particles.min(t)="<<t<<"\n";
519  if (i==0 || t<fToffset_corsika) fToffset_corsika=t;
520  }else{
521  throw cet::exception("Gen311") << "Unexpected sqlite3_step return value: (" <<res<<"); "<<"ERROR:"<<sqlite3_errmsg(fdb[i])<<"\n";
522  }
523  }else{
524  throw cet::exception("Gen311") << "Error preparing statement: (" <<kStatement<<"); "<<"ERROR:"<<sqlite3_errmsg(fdb[i])<<"\n";
525  }
526  }
527 
528  mf::LogInfo("Gen311")<<"Found corsika timeoffset [ns]: "<< fToffset_corsika<<"\n";
529  }
530 
532  //populate vector of the number of showers per event based on:
533  //AREA the showers are being distributed over
534  //TIME of the event (fSampleTime)
535  //flux constants that determine the overall normalizations (fShowerFluxConstants)
536  //Energy range over which the sample was generated (ERANGE_*)
537  //power spectrum over which the sample was generated (ESLOPE)
538 
539 
540  //compute shower area based on the maximal x,z dimensions of cryostat boundaries + fShowerAreaExtension
541  //art::ServiceHandle<geo::Geometry> geom;
542  for(unsigned int c = 0; c < geom->Ncryostats(); ++c){
543  double bounds[6] = {0.};
544  geom->CryostatBoundaries(bounds, c);
545  for (unsigned int bnd = 0; bnd<6; bnd++){
546  mf::LogVerbatim("Gen311")<<"Cryo Boundary: "<<bnd<<"="<<bounds[bnd]<<" ( + Buffer="<<fBuffBox[bnd]<<")\n";
547  if(fabs(bounds[bnd])>fabs(fShowerBounds[bnd])){
548  fShowerBounds[bnd]=bounds[bnd];
549  }
550  }
551  }
552  //add on fShowerAreaExtension without being clever
557 
558  double showersArea=(fShowerBounds[3]/100-fShowerBounds[2]/100)*(fShowerBounds[5]/100-fShowerBounds[4]/100);
559 
560  mf::LogInfo("Gen311")
561  << "Area extended by : "<<fShowerAreaExtension
562  <<"\nShowers to be distributed betweeen: y="<<fShowerBounds[2]<<","<<fShowerBounds[3]
563  <<" & z="<<fShowerBounds[4]<<","<<fShowerBounds[5]
564  <<"\nShowers to be distributed with random YZ shift: "<<fRandomYZShift<<" cm"
565  <<"\nShowers to be distributed over area: "<<showersArea<<" m^2"
566  <<"\nShowers to be distributed over time: "<<fSampleTime<<" s"
567  <<"\nShowers to be distributed with time offset: "<<fToffset<<" s"
568  <<"\nShowers to be distributed at x: "<<fShowerBounds[1]<<" cm"
569  ;
570 
571  //db variables
572  sqlite3_stmt *statement;
573  const std::string kStatement("select erange_high,erange_low,eslope,nshow from input");
574  double upperLimitOfEnergyRange=0.,lowerLimitOfEnergyRange=0.,energySlope=0.,oneMinusGamma=0.,EiToOneMinusGamma=0.,EfToOneMinusGamma=0.;
575 
576  for(int i=0; i<fShowerInputs; i++){
577  //build and do query to get run info from databases
578  // double thisrnd=flat();//need a new random number for each query
579  if ( sqlite3_prepare(fdb[i], kStatement.c_str(), -1, &statement, 0 ) == SQLITE_OK ){
580  int res=0;
581  res = sqlite3_step(statement);
582  if ( res == SQLITE_ROW ){
583  upperLimitOfEnergyRange=sqlite3_column_double(statement,0);
584  lowerLimitOfEnergyRange=sqlite3_column_double(statement,1);
585  energySlope = sqlite3_column_double(statement,2);
586  fMaxShowers.push_back(sqlite3_column_int(statement,3));
587  oneMinusGamma = 1 + energySlope;
588  EiToOneMinusGamma = pow(lowerLimitOfEnergyRange, oneMinusGamma);
589  EfToOneMinusGamma = pow(upperLimitOfEnergyRange, oneMinusGamma);
590  mf::LogVerbatim("Gen311")<<"For showers input "<< i<<" found e_hi="<<upperLimitOfEnergyRange<<", e_lo="<<lowerLimitOfEnergyRange<<", slope="<<energySlope<<", k="<<fShowerFluxConstants[i]<<"\n";
591  }else{
592  throw cet::exception("Gen311") << "Unexpected sqlite3_step return value: (" <<res<<"); "<<"ERROR:"<<sqlite3_errmsg(fdb[i])<<"\n";
593  }
594  }else{
595  throw cet::exception("Gen311") << "Error preparing statement: (" <<kStatement<<"); "<<"ERROR:"<<sqlite3_errmsg(fdb[i])<<"\n";
596  }
597 
598  //this is computed, how?
599  double NShowers=( M_PI * showersArea * fShowerFluxConstants[i] * (EfToOneMinusGamma - EiToOneMinusGamma) / oneMinusGamma )*fSampleTime;
600  fNShowersPerEvent.push_back(NShowers);
601  mf::LogVerbatim("Gen311")<<"For showers input "<< i
602  <<" the number of showers per event is "<<(int)NShowers<<"\n";
603  }
604  }
605 
606  double evgendp::Gen311::wrapvar( const double var, const double low, const double high){
607  //wrap variable so that it's always between low and high
608  return (var - (high - low) * floor(var/(high-low))) + low;
609  }
610 
611  double evgendp::Gen311::wrapvarBoxNo( const double var, const double low, const double high, int& boxno){
612  //wrap variable so that it's always between low and high
613  boxno=int(floor(var/(high-low)));
614  return (var - (high - low) * floor(var/(high-low))) + low;
615  }
616 
618  //for each input, randomly pull fNShowersPerEvent[i] showers from the Particles table
619  //and randomly place them in time (between -fSampleTime/2 and fSampleTime/2)
620  //wrap their positions based on the size of the area under consideration
621  //based on http://nusoft.fnal.gov/larsoft/doxsvn/html/CRYHelper_8cxx_source.html (Sample)
622 
623  //query from sqlite db with select * from particles where shower in (select id from showers ORDER BY substr(id*0.51123124141,length(id)+2) limit 100000) ORDER BY substr(shower*0.51123124141,length(shower)+2);
624  //where 0.51123124141 is a random seed to allow randomly selecting rows and should be randomly generated for each query
625  //the inner order by is to select randomly from the possible shower id's
626  //the outer order by is to make sure the shower numbers are ordered randomly (without this, the showers always come out ordered by shower number
627  //and 100000 is the number of showers to be selected at random and needs to be less than the number of showers in the showers table
628 
629  //dummy holder for particles object
630  std::map< int, std::vector<simb::MCParticle> > ParticleMap;
631  std::map< int, int > ShowerTrkIDMap;
632 
633  //define the trigger object
634  Trigger trg;
635  trg.SetCryoBuffer( fBuffBox );
637 
638  //TDatabasePDG is for looking up particle masses
639  static TDatabasePDG* pdgt = TDatabasePDG::Instance();
640 
641  //db variables
642  sqlite3_stmt *statement;
643  const TString kStatement("select shower,pdg,px,py,pz,x,z,t,e from particles where shower in (select id from showers ORDER BY substr(id*%f,length(id)+2) limit %d) ORDER BY substr(shower*%f,length(shower)+2)");
644 
645  CLHEP::RandFlat flat(fGenEngine);
646  CLHEP::RandPoissonQ randpois(fPoisEngine);
647 
648  // get geometry and figure where to project particles to, based on CRYHelper
649  //art::ServiceHandle<geo::Geometry> geom;
650  double x1, x2;
651  double y1, y2;
652  double z1, z2;
653  geom->WorldBox(&x1, &x2, &y1, &y2, &z1, &z2);
654 
655  // make the world box slightly smaller so that the projection to
656  // the edge avoids possible rounding errors later on with Geant4
657  double fBoxDelta=1.e-5;
658 
659  geom->WorldBox(&y1, &y2, &x1, &x2, &z1, &z2);
660  y1 += fBoxDelta;
661  y2 -= fBoxDelta;
662  x1 += fBoxDelta;
663  x2 = fProjectToHeight;
664  z1 += fBoxDelta;
665  z2 -= fBoxDelta;
666 
667  //populate mctruth
668  int ntotalCtr=0; //count number of particles added to mctruth
669  //int lastShower=0; //keep track of last shower id so that t can be randomized on every new shower
670  int nShowerCntr=0; //keep track of how many showers are left to be added to mctruth
671  int nShowerQry=0; //number of showers to query from db
672  int shower,pdg;
673  double px,py,pz,etot, y=0,z,t; //tParticleTime,,showerTime=0.,showerTimex=0.,showerTimez=0.,showerXOffset=0.,showerZOffset=0.,t;
674  for(int i=0; i<fShowerInputs; i++){
675  nShowerCntr=randpois.fire(fNShowersPerEvent[i]);
676  mf::LogInfo("Gen311") << " Shower input " << i << " with mean " << fNShowersPerEvent[i] << " generating " << nShowerCntr;
677 
678  while(nShowerCntr>0){
679  //how many showers should we query?
680  if(nShowerCntr>fMaxShowers[i]){
681  nShowerQry=fMaxShowers[i]; //take the group size
682  }else{
683  nShowerQry=nShowerCntr; //take the rest that are needed
684  }
685  //build and do query to get nshowers
686  double thisrnd=flat(); //need a new random number for each query
687  TString kthisStatement=TString::Format(kStatement.Data(),thisrnd,nShowerQry,thisrnd);
688  MF_LOG_DEBUG("Gen311")<<"Executing: "<<kthisStatement;
689  if ( sqlite3_prepare(fdb[i], kthisStatement.Data(), -1, &statement, 0 ) == SQLITE_OK ){
690  int res=0;
691  //loop over database rows, pushing particles into mctruth object
692  while(1){
693  res = sqlite3_step(statement);
694  if ( res == SQLITE_ROW ){
695  shower=sqlite3_column_int(statement,0);
696 
697  pdg=sqlite3_column_int(statement,1);
698  //get mass for this particle
699  double m = 0.; // in GeV
700  TParticlePDG* pdgp = pdgt->GetParticle(pdg);
701  if (pdgp) m = pdgp->Mass();
702 
703  //get momentum components
704  //NR rotation from CORSIKA ref system to LArSoft ref system:
705  //LArsoft: px, py, pz;
706  //uBoone px', py', pz'; << from the sqlite database instances
707  // px = py'
708  // py = pz'
709  // pz = px'
710  px = sqlite3_column_double(statement,3);
711  py = sqlite3_column_double(statement,4);
712  pz = sqlite3_column_double(statement,2);
713  etot=sqlite3_column_double(statement,8);
714  y = sqlite3_column_double(statement,6);
715  z = sqlite3_column_double(statement,5);
716  t = sqlite3_column_double(statement,7); //time offset, includes propagation time from top of atmosphere
717 
718  TLorentzVector pos(fShowerBounds[1], y, z,t);// time needs to be in ns to match GENIE, etc
719  TLorentzVector mom(px,py,pz,etot);
720 
721  simb::MCParticle p(ntotalCtr,pdg,"primary",-200,m,1);
722  p.AddTrajectoryPoint(pos,mom);
723 
724  //if it is muon, fill up the list of possible triggers
726  pdgIt = find( fLeadingParticlesList.begin(), fLeadingParticlesList.end(), p.PdgCode() );
727  if( pdgIt != fLeadingParticlesList.end() ){ trg.AddMuon( p ); }
728 
729  ParticleMap[ shower ].push_back(p);
730  ShowerTrkIDMap[ ntotalCtr ] = shower; //<< use the unique trackID to trace the source shower back
731 
732  ntotalCtr++;
733  }else if ( res == SQLITE_DONE ){
734  break;
735  }else{
736  throw cet::exception("Gen311") << "Unexpected sqlite3_step return value: (" <<res<<"); "<<"ERROR:"<<sqlite3_errmsg(fdb[i])<<"\n";
737  }
738  }
739  }else{
740  throw cet::exception("Gen311") << "Error preparing statement: (" <<kthisStatement<<"); "<<"ERROR:"<<sqlite3_errmsg(fdb[i])<<"\n";
741  }
742  nShowerCntr=nShowerCntr-nShowerQry;
743  }
744  } //end loop over showers
745 
746  trg.MakeTrigger(fGenEngine); //<<--Select a muon to use as trigger
747 
748  double showerTime=0, showerTimey=0, showerTimez=0, showerYOffset=0, showerZOffset=0;
749  int boxnoY=0, boxnoZ=0;
750 
751  for( auto ParticleMapIt : ParticleMap ){
752 
753  if( ParticleMapIt.first == ShowerTrkIDMap[ trg.GetTriggerId() ] ){
754 
755  showerTime =1e9*trg.GetTriggerOffsetT(); //converting from s to ns
756  showerTimey=1e9*trg.GetTriggerOffsetT();
757  showerTimez=1e9*trg.GetTriggerOffsetT();
758 
759  //and a random offset in both z and x controlled by the fRandomYZShift parameter
760  showerYOffset=1e9*trg.GetTriggerOffsetY();
761  showerZOffset=1e9*trg.GetTriggerOffsetZ();
762 
763  }else{
764 
765  showerTime =1e9*(flat()*fSampleTime); //converting from s to ns
766  showerTimey=1e9*(flat()*fSampleTime); //converting from s to ns
767  showerTimez=1e9*(flat()*fSampleTime); //converting from s to ns
768  //and a random offset in both z and x controlled by the fRandomYZShift parameter
769  showerYOffset=flat()*fRandomYZShift - (fRandomYZShift/2);
770  showerZOffset=flat()*fRandomYZShift - (fRandomYZShift/2);
771  }
772 
773  for( auto particleIt : ParticleMapIt.second ){
774 
775  simb::MCParticle particle(particleIt.TrackId(),particleIt.PdgCode(),"primary",-200,particleIt.Mass(),1);
776 
777  double x0[3]={0.};
778  double xyzo[3]={0.};
779  double dx[3]={0.};
780 
781  if( particleIt.TrackId() == trg.GetTriggerId() ){
782 
783  x0[0] = trg.GetTriggerPos().X();
784  x0[1] = trg.GetTriggerPos().Y();
785  x0[2] = trg.GetTriggerPos().Z();
786  dx[0] = trg.GetTriggerMom().X();
787  dx[1] = trg.GetTriggerMom().Y();
788  dx[2] = trg.GetTriggerMom().Z();
789 
790  t = trg.GetTriggerPos().T();
791 
792  }else{
793 
794  y = wrapvarBoxNo(particleIt.Position().Y()+showerYOffset,fShowerBounds[2],fShowerBounds[3],boxnoY);
795  z = wrapvarBoxNo(particleIt.Position().Z()+showerZOffset,fShowerBounds[4],fShowerBounds[5],boxnoZ);
796 
797  t=particleIt.Position().T()+showerTime+(1e9*fToffset)-fToffset_corsika + showerTimey*boxnoY + showerTimez*boxnoZ;
798  t=wrapvar(t,(1e9*fToffset),1e9*(fToffset+fSampleTime));
799 
800  x0[0]= fShowerBounds[1];
801  x0[1]= y;
802  x0[2]= z;
803  dx[0]= particleIt.Momentum().X();
804  dx[1]= particleIt.Momentum().Y();
805  dx[2]= particleIt.Momentum().Z();
806 
807  }
808 
809  trg.ProjectToBoxEdge(x0, dx, x1, x2, y1, y2, z1, z2, xyzo);
810  TLorentzVector pos(xyzo[0],xyzo[1],xyzo[2], t);
811  TLorentzVector mom(dx[0],dx[1],dx[2], particleIt.Momentum().T() );
812  particle.AddTrajectoryPoint( pos, mom );
813 
814  mctruth.Add( particle );
815  } //end loop over particles
816  }//loop over showers
817  } //end GetSample
818 
819 
820 //Functions to study the trigger ***********************************************************************************
821 
823  fMuonList.clear();
824 }
825 
827 
828 double evgendp::Trigger::GetPhi( const double py, const double pz ){
829 
830  if( pz !=0 ){
831  if( pz > 0 ){
832  return atan( py/pz );
833  }
834  else if( atan( py/pz ) < 0 ){
835  return atan( py/pz )+3.1415926;
836  }
837  else{
838  return atan( py/pz )-3.1415926;
839  }
840  }
841  else if( py > 0 ){
842  return 3.1415926/2.;
843  }
844  else{
845  return -3.1415926/2.;
846  }
847 }
848 
849 void evgendp::Trigger::GetMatrix( double theta, double phi, double (*p_R)[3][3] ){
850 
851  (*p_R)[0][0]= cos(phi)*cos(theta);
852  (*p_R)[0][1]= cos(phi)*sin(theta);
853  (*p_R)[0][2]= -sin(phi);
854  (*p_R)[1][0]= -sin(theta);
855  (*p_R)[1][1]= cos(theta);
856  (*p_R)[1][2]= 0;
857  (*p_R)[2][0]= sin(phi)*cos(theta);
858  (*p_R)[2][1]= sin(phi)*sin(theta);
859  (*p_R)[2][2]= cos(phi);
860 
861  return;
862 }
863 
864 void evgendp::Trigger::DoRotation( double urv[], double dir[], double theta, double phi ){
865 
866  //build the rotation matrix;
867  double R[3][3];
868  double (*p_R)[3][3]=&R;
869  GetMatrix(theta, phi, p_R);
870 
871  for(int i=0; i<3; i++){
872  for(int j=0; j<3; j++){
873  dir[i] += (*p_R)[i][j]*urv[j];
874  //cout << i << " " << j << " " << urv[j] << " " << (*p_R)[i][j] << " " << dir[i] << endl;
875  }
876  }
877 
878  return;
879 }
880 
881 bool evgendp::Trigger::Intersect(const double x0[], const double dx[], const double bounds[]){
882  //check if the particle intercept the tpc
883 
884  bool intersects_tpc = false;
885  for (int bnd=0; bnd!=6; ++bnd) {
886  if (bnd<2) {
887  double p2[3] = {bounds[bnd], x0[1] + (dx[1]/dx[0])*(bounds[bnd] - x0[0]), x0[2] + (dx[2]/dx[0])*(bounds[bnd] - x0[0])};
888  if ( p2[1] >= bounds[2] && p2[1] <= bounds[3] &&
889  p2[2] >= bounds[4] && p2[2] <= bounds[5] ) {
890  intersects_tpc = true;
891  break;
892  }
893  }
894  else if (bnd>=2 && bnd<4) {
895  double p2[3] = {x0[0] + (dx[0]/dx[1])*(bounds[bnd] - x0[1]), bounds[bnd], x0[2] + (dx[2]/dx[1])*(bounds[bnd] - x0[1])};
896  if ( p2[0] >= bounds[0] && p2[0] <= bounds[1] &&
897  p2[2] >= bounds[4] && p2[2] <= bounds[5] ) {
898  intersects_tpc = true;
899  break;
900  }
901  }
902  else if (bnd>=4) {
903  double p2[3] = {x0[0] + (dx[0]/dx[2])*(bounds[bnd] - x0[2]), x0[1] + (dx[1]/dx[2])*(bounds[bnd] - x0[2]), bounds[bnd]};
904  if ( p2[0] >= bounds[0] && p2[0] <= bounds[1] &&
905  p2[1] >= bounds[2] && p2[1] <= bounds[3] ) {
906  intersects_tpc = true;
907  break;
908  }
909  }
910  }
911 
912  return intersects_tpc;
913 }
914 
915 void evgendp::Trigger::GetTPCSize( double tpc[]){
916 
917  //art::ServiceHandle<geo::Geometry> geom;
918 
919  double minx=0, miny=0, minz=0;
920  double maxx=0, maxy=0, maxz=0;
921  for (size_t c = 0; c < geom->Ncryostats(); c++){
922  const geo::CryostatGeo& cryostat = geom->Cryostat(c);
923  for (size_t t = 0; t < cryostat.NTPC(); t++){
924  const geo::TPCGeo& tpcg = cryostat.TPC(t);
925  if (tpcg.MinX() < minx) minx = tpcg.MinX();
926  if (tpcg.MaxX() > maxx) maxx = tpcg.MaxX();
927  if (tpcg.MinY() < miny) miny = tpcg.MinY();
928  if (tpcg.MaxY() > maxy) maxy = tpcg.MaxY();
929  if (tpcg.MinZ() < minz) minz = tpcg.MinZ();
930  if (tpcg.MaxZ() > maxz) maxz = tpcg.MaxZ();
931  }
932  }
933 
934  tpc[0] = minx;
935  tpc[1] = maxx;
936  tpc[2] = miny;
937  tpc[3] = maxy;
938  tpc[4] = minz;
939  tpc[5] = maxz;
940 
941  return;
942 }
943 
944 void evgendp::Trigger::GetCryoSize( double cryo[]){
945 
946  //;
947 
948  double dummy[6] = {0};
949  for(unsigned int c = 0; c < geom->Ncryostats(); ++c){
950  geom->CryostatBoundaries(dummy, c);
951  }
952 
953  for(int i=0;i<6;i++){cryo[i] = dummy[i];}
954 
955  return;
956 }
957 
958 void evgendp::Trigger::ProjectToBoxEdge( const double xyz[],
959  const double indxyz[],
960  const double xlo,
961  const double xhi,
962  const double ylo,
963  const double yhi,
964  const double zlo,
965  const double zhi,
966  double xyzout[] ){
967 
968 
969  //we want to project backwards, so take mirror of momentum
970  const double dxyz[3]={-indxyz[0],-indxyz[1],-indxyz[2]};
971 
972  // Compute the distances to the x/y/z walls
973  double dx = 99.E99;
974  double dy = 99.E99;
975  double dz = 99.E99;
976  if (dxyz[0] > 0.0) { dx = (xhi-xyz[0])/dxyz[0]; }
977  else if (dxyz[0] < 0.0) { dx = (xlo-xyz[0])/dxyz[0]; }
978  if (dxyz[1] > 0.0) { dy = (yhi-xyz[1])/dxyz[1]; }
979  else if (dxyz[1] < 0.0) { dy = (ylo-xyz[1])/dxyz[1]; }
980  if (dxyz[2] > 0.0) { dz = (zhi-xyz[2])/dxyz[2]; }
981  else if (dxyz[2] < 0.0) { dz = (zlo-xyz[2])/dxyz[2]; }
982 
983 
984  // Choose the shortest distance
985  double d = 0.0;
986  if (dx < dy && dx < dz) d = dx;
987  else if (dy < dz && dy < dx) d = dy;
988  else if (dz < dx && dz < dy) d = dz;
989 
990  // Make the step
991  for (int i = 0; i < 3; ++i) {
992  xyzout[i] = xyz[i] + dxyz[i]*d;
993  }
994 
995 }
996 
997 void evgendp::Trigger::MakeTrigger(CLHEP::HepRandomEngine& engine) {
998 
999  //get the coordinates of the tpc and an active volume arount it
1000  double tpc[6] ={0.}; this->GetTPCSize(tpc);
1001  for(int i=0; i<6; i++){ tpc[i] += fTPCBuffer[i]; }
1002 
1003  //get the coordinates of the cryo + a buffer around it
1004  double cryo[6] ={0.}; this->GetCryoSize(cryo);
1005  for(int i=0; i<6; i++){ cryo[i] += fCryoBuffer[i]; }
1006 
1007  CLHEP::RandFlat flat(engine);
1008 
1009  //choose a random muon
1010  if( fMuonList.size() == 0){
1011  mf::LogInfo("Gen311") << "Trigger muon not found! Only Background";
1012  return;
1013  }
1014 
1015  fTriggerMu = fMuonList.at( (int)flat()*fMuonList.size() );
1016 
1017  double px=0,py=0,pz=0;
1018  double p=0, theta=0, phi=0;
1019 
1020  px = fTriggerMu.Momentum().X();
1021  py = fTriggerMu.Momentum().Y();
1022  pz = fTriggerMu.Momentum().Z();
1023 
1024 
1025  p = sqrt(px*px+py*py+pz*pz);
1026  theta = acos(px/p);
1027  phi = this->GetPhi( py, pz );
1028 
1029  double xyz[3] ={0.};
1030  xyz[0]=(tpc[5]-tpc[4])/2-tpc[5];
1031  xyz[1]=(tpc[1]-tpc[0])/2-tpc[1];
1032  xyz[2]=(tpc[3]-tpc[2])/2-tpc[2];
1033 
1034  //define direction
1035  double cos_x=cos(theta);
1036  double cos_y=sin(phi)*sin(theta);
1037  double cos_z=cos(phi)*sin(theta);
1038  double dxyz[3] = { cos_z, cos_x, cos_y };
1039 
1040  //get cr impact size along u and v
1041  double length[2]={0.}; //0 along u, 1 along v
1042  double corner[3]={0.};
1043  double rdm_start[3] ={0.};
1044  double xyzo[3]={0.};
1045 
1046  //loop over the tpc boundaries and project them on u and v
1047  for(int i=0; i<2; i++){
1048  for(int j=2; j<4; j++){
1049  for(int k=4; k<6; k++){
1050 
1051  double dot=0;
1052  double proj[3]={0.}; //projection on the plane
1053  double u=0; double v=0;
1054 
1055  //coordinates of the tpc corner
1056  corner[0] = tpc[k];
1057  corner[1] = tpc[i];
1058  corner[2] = tpc[j];
1059 
1060  //now get the dot product between the corner vector and the plane versor
1061  for( int p=0; p<3; p++ ){ dot+=(corner[p]-xyz[p])*dxyz[p]; }
1062  for( int p=0; p<3; p++ ){ proj[p] = corner[p]-(dot*dxyz[p]); }
1063 
1064  proj[0] -= (tpc[5]-tpc[4])/2; //NB: not really elegant...makes things work though
1065 
1066  //build the rotation matrix;
1067  double R[3][3];
1068  double (*p_R)[3][3]=&R;
1069  this->GetMatrix(theta, phi, p_R);
1070 
1071  //project proj along u and pick the longest
1072  for( int p=0; p<3; p++ ){ u += (*p_R)[p][0]*proj[p]; }
1073  if(length[0] < u){ length[0] = u; }
1074 
1075  //project proj along v and pick the longest projection
1076  for( int p=0; p<3; p++ ){ v += (*p_R)[p][2]*proj[p]; }
1077  if(length[1] < v){ length[1] = v; }
1078 
1079  }//end for k
1080  }//end for j
1081  } //end for i
1082 
1083  bool is_inside=false;
1084  int iteration = 20; //NB: It is harcoded
1085 
1086  while(!is_inside && iteration > 0){
1087 
1088  //We extract a random start over the plane u, v
1089  double u = flat()*2*length[0]-length[0];
1090  double v = flat()*2*length[1]-length[1];;
1091 
1092  //now rotate along the r direction
1093  double urv[3] ={ u, 0, v };
1094  double dir[3]={ 0., 0., 0. };
1095  this->DoRotation( urv, dir, theta, phi );
1096 
1097  //parse the correct direction of our reference system
1098  rdm_start[0] = (double)dir[1];
1099  rdm_start[1] = (double)dir[2];
1100  rdm_start[2] = (double)dir[0]+(tpc[5]-tpc[4])/2;
1101 
1102  double dx[3]={px,py,pz};
1103  this->ProjectToBoxEdge(rdm_start, dx, cryo[0], cryo[1], cryo[2], cryo[3], cryo[4], cryo[5], xyzo);
1104 
1105  if( this->Intersect(xyzo, dx, tpc) ){
1106  is_inside=true;
1107  //mf::LogInfo("Gen311")<< "======> " << iteration;
1108  }else{
1109  //mf::LogInfo("Gen311")<< "======> " << iteration;
1110  iteration--;
1111  }
1112  }//end while
1113 
1114 
1115  if(iteration==0){
1116  mf::LogInfo("Gen311") << "Trigger muon not found in 20 iterations. Only Background";
1117  }
1118 
1119  /*
1120 
1121  double rdm_start[3] ={0.};
1122  rdm_start[0] = 0;
1123  rdm_start[1] = flat()*(tpc[3]-tpc[2])-(tpc[3]-tpc[2])/2;
1124  rdm_start[2] = flat()*(tpc[5]-tpc[4])-(tpc[5]-tpc[4])/2;
1125 
1126  */
1127 
1128  fTriggerID = fTriggerMu.TrackId();
1129  fTriggerPosX = rdm_start[0];
1130  fTriggerPosY = rdm_start[1];
1131  fTriggerPosZ = rdm_start[2];
1132  fTriggerPosT = 0;
1133  fTriggerPos.SetXYZT(rdm_start[0],rdm_start[1],rdm_start[2],0);
1134  fTriggerOffsetX = rdm_start[0] - fTriggerMu.Position().X();
1135  fTriggerOffsetY = rdm_start[1] - fTriggerMu.Position().Y();
1136  fTriggerOffsetZ = rdm_start[2] - fTriggerMu.Position().Z();
1137  fTriggerOffsetT = 0 - fTriggerMu.Position().T();
1138 
1139  return;
1140  }//end make trigger
1141 
1142 //******************************************************************************************************************
1143 
1145  //Fetch the particle generated by GetParticle
1146 
1147  fRun = e.id().run();
1148  fEvent = e.id().event();
1149 
1150  std::unique_ptr< std::vector<simb::MCTruth> > truthcol(new std::vector<simb::MCTruth>);
1151 
1153 
1154  simb::MCTruth truth;
1155  truth.SetOrigin(simb::kCosmicRay);
1156 
1157  simb::MCTruth pretruth;
1158 
1159  GetSample(pretruth);
1160  mf::LogInfo("CORSIKAGendp")<<"GetSample number of particles returned: "<<pretruth.NParticles()<<"\n";
1161  // loop over particles in the truth object
1162 
1163  //add a buffer box around the cryostat bounds to increase the acceptance and account for scattering
1164  //By default, the buffer box has zero size
1165 
1166  for(int i = 0; i < pretruth.NParticles(); ++i){
1167  simb::MCParticle particle = pretruth.GetParticle(i);
1168 
1169  TLorentzVector v4 = particle.Position();
1170  const TLorentzVector& p4 = particle.Momentum();
1171  double x0[3] = {v4.X(), v4.Y(), v4.Z() };
1172  double dx[3] = {p4.Px(), p4.Py(), p4.Pz()};
1173  // now check if the particle goes through any cryostat in the detector
1174  // if so, add it to the truth object.
1175  for(unsigned int c = 0; c < geom->Ncryostats(); ++c){
1176  double bounds[6] = {0.};
1177  geom->CryostatBoundaries(bounds, c);
1178 
1179  //add a buffer box around the cryostat bounds to increase the acceptance and account for scattering
1180  //By default, the buffer box has zero size
1181  for (unsigned int cb=0; cb<6; cb++){
1182  bounds[cb] = bounds[cb]+fBuffBox[cb];
1183  }
1184 
1185  //calculate the intersection point with each cryostat surface
1186  bool intersects_cryo = false;
1187  for (int bnd=0; bnd!=6; ++bnd) {
1188  if (bnd<2) {
1189  double p2[3] = {bounds[bnd], x0[1] + (dx[1]/dx[0])*(bounds[bnd] - x0[0]), x0[2] + (dx[2]/dx[0])*(bounds[bnd] - x0[0])};
1190  if ( p2[1] >= bounds[2] && p2[1] <= bounds[3] &&
1191  p2[2] >= bounds[4] && p2[2] <= bounds[5] ) {
1192  intersects_cryo = true;
1193  break;
1194  }
1195  }
1196  else if (bnd>=2 && bnd<4) {
1197  double p2[3] = {x0[0] + (dx[0]/dx[1])*(bounds[bnd] - x0[1]), bounds[bnd], x0[2] + (dx[2]/dx[1])*(bounds[bnd] - x0[1])};
1198  if ( p2[0] >= bounds[0] && p2[0] <= bounds[1] &&
1199  p2[2] >= bounds[4] && p2[2] <= bounds[5] ) {
1200  intersects_cryo = true;
1201  break;
1202  }
1203  }
1204  else if (bnd>=4) {
1205  double p2[3] = {x0[0] + (dx[0]/dx[2])*(bounds[bnd] - x0[2]), x0[1] + (dx[1]/dx[2])*(bounds[bnd] - x0[2]), bounds[bnd]};
1206  if ( p2[0] >= bounds[0] && p2[0] <= bounds[1] &&
1207  p2[1] >= bounds[2] && p2[1] <= bounds[3] ) {
1208  intersects_cryo = true;
1209  break;
1210  }
1211  }
1212  }
1213 
1214  if (intersects_cryo){
1215  truth.Add(particle);
1216  break; //leave loop over cryostats to avoid adding particle multiple times
1217  }// end if particle goes into a cryostat
1218  }// end loop over cryostats in the detector
1219 
1220  }// loop on particles
1221 
1222  mf::LogInfo("Gen311")<<"Number of particles from getsample crossing cryostat + bounding box: "<<truth.NParticles()<<"\n";
1223 
1224  truthcol->push_back(truth);
1225  e.put(std::move(truthcol));
1226 
1227  return;
1228  }
1229 
1230 
1232 
1233 //#endif // EVGEN_311Gen_H
static QCString name
Definition: declinfo.cpp:673
CLHEP::HepRandomEngine & fPoisEngine
intermediate_table::iterator iterator
base_engine_t & createEngine(seed_t seed)
void beginJob() override
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
void AddMuon(simb::MCParticle particle)
const TLorentzVector & Position(const int i=0) const
Definition: MCParticle.h:219
int PdgCode() const
Definition: MCParticle.h:212
Format
Definition: utils.h:7
void DoRotation(double urv[], double dir[], double theta, double phi)
art::ServiceHandle< geo::Geometry > geom
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
Definition: MCParticle.h:257
double wrapvarBoxNo(const double var, const double low, const double high, int &boxno)
Encapsulate the construction of a single cyostat.
void produce(art::Event &e) override
Collect all the geometry header files together.
void SetOrigin(simb::Origin_t origin)
Definition: MCTruth.h:82
std::vector< double > fActiveVolumeCut
Active volume cut.
std::string string
Definition: nybbler.cc:12
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
std::vector< double > fCryoBuffer
double fShowerBounds[6]
Boundaries of area over which showers are to be distributed.
void WorldBox(double *xlo, double *xhi, double *ylo, double *yhi, double *zlo, double *zhi) const
Fills the arguments with the boundaries of the world.
double wrapvar(const double var, const double low, const double high)
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
constexpr T pow(T x)
Definition: pow.h:72
double MinX() const
Returns the world x coordinate of the start of the box.
Definition: BoxBoundedGeo.h:88
Geometry information for a single TPC.
Definition: TPCGeo.h:38
std::vector< double > fShowerFluxConstants
Set of flux constants to be associated with each shower data file.
def GetPhi(pos, x0, pars)
Definition: tracks.py:36
struct sqlite3_stmt sqlite3_stmt
double fSampleTime
Duration of sample [s].
void SetTPCBuffer(std::vector< double > buffer)
double MaxX() const
Returns the world x coordinate of the end of the box.
Definition: BoxBoundedGeo.h:91
double GetTriggerOffsetT()
int NParticles() const
Definition: MCTruth.h:75
void GetCryoSize(double cryo[])
string dir
Geometry information for a single cryostat.
Definition: CryostatGeo.h:43
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
Particle class.
double GetTriggerMomX()
TLorentzVector fTriggerPos
RunNumber_t run() const
Definition: EventID.h:98
void CryostatBoundaries(double *boundaries, geo::CryostatID const &cid) const
Returns the boundaries of the specified cryostat.
art framework interface to geometry description
Definition: Run.h:17
void reconfigure(fhicl::ParameterSet const &p)
TLorentzVector GetTriggerPos()
double GetTriggerPosX()
void MakeTrigger(CLHEP::HepRandomEngine &engine)
double GetTriggerOffsetX()
bool InTPC(const simb::MCParticle particle)
void ProjectToBoxEdge(const double xyz[], const double indxyz[], const double xlo, const double xhi, const double ylo, const double yhi, const double zlo, const double zhi, double xyzout[])
ifdh_ns::ifdh * fIFDH
(optional) flux file handling
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
std::vector< double > fNShowersPerEvent
Number of showers to put in each event of duration fSampleTime; one per showerinput.
std::string DetectorName() const
Returns a string with the name of the detector, as configured.
sqlite3 * fdb[5]
Pointers to sqlite3 database object, max of 5.
double GetTriggerMomT()
int fShowerInputs
Number of shower inputs to process from.
std::string getenv(std::string const &name)
Definition: getenv.cc:15
def move(depos, offset)
Definition: depos.py:107
void GetMatrix(double theta, double phi, double(*p_R)[3][3])
double fProjectToHeight
Height to which particles will be projected [cm].
double MinZ() const
Returns the world z coordinate of the start of the box.
CLHEP::HepRandomEngine & fGenEngine
p
Definition: test.py:223
std::vector< int > fMaxShowers
unsigned int NTPC() const
Number of TPCs in this cryostat.
Definition: CryostatGeo.h:181
std::vector< std::string > fShowerInputFiles
Set of CORSIKA shower data files to use.
void GetTPCSize(double tpc[])
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
double GetPhi(const double py, const double pz)
Gen311(fhicl::ParameterSet const &p)
double GetTriggerOffsetZ()
BoundingBox bounds(int x, int y, int w, int h)
Definition: main.cpp:37
double fToffset_corsika
Timing offset to account for propagation time through atmosphere, populated from db.
void GetSample(simb::MCTruth &)
struct sqlite3 sqlite3
double MaxY() const
Returns the world y coordinate of the end of the box.
double GetTriggerPosY()
const simb::MCParticle & GetParticle(int i) const
Definition: MCTruth.h:76
double GetTriggerMomZ()
Gen311 & operator=(Gen311 const &)=delete
#define M_PI
Definition: includeROOT.h:54
double GetTriggerOffsetY()
void beginRun(art::Run &run) override
double fRandomYZShift
Each shower will be shifted by a random amount in xz so that showers won&#39;t repeatedly sample the same...
void Add(simb::MCParticle const &part)
Definition: MCTruth.h:80
std::vector< double > fBuffBox
Buffer box extensions to cryostat in each direction (6 of them: x_lo,x_hi,y_lo,y_hi,z_lo,z_hi) [cm].
double fShowerAreaExtension
Extend distribution of corsika particles in x,z by this much (e.g. 1000 will extend 10 m in -x...
int var
Definition: 018_def.c:9
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
Definition: CryostatGeo.cxx:93
void SetCryoBuffer(std::vector< double > buffer)
double MaxZ() const
Returns the world z coordinate of the end of the box.
std::string pattern
Definition: regex_t.cc:35
const TLorentzVector & Momentum(const int i=0) const
Definition: MCParticle.h:220
#define MF_LOG_DEBUG(id)
double GetTriggerPosZ()
simb::MCParticle fTriggerMu
cet::LibraryManager dummy("noplugin")
EventNumber_t event() const
Definition: EventID.h:116
std::vector< double > fTPCBuffer
std::vector< simb::MCParticle > fMuonList
void ProjectToBoxEdge(const double xyz[], const double dxyz[], double xlo, double xhi, double ylo, double yhi, double zlo, double zhi, double xyzout[])
Definition: geo.h:49
art::ServiceHandle< geo::Geometry > geom
Event generator information.
Definition: MCTruth.h:32
bool fUseIFDH
< List of pdg codes for particles that can be potentially used as triggers
double GetTriggerPosT()
LArSoft geometry interface.
Definition: ChannelGeo.h:16
double MinY() const
Returns the world y coordinate of the start of the box.
EventID id() const
Definition: Event.cc:34
bool Intersect(const double x0[], const double dx[], const double bounds[])
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Cosmic rays.
Definition: MCTruth.h:24
QTextStream & endl(QTextStream &s)
TLorentzVector GetTriggerMom()
double fToffset
Time offset of sample, defaults to zero (no offset) [s].
double GetTriggerMomY()
std::vector< double > fLeadingParticlesList