G4Helper.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file G4Helper.h
3 /// \brief Use Geant4 to run the LArSoft detector simulation
4 ///
5 /// \version $Id: G4Helper.cxx,v 1.20 2012-12-03 23:29:49 rhatcher Exp $
6 /// \author seligman@nevis.columbia.edu, brebel@fnal.gov
7 ////////////////////////////////////////////////////////////////////////
8 
9 #include "nutools/G4Base/G4Helper.h"
10 #include "nutools/G4Base/DetectorConstruction.h"
11 #include "nutools/G4Base/UserActionManager.h"
12 
14 
15 #include "Geant4/G4UImanager.hh"
16 #include "Geant4/G4VUserDetectorConstruction.hh"
17 #include "Geant4/G4VUserPrimaryGeneratorAction.hh"
18 #include "Geant4/G4VUserPhysicsList.hh"
19 #include "Geant4/G4UserLimits.hh"
20 #include "Geant4/G4UserRunAction.hh"
21 #include "Geant4/G4UserEventAction.hh"
22 #include "Geant4/G4UserTrackingAction.hh"
23 #include "Geant4/G4UserSteppingAction.hh"
24 #include "Geant4/G4VisExecutive.hh"
25 #include "Geant4/G4StepLimiterPhysics.hh"
26 #include "Geant4/G4LogicalVolumeStore.hh"
27 
28 #include <boost/algorithm/string.hpp>
29 
30 #include "Geant4/QGSP_BERT.hh"
31 #define TRY_NEW_PL_FACTORY
32 #ifdef TRY_NEW_PL_FACTORY
33 #include "nutools/G4Base/G4PhysListFactory.hh"
34 #else
35 #include "Geant4/G4PhysListFactory.hh"
36 #endif
37 //
38 #include "nutools/G4Base/G4PhysicsProcessFactorySingleton.hh"
39 #include "Geant4/G4VModularPhysicsList.hh"
40 
41 #include <Rtypes.h>
42 
43 #include <iostream>
44 #include <cstring>
45 #include <sys/stat.h>
46 
48 
49 namespace g4b{
50 
51  static G4VisExecutive* vm_ = 0;
52 
53  //------------------------------------------------
54  // Constructor
56  : fCheckOverlaps (false )
57  , fValidateGDMLSchema(false )
58  , fUseStepLimits (false )
59  , fUIManager (nullptr)
60  , fConvertMCTruth (nullptr)
61  , fDetector (nullptr)
62  {
63  fParallelWorlds.clear();
64  }
65 
66  //------------------------------------------------
67  // Constructor
68  G4Helper::G4Helper(std::string const& g4macropath,
69  std::string const& g4physicslist,
70  std::string const& gdmlFile)
71  : fG4MacroPath (g4macropath )
72  , fG4PhysListName (g4physicslist)
73  , fGDMLFile (gdmlFile )
74  , fCheckOverlaps (false )
75  , fValidateGDMLSchema(true )
76  , fUseStepLimits (false )
77  , fUIManager (nullptr )
78  , fConvertMCTruth (nullptr )
79  , fDetector (nullptr )
80  {
81  // Geant4 run manager. Nothing happens in Geant4 until this object
82  // is created.
83  fRunManager = new G4RunManager;
84 
85  // Get the pointer to the User Interface manager
86  fUIManager = G4UImanager::GetUIpointer();
87 
88  fParallelWorlds.clear();
89  }
90 
91  //------------------------------------------------
92  // Destructor
94  {
95  if( vm_ ) delete vm_;
96 
97  if ( fRunManager != 0 ){
98  // In SetUserAction(), we set all the G4 user-action classes to be the
99  // same action: G4Base::UserActionManager This is convenient, but
100  // it creates a problem here: First the G4RunManager deletes the
101  // G4UserRunAction, then it tries to delete the
102  // G4UserEventAction... but that's the same object, which has
103  // already been deleted. Crash.
104 
105  // To keep this from happening, handle the UserActionManager
106  // clean-up manually, then tell the G4RunManager that all those
107  // classes no longer exist.
108 
110  bool wasStacking = uaManager->DoesAnyActionProvideStacking();
111  uaManager->Close();
112 
113  // Each one of these G4RunManager::SetUserAction methods calls a
114  // different method, based on the type of the argument. We want
115  // to use "0" (a null pointer), but we have to cast that "0" to a
116  // particular type in order for the right SetUserAction method to
117  // be called.
118 
119  fRunManager->SetUserAction( static_cast<G4UserRunAction*>(0) );
120  fRunManager->SetUserAction( static_cast<G4UserEventAction*>(0) );
121  fRunManager->SetUserAction( static_cast<G4UserTrackingAction*>(0) );
122  fRunManager->SetUserAction( static_cast<G4UserSteppingAction*>(0) );
123  if ( wasStacking ) {
124  fRunManager->SetUserAction( static_cast<G4UserStackingAction*>(0) );
125  }
126 
127  delete fRunManager;
128  }
129  else{
130  MF_LOG_ERROR("G4Helper")
131  << "G4Helper never initialized; probably because there were no input primary events";
132  }
133 
134  for(size_t i = 0; i < fParallelWorlds.size(); ++i){
135  if(fParallelWorlds[i]) delete fParallelWorlds[i];
136  }
137  fParallelWorlds.clear();
138 
139  }
140 
141  //------------------------------------------------
143  {
144  /// Set up the physics list for Geant4, and pass it to Geant4's
145  /// run manager.
146  /// Without a physics list, Geant4 won't do anything. G4 comes with a
147  /// number of pre-constructed lists, and for now I plan to use
148  /// "QGSP_BERT". It has the following properties:
149  ///
150  /// - Standard EM physics processes.
151  /// - Quark-gluon string model for high energies (> 20GeV)
152  /// - Low Energy Parameterized (LEP) for medium energies (10<E<20GeV)
153  /// - Gertini-style cascade for low energies (< 10GeV)
154  /// - LEP, HEP for all anti-baryons (LEP,HEP = low/high energy parameterized, from GHEISHA)
155  /// - Gamma-nuclear model added for E<3.5 GeV
156  /// (comments from "Guided Tour of Geant4 Physics List II",
157  /// talk given at JPL by Dennis Wright)
158  ///
159  /// if we decide that QGSP_BERT is not what we want, then we will
160  /// have to write a new physics list class that derives from
161  /// G4VUserPhysicsList that does what we want.
162 
163  G4VUserPhysicsList* physics = 0;
164  std::string bywhom = "User";
165  std::string factoryname = "G4PhysListFactory";
166  bool list_known_procs = true;
167 
168  // physics list name is the first part, anything afterwards is
169  // extra physics processes to be added to the base list
170  // ie. "QGSP_BERT ; myspace::MonopolePhysics ; MyOtherSpecialPhysics "
171  std::vector< std::string > pstrings;
172  // don't use ":" as a separator because it's used in namespaces
173  boost::algorithm::split( pstrings, physicsString, boost::is_any_of(";"),
174  boost::token_compress_on );
175  // trim lead/trail space
176  for (unsigned int j=0; j < pstrings.size(); ++j )
177  boost::algorithm::trim(pstrings[j]);
178 
179  if ( pstrings.size() < 1 ) pstrings.push_back(""); // non-empty
180  std::string phListName = pstrings[0];
181 
182  //for (unsigned int j=0; j < pstrings.size(); ++j )
183  // std::cout << "G4Helper pstrings[" << j << "] = \""
184  // << pstrings[j] << "\"" << std::endl;
185 
186  if ( ! physics ) {
187 #ifdef TRY_NEW_PL_FACTORY
188  // user extensible physics list factory
189  alt::G4PhysListFactory factory;
190  factoryname = "alt::G4PhysListFactory";
191 #else
192  // The official Geant4 G4PhysListFactory _isn't_ a modern factory;
193  // it can only generate items that have pre-programmed blueprints
194  // already known to it (via if/else-if calls to various ctors) and
195  // is not user extensible (i.e. you can't send it blueprints and
196  // have it make them for you). If we have our own physics list
197  // then we need to select on and construct it ourselves before
198  // looking to the factory.
199 
200  // Put if/then/else statement here for user defined physics lists
201  // when using old stodgy offical G4 factory.
202  // Example:
203  /*
204  // string name actual class ctor
205  if ( "MY_COOL_PL" == phListName ) {physics = new My_Cool_PL();}
206  else if ( "MY_OTHER_PL" == phListName ) {physics = new My_Other_PL();}
207  */
208 
209  G4PhysListFactory factory; // official G4 factory
210 #endif
211 
212  if ( ! physics ) {
213  if ( factory.IsReferencePhysList(phListName) ) {
214  bywhom = factoryname;
215  physics = factory.GetReferencePhysList(phListName);
216  }
217  else {
218  // in the case of non-default name
219  if ( phListName != "" ) {
220  std::cerr << std::endl << factoryname
221  << " failed to find ReferencePhysList \""
222  << phListName << "\"" << std::endl;
223 #ifdef TRY_NEW_PL_FACTORY
224  factory.PrintAvailablePhysLists();
225 #else
226  std::vector<G4String> list = factory.AvailablePhysLists();
227  MF_LOG_VERBATIM("G4Helper")
228  << "For reference: PhysicsLists in G4PhysListFactory are: ";
229  for (size_t indx=0; indx < list.size(); ++indx ) {
230  MF_LOG_VERBATIM("G4Helper")
231  << " [" << std::setw(2) << indx << "] "
232  << "\"" << list[indx] << "\"";
233  }
234 #endif
235  }
236  } // query factory
237  } // no predetermined user list
238 
239  if ( ! physics ) {
240  MF_LOG_ERROR("G4Helper")
241  << "G4PhysListFactory could not construct \""
242  << phListName
243  << "\","
244  << std::endl
245  << "fall back to using QGSP_BERT";
246 
247  physics = new QGSP_BERT;
248  phListName = "QGSP_BERT";
249 
250  } else {
251  MF_LOG_VERBATIM("G4Helper")
252  << bywhom
253  << " constructed G4VUserPhysicsList \""
254  << phListName
255  << "\"";
256  }
257 
258  }
259 
260  // Extend the physics list with additional physics processes
261  // Already used pstrings[0] entry for physics list name.
262  // The rest should be semi-colon separated list of:
263  // physicsProcessName ( optional UI command , more UI commands )
264  for (unsigned int k=1; k < pstrings.size(); ++k ) {
265  std::string physProcAddition = pstrings[k];
266 
267  // break off UI commands from process name
268  std::vector< std::string > physProcParts;
269  boost::algorithm::split( physProcParts, physProcAddition,
270  boost::is_any_of("(,)"),
271  boost::token_compress_on );
272  // trim lead/trail spaces
273  for (unsigned int j=0; j < physProcParts.size(); ++j )
274  boost::algorithm::trim(physProcParts[j]);
275 
276  // element 0 is the physics process name
277  std::string physProcName = physProcParts[0];
278  if ( physProcName == "" ) continue; // not real, user has trailing ";"
279  G4PhysicsProcessFactorySingleton& procFactory =
281 
282  if ( ! procFactory.IsKnownPhysicsProcess(physProcName) ) {
283  MF_LOG_VERBATIM("G4Helper")
284  << "G4PhysicsProcessFactorySingleton could not "
285  << "construct a \""
286  << physProcName
287  << "\"";
288 
289  if ( ! list_known_procs ) continue;
290  list_known_procs = false;
291  std::vector<G4String> list = procFactory.AvailablePhysicsProcesses();
292  MF_LOG_VERBATIM("G4Helper")
293  << "For reference: PhysicsProcesses in "
294  << "G4PhysicsProcessFactorySingleton are: ";
295 
296  if ( list.empty() )
297  MF_LOG_VERBATIM("G4Helper")
298  << " ... no registered processes";
299  else {
300  for (size_t indx=0; indx < list.size(); ++indx ) {
301  MF_LOG_VERBATIM("G4Helper")
302  << " [" << std::setw(2) << indx << "] "
303  << "\"" << list[indx] << "\"";
304  }
305  }
306  continue;
307  }
308 
309  MF_LOG_VERBATIM("G4Helper")
310  << "Adding \""
311  << physProcName
312  << "\" physics process to \""
313  << phListName
314  << "\"";
315 
316  // construct physics process, add it to the base physics list
317  G4VPhysicsConstructor* pctor = procFactory.GetPhysicsProcess(physProcName);
318 
319 
320  G4VModularPhysicsList* mpl = dynamic_cast<G4VModularPhysicsList*>(physics);
321  if ( ! pctor ) MF_LOG_VERBATIM("G4Helper") << " ... failed with null pointer";
322  else if ( ! mpl ) MF_LOG_VERBATIM("G4Helper") << " ... failed, physics list wasn't a G4VModularPhysicsList";
323  else mpl->RegisterPhysics(pctor);
324 
325  // Handle associated UI commands
326  // One must do it here for cases where values need to be set *before*
327  // one calls SetUserInitialization(physics)
328 
329  for ( unsigned int i=1; i < physProcParts.size(); ++i ) {
330  if ( physProcParts[i] == "" ) continue;
331  MF_LOG_VERBATIM("G4Helper")
332  << physProcParts[i];
333 
334  fUIManager->ApplyCommand(physProcParts[i]);
335  }
336 
337  }
338 
339  // User should have called SetVolumeStepLimit before calling this
340  // method, otherwise fUseStepLimits is always false.
341  if(fUseStepLimits){
342  auto mpl = dynamic_cast<G4VModularPhysicsList*>(physics);
343  if(mpl) mpl->RegisterPhysics(new G4StepLimiterPhysics());
344  else
345  MF_LOG_WARNING("G4Helper")
346  << "Step limits requested, but unable to register G4StepLimiterPhysics"
347  << "\n NO STEP LIMITS WILL BE APPLIED";
348  }
349 
350  // pass off (possibly augmented) physics list to run manager
351  // which calls G4RunManagerKernel->SetPhysics() on it
352  // which itself call ConstructParticle() for the list
353  fRunManager->SetUserInitialization(physics);
354  }
355 
356  //------------------------------------------------
357  void G4Helper::SetParallelWorlds(std::vector<G4VUserParallelWorld*> pworlds)
358  {
359  for(auto const& pw : pworlds){
360  MF_LOG_DEBUG("G4Helper") << pw->GetName();
361  fParallelWorlds.push_back(pw);
362  }
363 
364  return;
365  }
366 
367  //------------------------------------------------
369  {
370  // Build the Geant4 detector description.
371  bool checkOverlaps = fCheckOverlaps;
372  bool validateGDMLSchema = fValidateGDMLSchema;
373  fDetector = new DetectorConstruction(gdmlFile,
374  checkOverlaps,
375  validateGDMLSchema);
376 
377  return;
378  }
379 
380  //------------------------------------------------
382  double maxStepSize)
383  {
384  // get the logical volume for the desired volume name
385  G4LogicalVolume* logVol = G4LogicalVolumeStore::GetInstance()->GetVolume(volumeName);
386 
387  if(logVol){
388  // the logical volume takes ownership of the G4UserLimits pointer
389  G4UserLimits *stepLimit = new G4UserLimits(maxStepSize);
390  logVol->SetUserLimits(stepLimit);
391 
392  fUseStepLimits = true;
393  }
394  else{
395  MF_LOG_WARNING("G4Helper")
396  << "Unable to find volume "
397  << volumeName
398  << " and set step size limit";
399  }
400 
401  return;
402  }
403 
404 
405  //------------------------------------------------
406  /// Initialization for the Geant4 Monte Carlo.
408  {
410 
411  for(auto pWorld : fParallelWorlds)
412  fDetector->RegisterParallelWorld(pWorld);
413 
414  // define the physics list to use
416 
417  // Pass the detector geometry on to Geant4.
418  fRunManager->SetUserInitialization(fDetector);
419 
420  // Tell the Geant4 run manager how to generate events. The
421  // ConvertMCTruthToG4 class will "generate" events by
422  // converting MCTruth objects from the input into G4Events.
424  fRunManager->SetUserAction(fConvertMCTruth);
425 
426  return;
427  }
428 
429 
430  //------------------------------------------------
431  /// Initialization for the Geant4 Monte Carlo.
433  {
434  // Geant4 comes with "user hooks" that allows users to perform
435  // special tasks at the beginning and end of runs, events, tracks,
436  // steps. By using the UserActionManager, we've separated each
437  // set of user tasks into their own class; e.g., there can be one
438  // class for processing particles, one class for histograms, etc.
439 
440  // Use the UserActionManager to handle all the Geant4 user hooks.
442 
443  // Tell the run manager about our user-action classes. We convert
444  // the UserActionManager into different types so Geant4's run and
445  // event managers will initialize them properly.
446  G4UserRunAction* runAction = (G4UserRunAction* ) uaManager;
447  G4UserEventAction* eventAction = (G4UserEventAction* ) uaManager;
448  G4UserTrackingAction* trackingAction = (G4UserTrackingAction*) uaManager;
449  G4UserSteppingAction* steppingAction = (G4UserSteppingAction*) uaManager;
450  fRunManager->SetUserAction( runAction );
451  fRunManager->SetUserAction( eventAction );
452  fRunManager->SetUserAction( trackingAction );
453  fRunManager->SetUserAction( steppingAction );
454 
455  if ( uaManager->DoesAnyActionProvideStacking() ) {
456  G4UserStackingAction* stackingAction = (G4UserStackingAction*) uaManager;
457  fRunManager->SetUserAction( stackingAction );
458  }
459 
460  /// Tell Geant4 to initialize the run manager. We're ready to
461  /// simulate events in the detector.
462  fRunManager->Initialize();
463 
464  if(!vm_) vm_ = new G4VisExecutive();
465  vm_->Initialize();
466 
467  // Tell the manager to execute the contents of the Geant4 macro
468  // file.
469  if ( ! fG4MacroPath.empty() ) {
470  G4String command = "/control/execute " + G4String(fG4MacroPath);
471  fUIManager->ApplyCommand(command);
472  }
473 
474 
475  return;
476  }
477 
478  //------------------------------------------------
480  {
481  return this->G4Run( primary.get() );
482  }
483 
484  //------------------------------------------------
485  bool G4Helper::G4Run(const simb::MCTruth* primary)
486  {
487  // Get the event converter ready.
489 
490  // Pass the MCTruth to our event generator.
491  fConvertMCTruth->Append( primary );
492 
493  // Start the simulation for this event. Note: The following
494  // statement increments the G4RunManager's run number. Because of
495  // this, it's important for events to use the run/event number
496  // from the EventDataModel Header, not G4's internal numbers.
497  fUIManager->ApplyCommand("/run/beamOn 1");
498 
499  return true;
500  }
501 
502  //------------------------------------------------
503  bool G4Helper::G4Run(std::vector<const simb::MCTruth*> &primaries)
504  {
505  // Get the event converter ready.
507 
508  // Pass all the MCTruths to our event generator.
509  for(auto primary : primaries)
510  fConvertMCTruth->Append( primary );
511 
512  // Start the simulation for this event. Note: The following
513  // statement increments the G4RunManager's run number. Because of
514  // this, it's important for events to use the run/event number
515  // from the EventDataModel Header, not G4's internal numbers.
516  fUIManager->ApplyCommand("/run/beamOn 1");
517 
518  return true;
519  }
520 
521 } // namespace
virtual ~G4Helper()
Definition: G4Helper.cxx:93
static std::string trim(const std::string &str, const std::string &whitespace=" \t")
Definition: doxyindexer.cpp:47
virtual bool DoesAnyActionProvideStacking()
void Reset()
Get ready to convert a new set of MCTruth objects.
bool fValidateGDMLSchema
Have G4GDML validate geometry schema?
Definition: G4Helper.h:114
std::string string
Definition: nybbler.cc:12
bool G4Run(std::vector< const simb::MCTruth * > &primaries)
Definition: G4Helper.cxx:503
int command
void SetUserAction()
Initialization for the Geant4 Monte Carlo.
Definition: G4Helper.cxx:432
void ConstructDetector(std::string const &gdmlFile)
Definition: G4Helper.cxx:368
#define MF_LOG_ERROR(category)
void SetParallelWorlds(std::vector< G4VUserParallelWorld * > pworlds)
Definition: G4Helper.cxx:357
std::vector< G4VUserParallelWorld * > fParallelWorlds
list of parallel worlds
Definition: G4Helper.h:122
const std::vector< G4String > & AvailablePhysicsProcesses() const
void InitPhysics()
Initialization for the Geant4 Monte Carlo.
Definition: G4Helper.cxx:407
void SetPhysicsList(std::string physicsList)
Definition: G4Helper.cxx:142
static G4VisExecutive * vm_
Definition: G4Helper.cxx:51
G4VModularPhysicsList * GetReferencePhysList(const G4String &)
std::string fGDMLFile
Name of the gdml file containing the detector Geometry.
Definition: G4Helper.h:112
static G4PhysicsProcessFactorySingleton & Instance()
bool fCheckOverlaps
Have G4GDML check for overlaps?
Definition: G4Helper.h:113
basic interface to Geant4 for ART-based software
void SetVolumeStepLimit(std::string const &volumeName, double maxStepSize)
Definition: G4Helper.cxx:381
std::string fG4MacroPath
to be executed before main MC processing.
Definition: G4Helper.h:109
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
DetectorConstruction * fDetector
DetectorConstruction object.
Definition: G4Helper.h:121
G4Helper()
Standard constructor and destructor for an FMWK module.
Definition: G4Helper.cxx:55
static UserActionManager * Instance()
#define MF_LOG_VERBATIM(category)
G4RunManager * fRunManager
Geant4&#39;s run manager.
Definition: G4Helper.h:117
std::string fG4PhysListName
Name of physics list to use.
Definition: G4Helper.h:111
#define MF_LOG_DEBUG(id)
void split(std::string const &s, char c, OutIter dest)
Definition: split.h:35
void Append(art::Ptr< simb::MCTruth > &mct)
Event generator information.
Definition: MCTruth.h:32
bool fUseStepLimits
Set in SetVolumeStepLimit.
Definition: G4Helper.h:115
#define MF_LOG_WARNING(category)
T const * get() const
Definition: Ptr.h:149
G4VPhysicsConstructor * GetPhysicsProcess(const G4String &)
ConvertMCTruthToG4 * fConvertMCTruth
Geant4 event generator.
Definition: G4Helper.h:119
QTextStream & endl(QTextStream &s)
G4UImanager * fUIManager
Geant4&#39;s user-interface manager.
Definition: G4Helper.h:118