LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
larg4Main_module.cc
Go to the documentation of this file.
1 // larg4Main is the main producer module for Geant.
2 
3 // larg4Main_module.cc replicates many GEANT programs' @main()@ driver. It
4 // creates and initializes the run manager, controls the beginning and end of
5 // events.
6 
9 
10 // Art includes
15 
16 // Local includes (like actions)
19 
20 // The actions
26 #include "larg4/pluginActions/MCTruthEventAction_service.h" // combined actions.
27 #include "larg4/pluginActions/ParticleListAction_service.h" // combined actions.
28 
29 // Services
35 // art extensions
41 // Geant4 includes
42 #include "Geant4/G4UImanager.hh"
43 #include "Geant4/G4UIterminal.hh"
44 // C++ includes
45 #include <atomic>
46 #include <map>
47 #include <memory>
48 #include <set>
49 #include <string>
50 #include <vector>
51 
52 using MCTruthCollection = std::vector<simb::MCTruth>;
53 
54 namespace larg4 {
55 
56  // Define the producer
57  class larg4Main : public art::EDProducer {
58  public:
59  explicit larg4Main(fhicl::ParameterSet const& p);
60  ~larg4Main();
61 
62  private:
63  void produce(art::Event& e) override;
64  void beginJob() override;
65  void beginRun(art::Run& r) override;
66  void endRun(art::Run&) override;
67 
68  std::vector<art::Handle<MCTruthCollection>> inputCollections(art::Event const& e) const;
69 
70  // Our custom run manager
71  static std::unique_ptr<artg4tk::ArtG4RunManager> runManager_;
72 
73  // G4 session and managers
74  G4UIsession* session_{nullptr};
75  G4UImanager* UI_{nullptr};
76 
77  // Pseudorandom engine seed (originally hardcoded to 12345),
78  // obtained from the configuration file.
79  // Note: the maximum seed value is 9e8, which is potentially larger
80  // than a long can hold.
81  long seed_;
82 
83  // Directory path(s), in colon-delimited list, in which we should look for
84  // macros, or the name of an environment variable containing that path.
85  // Contains only the $FW_SEARCH_PATH by default, which contains some basic
86  // macro files, but can be set by config file
87  std::string macroPath_;
88 
89  // And a tool to find files along that path
90  // Initialized based on macroPath_.
91  cet::search_path pathFinder_;
92 
93  // Name of the Geant4 macro file, if provided
94  std::string g4MacroFile_;
95 
96  // Input tags used to specify which MCTruth collections to use during G4
97  std::vector<art::InputTag> inputCollectionTags_;
98 
99  // Boolean to determine whether we pause execution after each event
100  // If it's true, then we do. Otherwise, we pause only after all events
101  // have been produced.
102  // False by default, can be changed by afterEvent in FHICL
103  bool pauseAfterEvent_{false};
104 
105  // Run diagnostic level (verbosity)
107 
108  // When to pop up user interface
110  bool uiAtEndEvent_{false}; // set by afterEvent in FHiCL
111 
112  // What to do at the end of the event
113  // Choices are
114  // pass -- do nothing
115  // pause -- Let user press return at the end of each event
116  // ui -- show the UI at the end of the event
117  std::string afterEvent_;
118 
119  static bool initializeDetectors_;
120  static std::atomic<int> processingRun_;
121 
125  };
126 }
127 
128 std::unique_ptr<artg4tk::ArtG4RunManager> larg4::larg4Main::runManager_{nullptr};
130 std::atomic<int> larg4::larg4Main::processingRun_{0};
131 
132 // Constructor - set parameters
134  : EDProducer{p}
135  , seed_(p.get<long>("seed", -1))
136  , macroPath_(p.get<std::string>("macroPath", "FW_SEARCH_PATH"))
138  , g4MacroFile_(p.get<std::string>("visMacro", "larg4.mac"))
139  , inputCollectionTags_{p.get<std::vector<art::InputTag>>("inputCollections", {})}
140  , rmvlevel_(p.get<int>("rmvlevel", 0))
141  , uiAtBeginRun_(p.get<bool>("uiAtBeginRun", false))
142  , afterEvent_(p.get<std::string>("afterEvent", "pass"))
144  p.get<std::string>("DroppedParticleInstanceName", "droppedMCParticles"))
145 {
146 
147  fStoreDroppedMCParticles = pla->storeDropped(); //Store dropped particles if requested
148  produces<sim::ParticleAncestryMap>();
149  produces<std::vector<simb::MCParticle>>();
151  produces<std::vector<simb::MCParticle>>(fDroppedParticleInstanceName);
152  } //Assign product instance name
153  produces<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
154 
155  // We need all of the services to run @produces@ on the data they will store. We do this
156  // by retrieving the holder services.
159 
160  if (initializeDetectors_) {
161  detectorHolder->initialize();
162  // Build the detectors' logical volumes
163  detectorHolder->constructAllLVs();
164  initializeDetectors_ = false;
165  }
166 
167  // And running @callArtProduces@ on each
168  actionHolder->callArtProduces(producesCollector());
169  detectorHolder->callArtProduces(producesCollector());
170 
171  // -- Check for invalid seed value
172  if (seed_ > 900000000) {
173  throw cet::exception("largeant:BadSeedValue")
174  << "The provided largeant seed value: " << seed_ << " is invalid! Maximum seed value is 9E8.";
175  }
176  // Set up the random number engine.
177  // -- D.R.: Use the NuRandomService engine for additional control over the seed generation policy
178  (void)art::ServiceHandle<rndm::NuRandomService>()->registerAndSeedEngine(
179  createEngine(0, "G4Engine"), "G4Engine", p, "seed");
180 
181  // Handle the afterEvent setting
182  if (afterEvent_ == "ui") { uiAtEndEvent_ = true; }
183  else if (afterEvent_ == "pause") {
184  pauseAfterEvent_ = true;
185  }
186 }
187 
189 {
190  if (runManager_) { runManager_.reset(); }
191 }
192 
194 {
195  mf::LogDebug("Main_Run_Manager") << "In begin job";
196  if (runManager_) { return; }
198 }
199 
201 {
202  if (processingRun_++ != 0) { return; }
203 
204  // Get the physics list and pass it to Geant and initialize the list if necessary
206  runManager_->SetUserInitialization(physicsListHolder->makePhysicsList());
207 
208  // Get all of the detectors and initialize them
209  // Declare the detector construction to Geant
210  auto detectorHolder = art::ServiceHandle<artg4tk::DetectorHolderService>().get();
211  runManager_->SetUserInitialization(
212  new artg4tk::ArtG4DetectorConstruction{detectorHolder->worldPhysicalVolume()});
213 
214  // Get all of the actions and initialize them
215  auto actionHolder = art::ServiceHandle<artg4tk::ActionHolderService>().get();
216  actionHolder->initialize();
217 
218  // Store the run in the action holder
219  actionHolder->setCurrArtRun(r);
220 
221  // Declare the primary generator action to Geant
222  runManager_->SetUserAction(new artg4tk::ArtG4PrimaryGeneratorAction{actionHolder});
223 
224  // Note that these actions (and ArtG4PrimaryGeneratorAction above) are all
225  // generic actions that really don't do much on their own. Rather, to
226  // use the power of actions, one must create action objects (derived from
227  // @ActionBase@) and register them with the Art @ActionHolder@ service.
228  // See @ActionBase@ and/or @ActionHolderService@ for more information.
229  runManager_->SetUserAction(new artg4tk::ArtG4SteppingAction{actionHolder});
230  runManager_->SetUserAction(new artg4tk::ArtG4StackingAction{actionHolder});
231  runManager_->SetUserAction(new artg4tk::ArtG4EventAction{actionHolder, detectorHolder});
232  runManager_->SetUserAction(new artg4tk::ArtG4TrackingAction{actionHolder});
233 
234  runManager_->Initialize();
235  physicsListHolder->initializePhysicsList();
236 
237  //get the pointer to the User Interface manager
238  UI_ = G4UImanager::GetUIpointer();
239 
240  // Find the macro (or try to) along the directory path.
241  std::string macroLocation = "";
242  bool macroWasFound = pathFinder_.find_file(g4MacroFile_, macroLocation);
243  mf::LogInfo("larg4Main") << "Finding path for " << g4MacroFile_ << "...\nSearch "
244  << (macroWasFound ? "successful " : "unsuccessful ") << "and path is: \n"
245  << macroLocation;
246 
247  // Execute the macro if we were able to find it
248  if (macroWasFound) {
249  // Create the string containing the execution command
250  mf::LogInfo("larg4Main") << "Executing macro: " << g4MacroFile_;
251  std::string commandToExecute = "/control/execute ";
252  commandToExecute.append(macroLocation);
253  UI_->ApplyCommand(commandToExecute);
254  }
255  else {
256  mf::LogInfo("larg4Main") << "Unable to find " << g4MacroFile_ << " in the path(s) "
257  << macroPath_;
258  }
259 
260  // Open a UI if asked
261  if (uiAtBeginRun_) {
262  session_ = new G4UIterminal;
263  session_->SessionStart();
264  delete session_;
265  }
266 
267  // Start the Geant run!
268  runManager_->BeamOnBeginRun(r.id().run());
269 }
270 
271 // Produce the Geant event
273 {
274  // The holder services need the event
277 
278  auto const mclists = inputCollections(e);
279  art::ServiceHandle<larg4::MCTruthEventActionService>()->setInputCollections(mclists);
280 
281  pla->ParticleFilter(); //Create particle filter
282  if (fStoreDroppedMCParticles) pla->DroppedParticleFilter(); //Create dropped particle filter
283  pla->setInputCollections(mclists);
284  auto const pid = e.getProductID<std::vector<simb::MCParticle>>();
285  pla->setPtrInfo(pid, e.productGetter(pid));
286 
287  runManager_->BeamOnDoOneEvent(e.id().event());
288  runManager_->BeamOnEndEvent();
289 
290  e.put(pla->ParticleCollection());
291  e.put(pla->AssnsMCTruthToMCParticle());
292  e.put(pla->DroppedTracksCollection());
293  if (fStoreDroppedMCParticles) { //Produce and place only if requested
294  e.put(pla->DroppedParticleCollection(), fDroppedParticleInstanceName);
295  }
296 }
297 
299 {
300  if (--processingRun_ != 0) { return; }
301 
302  runManager_->BeamOnEndRun();
303 }
304 
305 std::vector<art::Handle<MCTruthCollection>> larg4::larg4Main::inputCollections(
306  art::Event const& e) const
307 {
308  if (empty(inputCollectionTags_)) { return e.getMany<std::vector<simb::MCTruth>>(); }
309 
310  std::vector<art::Handle<MCTruthCollection>> result;
311  for (auto const& tag : inputCollectionTags_) {
312  result.push_back(e.getHandle<MCTruthCollection>(tag));
313  }
314  return result;
315 }
316 
TRandom r
Definition: spectrum.C:23
base_engine_t & createEngine(seed_t seed)
static bool initializeDetectors_
G4UImanager * UI_
static std::atomic< int > processingRun_
bool fStoreDroppedMCParticles
Store dropped particles.
void endRun(art::Run &) override
RunID id() const
Definition: Run.cc:21
ProductID getProductID(std::string const &instance_name="") const
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
static std::unique_ptr< artg4tk::ArtG4RunManager > runManager_
void produce(art::Event &e) override
std::vector< art::Handle< MCTruthCollection > > inputCollections(art::Event const &e) const
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
G4UIsession * session_
cet::search_path pathFinder_
Geant4 interface.
Contains data associated to particles from detector simulation.
std::string fDroppedParticleInstanceName
Name of the dropped particle collection.
Particle class.
RunNumber_t run() const
Definition: RunID.h:64
Definition: Run.h:37
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
std::string afterEvent_
EDProductGetter const * productGetter(ProductID const pid) const
Utility functions to print MC truth information.
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
void beginJob() override
Use Geant4&#39;s user "hooks" to maintain a list of particles generated by Geant4.
std::vector< simb::MCTruth > MCTruthCollection
std::string g4MacroFile_
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
std::vector< art::InputTag > inputCollectionTags_
ProducesCollector & producesCollector() noexcept
G4VUserPhysicsList * makePhysicsList() const
Handle< PROD > getHandle(SelectorBase const &) const
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
art::ServiceHandle< larg4::ParticleListActionService > pla
void callArtProduces(art::ProducesCollector &)
EventNumber_t event() const
Definition: EventID.h:116
void beginRun(art::Run &r) override
larg4Main(fhicl::ParameterSet const &p)
std::string macroPath_
Particle list in DetSim contains Monte Carlo particle information.
Float_t e
Definition: plot.C:35
EventID id() const
Definition: Event.cc:23
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
std::vector< Handle< PROD > > getMany(SelectorBase const &selector=MatchAllSelector{}) const