LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
LArG4_module.cc
Go to the documentation of this file.
1 
20 
21 #ifndef LARG4_LARG4_H
22 #define LARG4_LARG4_H 1
23 
26 
27 // C++ Includes
28 #include <sstream> // std::ostringstream
29 #include <vector> // std::ostringstream
30 #include <map> // std::ostringstream
31 #include <set> // std::ostringstream
32 #include <iostream>
33 #include <sys/stat.h>
34 
35 // Framework includes
39 #include "fhiclcpp/ParameterSet.h"
48 #include "cetlib_except/exception.h"
49 #include "cetlib/search_path.h"
50 
51 // art extensions
53 
54 // LArSoft Includes
68 #include "larcorealg/CoreUtils/ParticleFilters.h" // util::PositionInVolumeFilter
70 #include "lardataalg/MCDumpers/MCDumpers.h" // sim::dump namespace
83 
84 // G4 Includes
85 #include "Geant4/G4RunManager.hh"
86 #include "Geant4/G4UImanager.hh"
87 #include "Geant4/G4VUserDetectorConstruction.hh"
88 #include "Geant4/G4VUserPrimaryGeneratorAction.hh"
89 #include "Geant4/G4VUserPhysicsList.hh"
90 #include "Geant4/G4UserRunAction.hh"
91 #include "Geant4/G4UserEventAction.hh"
92 #include "Geant4/G4UserTrackingAction.hh"
93 #include "Geant4/G4UserSteppingAction.hh"
94 #include "Geant4/G4UserStackingAction.hh"
95 #include "Geant4/G4VisExecutive.hh"
96 #include "Geant4/G4VUserPhysicsList.hh"
97 #include "Geant4/G4SDManager.hh"
98 #include "Geant4/G4LogicalVolumeStore.hh"
99 #include "Geant4/Randomize.hh"
100 #include "Geant4/G4SDManager.hh"
101 #include "Geant4/G4VSensitiveDetector.hh"
102 #include "Geant4/globals.hh"
103 
104 // ROOT Includes
105 #include "TGeoManager.h"
106 
107 //For energy depositions
109 
110 
111 // Forward declarations
112 class G4RunManager;
113 class G4UImanager;
114 class G4VisExecutive;
115 
116 #if defined __clang__
117  #pragma clang diagnostic push
118  #pragma clang diagnostic ignored "-Wunused-private-field"
119 #endif
120 
122 namespace larg4 {
123 
124  // Forward declarations within namespace.
125  class LArVoxelListAction;
126  class ParticleListAction;
127 
297  class LArG4 : public art::EDProducer{
298  public:
299 
301  explicit LArG4(fhicl::ParameterSet const& pset);
302  virtual ~LArG4();
303 
307  void produce (art::Event& evt);
308  void beginJob();
309  void beginRun(art::Run& run);
310 
311  private:
313  larg4::LArVoxelListAction* flarVoxelListAction;
315 
316  std::string fG4PhysListName;
317  std::string fG4MacroPath;
318  bool fCheckOverlaps;
325  double fOffPlaneMargin = 0.;
326  std::vector<std::string> fInputLabels;
328  std::vector<std::string> fKeepParticlesInVolumes;
329 
331 
333  std::unique_ptr<util::PositionInVolumeFilter> CreateParticleVolumeFilter
334  (std::set<std::string> const& vol_names) const;
335 
336  };
337 
338 } // namespace LArG4
339 
340 namespace larg4 {
341 
342  //----------------------------------------------------------------------
343  // Constructor
345  : fG4Help (0)
346  , flarVoxelListAction (0)
347  , fparticleListAction (0)
348  , fG4PhysListName (pset.get< std::string >("G4PhysListName","larg4::PhysicsList"))
349  , fCheckOverlaps (pset.get< bool >("CheckOverlaps",false) )
350  , fdumpParticleList (pset.get< bool >("DumpParticleList",false) )
351  , fdumpSimChannels (pset.get< bool >("DumpSimChannels", false) )
352  , fStoreReflected (false)
353  , fSmartStacking (pset.get< int >("SmartStacking",0) )
354  , fOffPlaneMargin (pset.get< double >("ChargeRecoveryMargin",0.0) )
355  , fKeepParticlesInVolumes (pset.get< std::vector< std::string > >("KeepParticlesInVolumes",{}))
356  , fSparsifyTrajectories (pset.get< bool >("SparsifyTrajectories",false) )
357  {
358  LOG_DEBUG("LArG4") << "Debug: LArG4()";
360 
361  if (pset.has_key("Seed")) {
363  << "The configuration of LArG4 module has the discontinued 'Seed' parameter.\n"
364  "Seeds are now controlled by two parameters: 'GEANTSeed' and 'PropagationSeed'.";
365  }
366  // setup the random number service for Geant4, the "G4Engine" label is a
367  // special tag setting up a global engine for use by Geant4/CLHEP;
368  // obtain the random seed from NuRandomService,
369  // unless overridden in configuration with key "Seed" or "GEANTSeed"
371  ->createEngine(*this, "G4Engine", "GEANT", pset, "GEANTSeed");
372  // same thing for the propagation engine:
374  ->createEngine(*this, "HepJamesRandom", "propagation", pset, "PropagationSeed");
375 
376  //get a list of generators to use, otherwise, we'll end up looking for anything that's
377  //made an MCTruth object
378  bool useInputLabels = pset.get_if_present< std::vector<std::string> >("InputLabels",fInputLabels);
379  if(!useInputLabels) fInputLabels.resize(0);
380 
383 
384  if(!lgp->NoPhotonPropagation()){
385  try {
388  }
389  catch (art::Exception const& e) {
390  // If the service is not configured, then just keep the default
391  // false for reflected light. If reflected photons are simulated
392  // without PVS they will show up in the regular SimPhotons collection
393  if (e.categoryCode() != art::errors::ServiceNotFound) throw;
394  }
395 
396  if(!fUseLitePhotons) {
397  produces< std::vector<sim::SimPhotons> >();
398  if(fStoreReflected) {
399  produces< std::vector<sim::SimPhotons> >("Reflected");
400  }
401  }
402  else{
403  produces< std::vector<sim::SimPhotonsLite> >();
404  produces< std::vector<sim::OpDetBacktrackerRecord> >();
405  if(fStoreReflected) {
406  produces< std::vector<sim::SimPhotonsLite> >("Reflected");
407  produces< std::vector<sim::OpDetBacktrackerRecord> >("Reflected");
408  }
409  }
410  }
411 
412  if(lgp->FillSimEnergyDeposits()){
413  produces < std::vector<sim::SimEnergyDeposit> >("TPCActive");
414  produces < std::vector<sim::SimEnergyDeposit> >("Other");
415  }
416 
417  produces< std::vector<simb::MCParticle> >();
418  if(!lgp->NoElectronPropagation()) produces< std::vector<sim::SimChannel> >();
419  produces< std::vector<sim::AuxDetSimChannel> >();
420  produces< art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo> >();
421 
422  // constructor decides if initialized value is a path or an environment variable
423  cet::search_path sp("FW_SEARCH_PATH");
424 
425  sp.find_file(pset.get< std::string >("GeantCommandFile"), fG4MacroPath);
426  struct stat sb;
427  if (fG4MacroPath.empty() || stat(fG4MacroPath.c_str(), &sb)!=0)
428  // failed to resolve the file name
429  throw cet::exception("NoG4Macro") << "G4 macro file "
430  << fG4MacroPath
431  << " not found!\n";
432 
433  }
434 
435  //----------------------------------------------------------------------
436  // Destructor
438  {
439  if(fG4Help) delete fG4Help;
440  }
441 
442  //----------------------------------------------------------------------
444  {
447 
451 
452  // Get the logical volume store and assign material properties
455  MPL->UpdateGeometry(G4LogicalVolumeStore::GetInstance());
456 
457  // Tell the detector about the parallel LAr voxel geometry.
458  std::vector<G4VUserParallelWorld*> pworlds;
459  // Intialize G4 physics and primary generator action
460  fG4Help->InitPhysics();
461 
462  // create the ionization and scintillation calculator;
463  // this is a singleton (!) so it does not make sense
464  // to create it in LArVoxelReadoutGeometry
465  IonizationAndScintillation::CreateInstance(rng->getEngine("propagation"));
466 
467  // make a parallel world for each TPC in the detector
468  LArVoxelReadoutGeometry::Setup_t readoutGeomSetupData;
469  readoutGeomSetupData.readoutSetup.offPlaneMargin = fOffPlaneMargin;
470  readoutGeomSetupData.readoutSetup.propGen
471  = &(rng->getEngine("propagation"));
472  pworlds.push_back(new LArVoxelReadoutGeometry
473  ("LArVoxelReadoutGeometry", readoutGeomSetupData)
474  );
475  pworlds.push_back( new OpDetReadoutGeometry( geom->OpDetGeoName() ));
476  pworlds.push_back( new AuxDetReadoutGeometry("AuxDetReadoutGeometry") );
477 
478  fG4Help->SetParallelWorlds(pworlds);
479 
480  // moved up
481  // Intialize G4 physics and primary generator action
482  fG4Help->InitPhysics();
483 
484  // Use the UserActionManager to handle all the Geant4 user hooks.
486 
487  // User-action class for accumulating LAr voxels.
489 
490  // UserAction for getting past a bug in v4.9.4.p02 of Geant4.
491  // This action will not be used once the bug has been fixed
492  // The techniques used in this UserAction are not to be repeated
493  // as in general they are a very bad idea, ie they take a const
494  // pointer and jump through hoops to change it
495  // 08-Apr-2014 WGS: It appears that with the shift to Geant 4.9.6 or
496  // above, there's no longer any need for the "Bad Idea Action" fix.
497  // larg4::G4BadIdeaAction *bia = new larg4::G4BadIdeaAction(fSmartStacking);
498  // uaManager->AddAndAdoptAction(bia);
499 
500  // remove IonizationAndScintillationAction for now as we are ensuring
501  // the Reset for each G4Step within the G4SensitiveVolumes
502  //larg4::IonizationAndScintillationAction *iasa = new larg4::IonizationAndScintillationAction();
503  //uaManager->AddAndAdoptAction(iasa);
504 
505  // User-action class for accumulating particles and trajectories
506  // produced in the detector.
508  lgp->StoreTrajectories(),
509  lgp->KeepEMShowerDaughters());
511 
512  // UserActionManager is now configured so continue G4 initialization
514 
515  // With an enormous detector with lots of rock ala LAr34 (nee LAr20)
516  // we need to be smarter about stacking.
517  if (fSmartStacking>0){
518  G4UserStackingAction* stacking_action = new LArStackingAction(fSmartStacking);
519  fG4Help->GetRunManager()->SetUserAction(stacking_action);
520  }
521 
522 
523 
524  }
525 
527  // prepare the filter object (null if no filtering)
528 
529  std::set<std::string> volnameset(fKeepParticlesInVolumes.begin(), fKeepParticlesInVolumes.end());
531 
532  }
533 
534  std::unique_ptr<util::PositionInVolumeFilter> LArG4::CreateParticleVolumeFilter
535  (std::set<std::string> const& vol_names) const
536  {
537 
538  // if we don't have favourite volumes, don't even bother creating a filter
539  if (vol_names.empty()) return {};
540 
541  auto const& geom = *art::ServiceHandle<geo::Geometry>();
542 
543  std::vector<std::vector<TGeoNode const*>> node_paths
544  = geom.FindAllVolumePaths(vol_names);
545 
546  // collection of interesting volumes
548  GeoVolumePairs.reserve(node_paths.size()); // because we are obsessed
549 
550  //for each interesting volume, follow the node path and collect
551  //total rotations and translations
552  for (size_t iVolume = 0; iVolume < node_paths.size(); ++iVolume) {
553  std::vector<TGeoNode const*> path = node_paths[iVolume];
554 
555  TGeoTranslation* pTransl = new TGeoTranslation(0.,0.,0.);
556  TGeoRotation* pRot = new TGeoRotation();
557  for (TGeoNode const* node: path) {
558  TGeoTranslation thistranslate(*node->GetMatrix());
559  TGeoRotation thisrotate(*node->GetMatrix());
560  pTransl->Add(&thistranslate);
561  *pRot=*pRot * thisrotate;
562  }
563 
564  //for some reason, pRot and pTransl don't have tr and rot bits set correctly
565  //make new translations and rotations so bits are set correctly
566  TGeoTranslation* pTransl2 = new TGeoTranslation(pTransl->GetTranslation()[0],
567  pTransl->GetTranslation()[1],
568  pTransl->GetTranslation()[2]);
569  double phi=0.,theta=0.,psi=0.;
570  pRot->GetAngles(phi,theta,psi);
571  TGeoRotation* pRot2 = new TGeoRotation();
572  pRot2->SetAngles(phi,theta,psi);
573 
574  TGeoCombiTrans* pTransf = new TGeoCombiTrans(*pTransl2,*pRot2);
575 
576  GeoVolumePairs.emplace_back(node_paths[iVolume].back()->GetVolume(), pTransf);
577 
578  }
579 
580  return std::make_unique<util::PositionInVolumeFilter>(std::move(GeoVolumePairs));
581 
582  } // CreateParticleVolumeFilter()
583 
584 
586  {
587  LOG_DEBUG("LArG4") << "produce()";
588 
589  // loop over the lists and put the particles and voxels into the event as collections
590  std::unique_ptr< std::vector<sim::SimChannel> > scCol (new std::vector<sim::SimChannel>);
591  std::unique_ptr< std::vector< sim::AuxDetSimChannel > > adCol (new std::vector<sim::AuxDetSimChannel> );
592  auto tpassn = std::make_unique<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
593  std::unique_ptr< std::vector<simb::MCParticle> > partCol (new std::vector<simb::MCParticle >);
594  std::unique_ptr< std::vector<sim::SimPhotons> > PhotonCol (new std::vector<sim::SimPhotons>);
595  std::unique_ptr< std::vector<sim::SimPhotons> > PhotonColRefl (new std::vector<sim::SimPhotons>);
596  std::unique_ptr< std::vector<sim::SimPhotonsLite> > LitePhotonCol (new std::vector<sim::SimPhotonsLite>);
597  std::unique_ptr< std::vector<sim::SimPhotonsLite> > LitePhotonColRefl (new std::vector<sim::SimPhotonsLite>);
598  std::unique_ptr< std::vector< sim::OpDetBacktrackerRecord > > cOpDetBacktrackerRecordCol (new std::vector<sim::OpDetBacktrackerRecord>);
599  std::unique_ptr< std::vector< sim::OpDetBacktrackerRecord > > cOpDetBacktrackerRecordColRefl (new std::vector<sim::OpDetBacktrackerRecord>);
600 
601 
602  art::PtrMaker<simb::MCParticle> makeMCPartPtr(evt, *this);
603 
604  //for energy deposits
605  std::unique_ptr< std::vector<sim::SimEnergyDeposit> > edepCol_TPCActive (new std::vector<sim::SimEnergyDeposit>);
606  std::unique_ptr< std::vector<sim::SimEnergyDeposit> > edepCol_Other (new std::vector<sim::SimEnergyDeposit>);
607 
608  // Fetch the lists of LAr voxels and particles.
611 
612  // Clear the detected photon table
614  if(lgp->FillSimEnergyDeposits())
616 
617  // reset the track ID offset as we have a new collection of interactions
619 
620  //look to see if there is any MCTruth information for this
621  //event
622  std::vector< art::Handle< std::vector<simb::MCTruth> > > mclists;
623  if(fInputLabels.size()==0)
624  evt.getManyByType(mclists);
625  else{
626  mclists.resize(fInputLabels.size());
627  for(size_t i=0; i<fInputLabels.size(); i++)
628  evt.getByLabel(fInputLabels[i],mclists[i]);
629  }
630 
631  unsigned int nGeneratedParticles = 0;
632 
633  // Need to process Geant4 simulation for each interaction separately.
634  for(size_t mcl = 0; mcl < mclists.size(); ++mcl){
635 
636  art::Handle< std::vector<simb::MCTruth> > mclistHandle = mclists[mcl];
637 
638  for(size_t m = 0; m < mclistHandle->size(); ++m){
639  art::Ptr<simb::MCTruth> mct(mclistHandle, m);
640 
641  LOG_DEBUG("LArG4") << *(mct.get());
642 
643  // The following tells Geant4 to track the particles in this interaction.
644  fG4Help->G4Run(mct);
645 
646  // receive the particle list
648 
649  for(auto const& partPair: particleList) {
650  simb::MCParticle& p = *(partPair.second);
651  ++nGeneratedParticles;
652 
653  // if the particle has been marked as dropped, we don't save it
654  // (as of LArSoft ~v5.6 this does not ever happen because
655  // ParticleListAction has already taken care of deleting them)
656  if (ParticleListAction::isDropped(&p)) continue;
657 
658  sim::GeneratedParticleInfo const truthInfo{
660  };
661  if (!truthInfo.hasGeneratedParticleIndex() && (p.Mother() == 0)) {
662  // this means it's primary but with no information; logic error!!
664  error << "Failed to match primary particle:\n";
665  sim::dump::DumpMCParticle(error, p, " ");
666  error << "\nwith particles from the truth record '"
667  << mclistHandle.provenance()->inputTag() << "':\n";
668  sim::dump::DumpMCTruth(error, *mct, 2U, " "); // 2 points per line
669  error << "\n";
670  throw error;
671  }
672 
674 
675  partCol->push_back(std::move(p));
676 
677  tpassn->addSingle(mct, makeMCPartPtr(partCol->size() - 1), truthInfo);
678 
679  } // for(particleList)
680 
681 
682  // Has the user request a detailed dump of the output objects?
683  if (fdumpParticleList){
684  mf::LogInfo("LArG4") << "Dump sim::ParticleList; size()="
685  << particleList.size() << "\n"
686  << particleList;
687  }
688 
689  }
690 
691  }// end loop over interactions
692 
693  // get the electrons from the LArVoxelReadout sensitive detector
694  // Get the sensitive-detector manager.
695  G4SDManager* sdManager = G4SDManager::GetSDMpointer();
696 
697  // Find the sensitive detector with the name "LArVoxelSD".
698  OpDetSensitiveDetector *theOpDetDet = dynamic_cast<OpDetSensitiveDetector*>(sdManager->FindSensitiveDetector("OpDetSensitiveDetector"));
699 
700  // Store the contents of the detected photon table
701  //
702  if(theOpDetDet){
703 
704  if(!lgp->NoPhotonPropagation()){
705 
706  for (int Reflected = 0; Reflected <= 1; Reflected++) {
707  if (Reflected && ! fStoreReflected)
708  continue;
709 
710  if(!fUseLitePhotons){
711  LOG_DEBUG("Optical") << "Storing OpDet Hit Collection in Event";
712  std::vector<sim::SimPhotons>& ThePhotons = OpDetPhotonTable::Instance()->GetPhotons(Reflected);
713  if (Reflected) PhotonColRefl->reserve(ThePhotons.size());
714  else PhotonCol->reserve(ThePhotons.size());
715  for(auto& it : ThePhotons) {
716  if (Reflected) PhotonColRefl->push_back(std::move(it));
717  else PhotonCol->push_back(std::move(it));
718  }
719  }
720  else{
721  LOG_DEBUG("Optical") << "Storing OpDet Hit Collection in Event";
722 
723  std::map<int, std::map<int, int> > ThePhotons = OpDetPhotonTable::Instance()->GetLitePhotons(Reflected);
724 
725  if(ThePhotons.size() > 0){
726  LitePhotonCol->reserve(ThePhotons.size());
727  for(auto const& it : ThePhotons){
729  ph.OpChannel = it.first;
730  ph.DetectedPhotons = it.second;
731  if (Reflected) LitePhotonColRefl->push_back(ph);
732  else LitePhotonCol->push_back(ph);
733  }
734  }
735  }
736  if (Reflected)
737  *cOpDetBacktrackerRecordColRefl = OpDetPhotonTable::Instance()->YieldReflectedOpDetBacktrackerRecords();
738  else
739  *cOpDetBacktrackerRecordCol = OpDetPhotonTable::Instance()->YieldOpDetBacktrackerRecords();
740  }
741  } //end if no photon propagation
742 
743  if(lgp->FillSimEnergyDeposits())
744  {
745  auto const& edepMap = OpDetPhotonTable::Instance()->GetSimEnergyDeposits();
746  for(auto const& edepCol : edepMap){
747  if(boost::contains(edepCol.first,"TPCActive"))
748  edepCol_TPCActive->insert(edepCol_TPCActive->end(),
749  edepCol.second.begin(),edepCol.second.end());
750  else
751  edepCol_Other->insert(edepCol_Other->end(),
752  edepCol.second.begin(),edepCol.second.end());
753  }
754  }
755  }//end if theOpDetDet
756 
757 
758  if(!lgp->NoElectronPropagation())
759  {
760 
761  // only put the sim::SimChannels into the event once, not once for every
762  // MCTruth in the event
763 
764  std::set<LArVoxelReadout*> ReadoutList; // to be cleared later on
765 
766  for(unsigned int c = 0; c < geom->Ncryostats(); ++c){
767 
768  // map to keep track of which channels we already have SimChannels for in scCol
769  // remake this map on each cryostat as channels ought not to be shared between
770  // cryostats, just between TPC's
771 
772  std::map<unsigned int, unsigned int> channelToscCol;
773 
774  unsigned int ntpcs = geom->Cryostat(c).NTPC();
775  for(unsigned int t = 0; t < ntpcs; ++t){
776  std::string name("LArVoxelSD");
777  std::ostringstream sstr;
778  sstr << name << "_Cryostat" << c << "_TPC" << t;
779 
780  // try first to find the sensitive detector specific for this TPC;
781  // do not bother writing on screen if there is none (yet)
782  G4VSensitiveDetector* sd
783  = sdManager->FindSensitiveDetector(sstr.str(), false);
784  // if there is none, catch the general one (called just "LArVoxelSD")
785  if (!sd) sd = sdManager->FindSensitiveDetector(name, false);
786  // If this didn't work, then a sensitive detector with
787  // the name "LArVoxelSD" does not exist.
788  if ( !sd ){
789  throw cet::exception("LArG4") << "Sensitive detector for cryostat "
790  << c << " TPC " << t << " not found (neither '"
791  << sstr.str() << "' nor '" << name << "' exist)\n";
792  }
793 
794  // Convert the G4VSensitiveDetector* to a LArVoxelReadout*.
795  LArVoxelReadout* larVoxelReadout = dynamic_cast<LArVoxelReadout*>(sd);
796 
797  // If this didn't work, there is a "LArVoxelSD" detector, but
798  // it's not a LArVoxelReadout object.
799  if ( !larVoxelReadout ){
800  throw cet::exception("LArG4") << "Sensitive detector '"
801  << sd->GetName()
802  << "' is not a LArVoxelReadout object\n";
803  }
804 
805  LArVoxelReadout::ChannelMap_t& channels = larVoxelReadout->GetSimChannelMap(c, t);
806  if (!channels.empty()) {
807  LOG_DEBUG("LArG4") << "now put " << channels.size() << " SimChannels"
808  " from C=" << c << " T=" << t << " into the event";
809  }
810 
811  for(auto ch_pair: channels){
812  sim::SimChannel& sc = ch_pair.second;
813 
814  // push sc onto scCol but only if we haven't already put something in scCol for this channel.
815  // if we have, then merge the ionization deposits. Skip the check if we only have one TPC
816 
817  if (ntpcs > 1) {
818  unsigned int ichan = sc.Channel();
819  std::map<unsigned int, unsigned int>::iterator itertest = channelToscCol.find(ichan);
820  if (itertest == channelToscCol.end()) {
821  channelToscCol[ichan] = scCol->size();
822  scCol->emplace_back(std::move(sc));
823  }
824  else {
825  unsigned int idtest = itertest->second;
826  auto const& tdcideMap = sc.TDCIDEMap();
827  for(auto const& tdcide : tdcideMap){
828  for(auto const& ide : tdcide.second){
829  double xyz[3] = {ide.x, ide.y, ide.z};
830  scCol->at(idtest).AddIonizationElectrons(ide.trackID,
831  tdcide.first,
832  ide.numElectrons,
833  xyz,
834  ide.energy);
835  } // end loop to add ionization electrons to scCol->at(idtest)
836  }// end loop over tdc to vector<sim::IDE> map
837  } // end if check to see if we've put SimChannels in for ichan yet or not
838  }
839  else {
840  scCol->emplace_back(std::move(sc));
841  } // end of check if we only have one TPC (skips check for multiple simchannels if we have just one TPC)
842  } // end loop over simchannels for this TPC
843 
844 
845  // mark it for clearing
846  ReadoutList.insert(const_cast<LArVoxelReadout*>(larVoxelReadout));
847 
848  } // end loop over tpcs
849  }// end loop over cryostats
850 
851  for (LArVoxelReadout* larVoxelReadout: ReadoutList){
852  larVoxelReadout->ClearSimChannels();
853  }
854  }//endif electron prop
855 
856  // only put the sim::AuxDetSimChannels into the event once, not once for every
857  // MCTruth in the event
858 
859  adCol->reserve(geom->NAuxDets());
860  for(unsigned int a = 0; a < geom->NAuxDets(); ++a){
861 
862  // there should always be at least one senstive volume because
863  // we make one for the full aux det if none are specified in the
864  // gdml file - see AuxDetGeo.cxx
865  for(size_t sv = 0; sv < geom->AuxDet(a).NSensitiveVolume(); ++sv){
866 
867  // N.B. this name convention is used when creating the
868  // AuxDetReadout SD in AuxDetReadoutGeometry
869  std::stringstream name;
870  name << "AuxDetSD_AuxDet" << a << "_" << sv;
871  G4VSensitiveDetector* sd = sdManager->FindSensitiveDetector(name.str().c_str());
872  if ( !sd ){
873  throw cet::exception("LArG4") << "Sensitive detector '"
874  << name.str()
875  << "' does not exist\n";
876  }
877 
878  // Convert the G4VSensitiveDetector* to a AuxDetReadout*.
879  larg4::AuxDetReadout *auxDetReadout = dynamic_cast<larg4::AuxDetReadout*>(sd);
880 
881  LOG_DEBUG("LArG4") << "now put the AuxDetSimTracks in the event";
882 
883  const sim::AuxDetSimChannel adsc = auxDetReadout->GetAuxDetSimChannel();
884  adCol->push_back(adsc);
885  auxDetReadout->clear();
886  }
887 
888  } // Loop over AuxDets
889 
890  mf::LogInfo("LArG4")
891  << "Geant4 simulated " << nGeneratedParticles << " MC particles, we keep "
892  << partCol->size() << " .";
893 
894  if (fdumpSimChannels) {
895  mf::LogVerbatim("DumpSimChannels")
896  << "Event " << evt.id()
897  << ": " << scCol->size() << " channels with signal";
898  unsigned int nChannels = 0;
899  for (const sim::SimChannel& sc: *scCol) {
900  mf::LogVerbatim out("DumpSimChannels");
901  out << " #" << nChannels << ": ";
902  // dump indenting with " ", but not on the first line
903  sc.Dump(out, " ");
904  ++nChannels;
905  } // for
906  } // if dump SimChannels
907 
908  if(!lgp->NoElectronPropagation()) evt.put(std::move(scCol));
909 
910  evt.put(std::move(adCol));
911  evt.put(std::move(partCol));
912  if(!lgp->NoPhotonPropagation()){
913  if(!fUseLitePhotons){
914  evt.put(std::move(PhotonCol));
915  if (fStoreReflected)
916  evt.put(std::move(PhotonColRefl),"Reflected");
917  }
918  else{
919  evt.put(std::move(LitePhotonCol));
920  evt.put(std::move(cOpDetBacktrackerRecordCol));
921  if (fStoreReflected) {
922  evt.put(std::move(LitePhotonColRefl),"Reflected");
923  evt.put(std::move(cOpDetBacktrackerRecordColRefl),"Reflected");
924  }
925  }
926  }
927  evt.put(std::move(tpassn));
928 
929  if(lgp->FillSimEnergyDeposits()){
930  evt.put(std::move(edepCol_TPCActive),"TPCActive");
931  evt.put(std::move(edepCol_Other),"Other");
932  }
933  return;
934  } // LArG4::produce()
935 
936 } // namespace LArG4
937 
938 namespace larg4 {
939 
941 
942 } // namespace LArG4
943 #if defined __clang__
944  #pragma clang diagnostic pop
945 #endif
946 
947 #endif // LARG4_LARG4_H
std::vector< std::string > fInputLabels
Build Geant4 geometry from GDML.
Store parameters for running LArG4.
Create the physics lists to be used by Geant4.
Collection of all it takes to set up this object.
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< sim::OpDetBacktrackerRecord > YieldReflectedOpDetBacktrackerRecords()
bool KeepEMShowerDaughters() const
void SparsifyTrajectory()
Definition: MCParticle.h:268
std::string fG4MacroPath
void produce(art::Event &evt)
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:143
Stores material properties and sends them to GEANT4 geometry.
intermediate_table::iterator iterator
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
bool G4Run(std::vector< const simb::MCTruth * > &primaries)
Definition: G4Helper.cxx:503
int Mother() const
Definition: MCParticle.h:217
std::string OpDetGeoName(unsigned int c=0) const
Returns gdml string which gives sensitive opdet name.
std::vector< VolumeInfo_t > AllVolumeInfo_t
virtual ~LArG4()
void SetUserAction()
Initialization for the Geant4 Monte Carlo.
Definition: G4Helper.cxx:432
void ConstructDetector(std::string const &gdmlFile)
Definition: G4Helper.cxx:368
const ChannelMap_t & GetSimChannelMap() const
Returns the accumulated channel -> SimChannel map for the single TPC.
void produces(std::string const &instanceName={}, Persistable const persistable=Persistable::Yes)
larg4::LArVoxelListAction * flarVoxelListAction
Geant4 user action to accumulate LAr voxel information.
void SetParallelWorlds(std::vector< G4VUserParallelWorld * > pworlds)
Definition: G4Helper.cxx:357
Geant4 interface.
STL namespace.
Contains data associated to particles from detector simulation.
larg4::LArVoxelReadout::Setup_t readoutSetup
Set up data for LArVoxelReadout.
Runs Geant4 simulation and propagation of electrons and photons to readout.
bool NoPhotonPropagation() const
Use Geant4 to run the LArSoft detector simulation.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
this UserAction derived class is to implement catches to known bugs in Geant4 that require grabbing c...
std::vector< std::string > fKeepParticlesInVolumes
Only write particles that have trajectories through these volumes.
G4RunManager * GetRunManager()
Definition: G4Helper.h:100
Definition: Run.h:30
bool StoreTrajectories() const
int TrackId() const
Definition: MCParticle.h:214
std::map< int, int > DetectedPhotons
Definition: SimPhotons.h:65
void InitPhysics()
Initialization for the Geant4 Monte Carlo.
Definition: G4Helper.cxx:407
Define the "parallel" geometry that&#39;s seen by the LAr Voxels.
bool fSparsifyTrajectories
Sparsify MCParticle Trajectories.
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
int fSmartStacking
Whether to instantiate and use class to.
Collection of particles crossing one auxiliary detector cell.
std::string GDMLFile() const
Returns the full directory path to the GDML file source.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
bool fdumpSimChannels
Whether each event&#39;s sim::Channel will be displayed.
larg4::ParticleListAction * fparticleListAction
Geant4 user action to particle information.
contains objects relating to OpDet hits
sim::ParticleList && YieldList()
std::map< unsigned int, sim::SimChannel > ChannelMap_t
Type of map channel -> sim::SimChannel.
void SetOverlapCheck(bool check)
Definition: G4Helper.h:128
object containing MC truth information necessary for making RawDigits and doing back tracking ...
std::vector< sim::SimPhotons > & GetPhotons(bool Reflected=false)
Use Geant4&#39;s user "hooks" to maintain a list of particles generated by Geant4.
base_engine_t & createEngine(seed_t seed)
std::unordered_map< std::string, std::vector< sim::SimEnergyDeposit > > const & GetSimEnergyDeposits() const
bool NoElectronPropagation() const
Utility functions to print MC truth information.
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
g4b::G4Helper * fG4Help
G4 interface object.
static bool isDropped(simb::MCParticle const *p)
returns whether the specified particle has been marked as dropped
static void AddAndAdoptAction(UserAction *a)
Provenance const * provenance() const
Definition: Handle.h:204
LArG4(fhicl::ParameterSet const &pset)
Standard constructor and destructor for an FMWK module.
virtual void clear()
void DumpMCTruth(Stream &&out, simb::MCTruth const &truth, unsigned int pointsPerLine, std::string indent, std::string firstIndent)
Dumps the content of the specified MC truth in the output stream.
Definition: MCDumpers.h:346
bool FillSimEnergyDeposits() const
static IonizationAndScintillation * CreateInstance(CLHEP::HepRandomEngine &engine)
void getManyByType(std::vector< Handle< PROD >> &results) const
Definition: DataViewImpl.h:446
unsigned int NTPC() const
Number of TPCs in this cryostat.
Definition: CryostatGeo.h:155
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
Convert MCTruth to G4Event; Geant4 event generator.
size_t NSensitiveVolume() const
Definition: AuxDetGeo.h:160
void ParticleFilter(std::unique_ptr< util::PositionInVolumeFilter > &&filter)
Grabs a particle filter.
GeneratedParticleIndex_t GetPrimaryTruthIndex(int trackId) const
Returns the index of primary truth (sim::NoGeneratorIndex if none).
bool fdumpParticleList
Whether each event&#39;s sim::ParticleList will be displayed.
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
AuxDetGeo const & AuxDet(unsigned int const ad=0) const
Returns the specified auxiliary detector.
unsigned int NOpDets() const
Number of OpDets in the whole detector.
void UpdateGeometry(G4LogicalVolumeStore *lvs)
Updates the material properties with the collected values.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
double ParticleKineticEnergyCut() const
raw::ChannelID_t Channel() const
Returns the readout channel this object describes.
Definition: SimChannel.h:332
static OpDetPhotonTable * Instance(bool LitePhotons=false)
A Geant4 sensitive detector that accumulates voxel information.
Define the "parallel" geometry that&#39;s seen by the AuxDet.
static art::ServiceHandle< art::RandomNumberGenerator > & rng()
double offPlaneMargin
Margin for charge recovery (see LArVoxelReadout).
void beginRun(art::Run &run)
std::unique_ptr< util::PositionInVolumeFilter > CreateParticleVolumeFilter(std::set< std::string > const &vol_names) const
Configures and returns a particle filter.
T const * get() const
Definition: Ptr.h:321
static UserActionManager * Instance()
bool fUseLitePhotons
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
std::vector< sim::OpDetBacktrackerRecord > YieldOpDetBacktrackerRecords()
Contains information about a generated particle.
contains information for a single step in the detector simulation
object containing MC truth information necessary for making RawDigits and doing back tracking ...
std::string fG4PhysListName
predefined physics list to use if not making a custom one
#define LOG_DEBUG(id)
bool fCheckOverlaps
Whether to use the G4 overlap checker.
Transports energy depositions from GEANT4 to TPC channels.
TDCIDEs_t const & TDCIDEMap() const
Returns all the deposited energy information as stored.
Definition: SimChannel.h:331
this UserAction derived class is to provide a hook during G4 stepping in which to call the code that ...
bool fStoreReflected
Defines classes to filter particles based on their trajectory.
TCEvent evt
Definition: DataStructs.cxx:5
std::map< int, std::map< int, int > > GetLitePhotons(bool Reflected=false)
void GetPropertiesFromServices()
Imports properties from LArSoft services.
Particle list in DetSim contains Monte Carlo particle information.
Float_t e
Definition: plot.C:34
double fOffPlaneMargin
dictate how tracks are put on stack.
void ClearTable(size_t nch=0)
Tools and modules for checking out the basics of the Monte Carlo.
A Geant4 sensitive detector that accumulates information.
EventID id() const
Definition: Event.h:56
sim::AuxDetSimChannel const GetAuxDetSimChannel() const
Definition: AuxDetReadout.h:73
art framework interface to geometry description
void DumpMCParticle(Stream &&out, simb::MCParticle const &particle, std::string indent, std::string firstIndent)
Dumps the content of the specified particle in the output stream.
Definition: MCDumpers.h:228
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
bool UseLitePhotons() const
unsigned int NAuxDets() const
Returns the number of auxiliary detectors.