LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
artg4Main_module.cc
Go to the documentation of this file.
1 // artg4tkMain is the main producer module for Geant.
2 
3 // artg4tkMain_module.cc replicates many GEANT programs' @main()@ driver. It
4 // creates and initializes the run manager, controls the beginning and end of
5 // events, and controls visualization.
6 
7 // Authors: Tasha Arvanitis, Adam Lyon
8 
9 // Date: July 2012
10 
11 // Art includes
18 
19 // Local includes (like actions)
22 
23 // The actions
29 
30 // Services
34 
35 // Geant4 includes
36 #include "Geant4/G4UImanager.hh"
37 #include "Geant4/G4UIterminal.hh"
38 
39 using namespace std;
40 
41 namespace artg4tk {
42 
43  // Define the producer
44 
45  class artg4tkMain : public art::EDProducer {
46  public:
47  // Constructor
48  explicit artg4tkMain(fhicl::ParameterSet const& p);
49 
50  // Destructor
51  virtual ~artg4tkMain();
52 
53  // Overriding producer members
54  void produce(art::Event& e) override;
55  void beginJob() override;
56  void beginRun(art::Run& r) override;
57  void endRun(art::Run&) override;
58 
59  private:
60  // Our custom run manager
61  unique_ptr<ArtG4RunManager> runManager_;
62 
63  // G4 session and managers
64  G4UIsession* session_;
65  G4UImanager* UI_;
66 
67  // Pseudorandom engine seed (originally hardcoded to 12345),
68  // obtained from the configuration file.
69  // Note: the maximum seed value is 9e8, which is potentially larger
70  // than a long can hold.
71  long seed_;
72 
73  // Determine whether we should use visualization
74  // False by default, can be set by config file
75  // bool enableVisualization_;
76 
77  // Directory path(s), in colon-delimited list, in which we should look for
78  // macros, or the name of an environment variable containing that path.
79  // Contains only the current directory ('.') by default, but can be
80  // set by config file
81  string macroPath_;
82 
83  // And a tool to find files along that path
84  // Initialized based on macroPath_.
85  cet::search_path pathFinder_;
86 
87  // Name of a macro file for visualization
88  // 'vis.mac' by default, and can be customized by config file.
89  string visMacro_;
90 
91  // Boolean to determine whether we pause execution after each event
92  // If it's true, then we do. Otherwise, we pause only after all events
93  // have been produced.
94  // False by default, can be changed by afterEvent in FHICL
96 
97  // Boolean to determine whether we're in "visualize only certain
98  // events" mode. If so, we pause and show the visualization only after
99  // the given events. Turning this on only works if visualization is
100  // also enabled, and it will pause, pass, or bring up a UI at the end
101  // of the given events, as specified by afterEvent.
103 
104  // If we're in "visualize only certain events" mode, this vector
105  // contains the events for which the visualization should be displayed.
106  // This is a map because determining whether an event is in there is
107  // O(log(n)), rather than O(n) for a vector, and find(...) is a heck of
108  // a lot more convenient than looping over the vector.
109  std::map<int, bool> eventsToDisplay_;
110 
111  // Run diagnostic level (verbosity)
113 
114  // When to pop up user interface
116  bool uiAtEndEvent_; // set by afterEvent in FHICL
117 
118  // What to do at the end of the event
119  // Choices are
120  // pass -- do nothing
121  // pause -- Let user press return at the end of each event
122  // ui -- show the UI at the end of the event
123  std::string afterEvent_;
124 
125  // Message logger
127  };
128 }
129 
130 // Constructor - set parameters
131 
133  : art::EDProducer(p)
134  , runManager_()
135  , session_(0)
136  , UI_(0)
137  , seed_(p.get<long>("seed", -1))
138  , macroPath_(p.get<std::string>("macroPath", "."))
139  , pathFinder_(macroPath_)
140  , visMacro_(p.get<std::string>("visMacro", "vis.mac"))
141  , pauseAfterEvent_(false)
142  , visSpecificEvents_(p.get<bool>("visualizeSpecificEvents", false))
143  , eventsToDisplay_()
144  , rmvlevel_(p.get<int>("rmvlevel", 0))
145  , uiAtBeginRun_(p.get<bool>("uiAtBeginRun", false))
146  , uiAtEndEvent_(false)
147  , afterEvent_(p.get<std::string>("afterEvent", "pass"))
148  , logInfo_("ArtG4Main")
149 {
150  // If we're in "visualize specific events" mode (essentially only pause
151  // after given events), then extract the list of events we need to
152  // pause for. They are placed in a map because it is more efficient to
153  // determine whether a given entry is present in the map than a vector.
154  if (visSpecificEvents_) {
155  std::vector<int> eventsToDisplayVec = p.get<vector<int>>("eventsToDisplay");
156  for (size_t i = 0; i < eventsToDisplayVec.size(); i++) {
157  eventsToDisplay_[eventsToDisplayVec[i]] = true;
158  }
159  // Would be nice to have error checking here, but for now, if you
160  // do something silly, it'll probably just crash.
161  }
162 
163  // We need all of the services to run @produces@ on the data they will store. We do this
164  // by retrieving the holder services.
167  detectorHolder->initialize();
168  // hjw:
169  // detectorHolder -> callArtProduces(this);
170  // Build the detectors' logical volumes
171  detectorHolder->constructAllLVs();
172  // And running @callArtProduces@ on each
173  actionHolder->callArtProduces(producesCollector());
174  detectorHolder->callArtProduces(producesCollector());
175 
176  // Set up the random number engine.
177  // See the documentation in RandomNumberHeader.h for
178  // how this works. Note that @createEngine@ is a member function
179  // of our base class (actually, a couple of base classes deep!).
180  // Note that the name @G4Engine@ is special.
181  if (seed_ == -1) {
182  // Construct seed from time and pid. (default behavior if
183  // no seed is provided by the fcl file)
184  // Note: According to Kevin Lynch, the two lines below are not portable.
185  seed_ = time(0) + getpid();
186  seed_ =
187  ((seed_ & 0xFFFF0000) >> 16) | ((seed_ & 0x0000FFFF) << 16); // exchange upper and lower word
188  seed_ = seed_ % 900000000; // ensure the seed is in the correct range for createEngine
189  }
190  createEngine(seed_, "G4Engine");
191 
192  // Handle the afterEvent setting
193  if (afterEvent_ == "ui") {
194  uiAtEndEvent_ = true;
195  } else if (afterEvent_ == "pause") {
196  pauseAfterEvent_ = true;
197  }
198 }
199 
200 // Destructor
201 
203 
204 // At begin job
205 
206 void
208 {
209  // Set up run manager
210  mf::LogDebug("Main_Run_Manager") << "In begin job";
211  runManager_.reset(new ArtG4RunManager);
212 }
213 
214 // At begin run
215 
216 void
218 {
219  // Get the physics list and pass it to Geant4and initialize the list if necessary
221  runManager_->SetUserInitialization(physicsListHolder->makePhysicsList());
222 
223  // Get all of the detectors and initialize them
225 
226  // Declare the detector construction to Geant
227  runManager_->SetUserInitialization(
228  new ArtG4DetectorConstruction{detectorHolder->worldPhysicalVolume()});
229 
230  // Get all of the actions and initialize them
232  actionHolder->initialize();
233 
234  // Store the run in the action holder
235  actionHolder->setCurrArtRun(r);
236 
237  // Declare the primary generator action to Geant
238  runManager_->SetUserAction(new ArtG4PrimaryGeneratorAction{actionHolder.get()});
239 
240  // Note that these actions (and ArtG4PrimaryGeneratorAction above) are all
241  // generic actions that really don't do much on their own. Rather, to
242  // use the power of actions, one must create action objects (derived from
243  // @ActionBase@) and register them with the Art @ActionHolder@ service.
244  // See @ActionBase@ and/or @ActionHolderService@ for more information.
245  runManager_->SetUserAction(new ArtG4SteppingAction{actionHolder.get()});
246  runManager_->SetUserAction(new ArtG4StackingAction{actionHolder.get()});
247  runManager_->SetUserAction(new ArtG4EventAction{actionHolder.get(), detectorHolder.get()});
248  runManager_->SetUserAction(new ArtG4TrackingAction{actionHolder.get()});
249 
250  runManager_->Initialize();
251  physicsListHolder->initializePhysicsList();
252 
253  // get the pointer to the User Interface manager
254  UI_ = G4UImanager::GetUIpointer();
255  // Open a UI if asked
256  if (uiAtBeginRun_) {
257  session_ = new G4UIterminal;
258  session_->SessionStart();
259  delete session_;
260  }
261 
262  // Start the Geant run!
263  runManager_->BeamOnBeginRun(r.id().run());
264 }
265 
266 // Produce the Geant event
267 
268 void
270 {
271  // The holder services need the event
274 
275  actionHolder->setCurrArtEvent(e);
276  detectorHolder->setCurrArtEvent(e);
277 
278  // Begin event
279  runManager_->BeamOnDoOneEvent(e.id().event());
280 
281  logInfo_ << "Producing event " << e.id().event() << "\n" << endl;
282 
283  // Done with the event
284  runManager_->BeamOnEndEvent();
285 }
286 
287 // At end run
288 
289 void
291 {
293  actionHolder->setCurrArtRun(r);
294 
295  runManager_->BeamOnEndRun();
296 }
297 
TRandom r
Definition: spectrum.C:23
base_engine_t & createEngine(seed_t seed)
void endRun(art::Run &) override
RunID id() const
Definition: Run.cc:21
artg4tkMain(fhicl::ParameterSet const &p)
T * get() const
Definition: ServiceHandle.h:69
unique_ptr< ArtG4RunManager > runManager_
STL namespace.
RunNumber_t run() const
Definition: RunID.h:64
void beginRun(art::Run &r) override
Definition: Run.h:37
void beginJob() override
std::map< int, bool > eventsToDisplay_
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
void beginJob()
Definition: Breakpoints.cc:14
T get(std::string const &key) const
Definition: ParameterSet.h:314
ProducesCollector & producesCollector() noexcept
decltype(auto) get(T &&obj)
ADL-aware version of std::to_string.
Definition: StdUtils.h:120
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
Definition: MVAAlg.h:12
EventNumber_t event() const
Definition: EventID.h:116
cet::search_path pathFinder_
Float_t e
Definition: plot.C:35
void produce(art::Event &e) override
EventID id() const
Definition: Event.cc:23