All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
7 #include "nusimdata/SimulationBase/MCParticle.h"
8 #include "nusimdata/SimulationBase/MCTruth.h"
9 
10 // Art includes
11 #include "art/Framework/Core/EDProducer.h"
12 #include "art/Framework/Core/ModuleMacros.h"
13 #include "art/Framework/Principal/Event.h"
14 #include "art/Framework/Principal/Run.h"
15 
16 // Local includes (like actions)
17 #include "artg4tk/geantInit/ArtG4DetectorConstruction.hh"
18 #include "artg4tk/geantInit/ArtG4RunManager.hh"
19 
20 // The actions
21 #include "artg4tk/geantInit/ArtG4EventAction.hh"
22 #include "artg4tk/geantInit/ArtG4PrimaryGeneratorAction.hh"
23 #include "artg4tk/geantInit/ArtG4StackingAction.hh"
24 #include "artg4tk/geantInit/ArtG4SteppingAction.hh"
25 #include "artg4tk/geantInit/ArtG4TrackingAction.hh"
26 #include "larg4/pluginActions/MCTruthEventAction_service.h" // combined actions.
27 #include "larg4/pluginActions/ParticleListAction_service.h" // combined actions.
28 
29 // Services
30 #include "art/Framework/Services/Optional/RandomNumberGenerator.h"
31 #include "art/Framework/Services/Registry/ServiceHandle.h"
32 #include "artg4tk/services/ActionHolder_service.hh"
33 #include "artg4tk/services/DetectorHolder_service.hh"
34 #include "artg4tk/services/PhysicsListHolder_service.hh"
35 // art extensions
38 #include "nug4/ParticleNavigation/ParticleList.h"
39 #include "nurandom/RandomUtils/NuRandomService.h"
40 // Geant4 includes
41 #include "Geant4/G4UImanager.hh"
42 #include "Geant4/G4UIterminal.hh"
43 // C++ includes
44 #include <atomic>
45 #include <string>
46 #include <set>
47 #include <map>
48 #include <memory>
49 #include <vector>
50 
51 using MCTruthCollection = std::vector<simb::MCTruth>;
52 
53 namespace larg4 {
54 
55  // Define the producer
56  class larg4Main : public art::EDProducer {
57  public:
58  explicit larg4Main(fhicl::ParameterSet const& p);
59  ~larg4Main();
60 
61  private:
62  void produce(art::Event& e) override;
63  void beginJob() override;
64  void beginRun(art::Run& r) override;
65  void endRun(art::Run&) override;
66 
67  std::vector<art::Handle<MCTruthCollection>> inputCollections(art::Event const& e) const;
68 
69  // Our custom run manager
70  static std::unique_ptr<artg4tk::ArtG4RunManager> runManager_;
71 
72  // G4 session and managers
73  G4UIsession* session_{nullptr};
74  G4UImanager* UI_{nullptr};
75 
76  // Pseudorandom engine seed (originally hardcoded to 12345),
77  // obtained from the configuration file.
78  // Note: the maximum seed value is 9e8, which is potentially larger
79  // than a long can hold.
80  long seed_;
81 
82  // Directory path(s), in colon-delimited list, in which we should look for
83  // macros, or the name of an environment variable containing that path.
84  // Contains only the $FW_SEARCH_PATH by default, which contains some basic
85  // macro files, but can be set by config file
86  std::string macroPath_;
87 
88  // And a tool to find files along that path
89  // Initialized based on macroPath_.
90  cet::search_path pathFinder_;
91 
92  // Name of the Geant4 macro file, if provided
93  std::string g4MacroFile_;
94 
95  // Input tags used to specify which MCTruth collections to use during G4
96  std::vector<art::InputTag> inputCollectionTags_;
97 
98  // Boolean to determine whether we pause execution after each event
99  // If it's true, then we do. Otherwise, we pause only after all events
100  // have been produced.
101  // False by default, can be changed by afterEvent in FHICL
102  bool pauseAfterEvent_{false};
103 
104  // Run diagnostic level (verbosity)
106 
107  // When to pop up user interface
109  bool uiAtEndEvent_{false}; // set by afterEvent in FHiCL
110 
111  // What to do at the end of the event
112  // Choices are
113  // pass -- do nothing
114  // pause -- Let user press return at the end of each event
115  // ui -- show the UI at the end of the event
116  std::string afterEvent_;
117 
118  static bool initializeDetectors_;
119  static std::atomic<int> processingRun_;
120  };
121 }
122 
123 std::unique_ptr<artg4tk::ArtG4RunManager> larg4::larg4Main::runManager_{nullptr};
125 std::atomic<int> larg4::larg4Main::processingRun_{0};
126 
127 // Constructor - set parameters
128 larg4::larg4Main::larg4Main(fhicl::ParameterSet const& p)
129  : EDProducer{p}
130  , seed_(p.get<long>("seed", -1))
131  , macroPath_(p.get<std::string>("macroPath", "FW_SEARCH_PATH"))
132  , pathFinder_(macroPath_)
133  , g4MacroFile_(p.get<std::string>("visMacro", "larg4.mac"))
134  , inputCollectionTags_{p.get<std::vector<art::InputTag>>("inputCollections", {})}
135  , rmvlevel_(p.get<int>("rmvlevel", 0))
136  , uiAtBeginRun_(p.get<bool>("uiAtBeginRun", false))
137  , afterEvent_(p.get<std::string>("afterEvent", "pass"))
138 {
139  produces<std::map<int,std::set<int>>>();
140  produces<std::vector<simb::MCParticle>>();
141  produces<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
142 
143  // We need all of the services to run @produces@ on the data they will store. We do this
144  // by retrieving the holder services.
145  art::ServiceHandle<artg4tk::ActionHolderService> actionHolder;
146  art::ServiceHandle<artg4tk::DetectorHolderService> detectorHolder;
147 
148  if (initializeDetectors_) {
149  detectorHolder->initialize();
150  // Build the detectors' logical volumes
151  detectorHolder->constructAllLVs();
152  initializeDetectors_ = false;
153  }
154 
155  // And running @callArtProduces@ on each
156  actionHolder->callArtProduces(producesCollector());
157  detectorHolder->callArtProduces(producesCollector());
158 
159  // -- Check for invalid seed value
160  if (seed_ > 900000000) {
161  throw cet::exception("largeant:BadSeedValue")
162  << "The provided largeant seed value: " << seed_ << " is invalid! Maximum seed value is 9E8.";
163  }
164  // Set up the random number engine.
165  // -- D.R.: Use the NuRandomService engine for additional control over the seed generation policy
166  (void)art::ServiceHandle<rndm::NuRandomService>()->createEngine(*this, "G4Engine", p, "seed");
167 
168  // Handle the afterEvent setting
169  if (afterEvent_ == "ui") { uiAtEndEvent_ = true; }
170  else if (afterEvent_ == "pause") {
171  pauseAfterEvent_ = true;
172  }
173 }
174 
176 {
177  if (runManager_) {
178  runManager_.reset();
179  }
180 }
181 
182 void
184 {
185  mf::LogDebug("Main_Run_Manager") << "In begin job";
186  if (runManager_) {
187  return;
188  }
189  runManager_.reset(new artg4tk::ArtG4RunManager);
190 }
191 
192 void
194 {
195  if (processingRun_++ != 0) {
196  return;
197  }
198 
199  // Get the physics list and pass it to Geant and initialize the list if necessary
200  art::ServiceHandle<artg4tk::PhysicsListHolderService const> physicsListHolder;
201  runManager_->SetUserInitialization(physicsListHolder->makePhysicsList());
202 
203  // Get all of the detectors and initialize them
204  // Declare the detector construction to Geant
205  auto detectorHolder = art::ServiceHandle<artg4tk::DetectorHolderService>().get();
206  runManager_->SetUserInitialization(
207  new artg4tk::ArtG4DetectorConstruction{detectorHolder->worldPhysicalVolume()});
208 
209  // Get all of the actions and initialize them
210  auto actionHolder = art::ServiceHandle<artg4tk::ActionHolderService>().get();
211  actionHolder->initialize();
212 
213  // Store the run in the action holder
214  actionHolder->setCurrArtRun(r);
215 
216  // Declare the primary generator action to Geant
217  runManager_->SetUserAction(new artg4tk::ArtG4PrimaryGeneratorAction{actionHolder});
218 
219  // Note that these actions (and ArtG4PrimaryGeneratorAction above) are all
220  // generic actions that really don't do much on their own. Rather, to
221  // use the power of actions, one must create action objects (derived from
222  // @ActionBase@) and register them with the Art @ActionHolder@ service.
223  // See @ActionBase@ and/or @ActionHolderService@ for more information.
224  runManager_->SetUserAction(new artg4tk::ArtG4SteppingAction{actionHolder});
225  runManager_->SetUserAction(new artg4tk::ArtG4StackingAction{actionHolder});
226  runManager_->SetUserAction(new artg4tk::ArtG4EventAction{actionHolder, detectorHolder});
227  runManager_->SetUserAction(new artg4tk::ArtG4TrackingAction{actionHolder});
228 
229  runManager_->Initialize();
230  physicsListHolder->initializePhysicsList();
231 
232  //get the pointer to the User Interface manager
233  UI_ = G4UImanager::GetUIpointer();
234 
235  // Find the macro (or try to) along the directory path.
236  std::string macroLocation = "";
237  bool macroWasFound = pathFinder_.find_file(g4MacroFile_, macroLocation);
238  mf::LogInfo("larg4Main") << "Finding path for " << g4MacroFile_ << "...\nSearch "
239  << (macroWasFound ? "successful " : "unsuccessful ") << "and path is: \n"
240  << macroLocation;
241 
242  // Execute the macro if we were able to find it
243  if (macroWasFound) {
244  // Create the string containing the execution command
245  mf::LogInfo("larg4Main") << "Executing macro: " << g4MacroFile_;
246  std::string commandToExecute = "/control/execute ";
247  commandToExecute.append(macroLocation);
248  UI_->ApplyCommand(commandToExecute);
249  }
250  else {
251  mf::LogInfo("larg4Main") << "Unable to find " << g4MacroFile_ << " in the path(s) "
252  << macroPath_;
253  }
254 
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 void
269 {
270  // The holder services need the event
271  art::ServiceHandle<artg4tk::ActionHolderService>()->setCurrArtEvent(e);
272  art::ServiceHandle<artg4tk::DetectorHolderService>()->setCurrArtEvent(e);
273 
274  auto const mclists = inputCollections(e);
275  art::ServiceHandle<larg4::MCTruthEventActionService>()->setInputCollections(mclists);
276 
277  art::ServiceHandle<larg4::ParticleListActionService> pla;
278  pla->setInputCollections(mclists);
279  auto const pid = e.getProductID<std::vector<simb::MCParticle>>();
280  pla->setPtrInfo(pid, e.productGetter(pid));
281 
282  runManager_->BeamOnDoOneEvent(e.id().event());
283  runManager_->BeamOnEndEvent();
284 
285  e.put(pla->ParticleCollection());
286  e.put(pla->AssnsMCTruthToMCParticle());
287  e.put(pla->DroppedTracksCollection());
288 }
289 
290 void
292 {
293  if (--processingRun_ != 0) {
294  return;
295  }
296 
297  runManager_->BeamOnEndRun();
298 }
299 
300 std::vector<art::Handle<MCTruthCollection>>
301 larg4::larg4Main::inputCollections(art::Event const& e) const
302 {
303  if (empty(inputCollectionTags_)) {
304  return e.getMany<std::vector<simb::MCTruth>>();
305  }
306 
307  std::vector<art::Handle<MCTruthCollection>> result;
308  for (auto const& tag : inputCollectionTags_) {
309  result.push_back(e.getHandle<MCTruthCollection>(tag));
310  }
311  return result;
312 }
313 
314 DEFINE_ART_MODULE(larg4::larg4Main)
static bool initializeDetectors_
G4UImanager * UI_
static std::atomic< int > processingRun_
void endRun(art::Run &) override
rmvlevel_(p.get< int >("rmvlevel", 0))
static std::unique_ptr< artg4tk::ArtG4RunManager > runManager_
void produce(art::Event &e) override
std::vector< art::Handle< MCTruthCollection > > inputCollections(art::Event const &e) const
pdgs p
Definition: selectors.fcl:22
G4UIsession * session_
cet::search_path pathFinder_
Contains data associated to particles from detector simulation.
std::string afterEvent_
Utility functions to print MC truth information.
void beginJob() override
Use Geant4&#39;s user &quot;hooks&quot; to maintain a list of particles generated by Geant4.
std::vector< simb::MCTruth > MCTruthCollection
std::string g4MacroFile_
j template void())
Definition: json.hpp:3108
std::vector< art::InputTag > inputCollectionTags_
do i e
afterEvent_(p.get< std::string >("afterEvent","pass"))
void beginRun(art::Run &r) override
larg4Main(fhicl::ParameterSet const &p)
uiAtBeginRun_(p.get< bool >("uiAtBeginRun", false))
std::string macroPath_
bool empty(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:555
esac echo uname r