DD4hep - The AIDA detector description toolkit for high energy physics experiments
DD4hep  Rev:Unversioneddirectory
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Geant4Kernel.cpp
Go to the documentation of this file.
1 // $Id: $
2 //==========================================================================
3 // AIDA Detector description implementation for LCD
4 //--------------------------------------------------------------------------
5 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
6 // All rights reserved.
7 //
8 // For the licensing terms see $DD4hepINSTALL/LICENSE.
9 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
10 //
11 // Author : M.Frank
12 //
13 //==========================================================================
14 
15 // Framework include files
16 #include "DD4hep/LCDD.h"
17 #include "DD4hep/Memory.h"
18 #include "DD4hep/Printout.h"
19 #include "DD4hep/Primitives.h"
20 #include "DD4hep/InstanceCount.h"
21 
22 #include "DDG4/Geant4Kernel.h"
23 #include "DDG4/Geant4Context.h"
24 #include "DDG4/Geant4ActionPhase.h"
25 
26 // Geant4 include files
27 #ifdef G4MULTITHREADED
28 #include "G4MTRunManager.hh"
29 #else
30 #include "G4RunManager.hh"
31 #endif
32 #include "G4UIdirectory.hh"
33 #include "G4Threading.hh"
34 #include "G4AutoLock.hh"
35 
36 // C/C++ include files
37 #include <stdexcept>
38 #include <algorithm>
39 #include <pthread.h>
40 #include <memory>
41 
42 using namespace std;
43 using namespace DD4hep::Simulation;
44 
45 namespace {
46  G4Mutex kernel_mutex=G4MUTEX_INITIALIZER;
47  DD4hep::dd4hep_ptr<Geant4Kernel> s_main_instance(0);
48 }
49 
51 Geant4Kernel::PhaseSelector::PhaseSelector(Geant4Kernel* kernel)
52  : m_kernel(kernel) {
53 }
54 
57  : m_kernel(c.m_kernel) {
58 }
59 
62  if ( this != &c ) {
63  m_kernel = c.m_kernel;
64  }
65  return *this;
66 }
67 
70  Geant4ActionPhase* action_phase = m_kernel->getPhase(nam);
71  if ( action_phase ) {
72  return *action_phase;
73  }
74  throw runtime_error(format("Geant4Kernel", "Attempt to access the nonexisting phase '%s'", nam.c_str()));
75 }
76 
79  : Geant4ActionContainer(), m_runManager(0), m_control(0), m_trackMgr(0), m_lcdd(&lcdd_ref),
81 {
82  m_lcdd->addExtension < Geant4Kernel > (this);
83  m_ident = -1;
85  declareProperty("OutputLevel", m_outputLevel = DEBUG);
86  declareProperty("NumEvents", m_numEvent = 10);
87  declareProperty("OutputLevels", m_clientLevels);
88  declareProperty("NumberOfThreads",m_numThreads);
89  m_controlName = "/ddg4/";
90  m_control = new G4UIdirectory(m_controlName.c_str());
91  m_control->SetGuidance("Control for named Geant4 actions");
92  setContext(new Geant4Context(this));
93  //m_shared = new Geant4Kernel(lcdd_ref, this, -2);
95 }
96 
99  : Geant4ActionContainer(), m_runManager(0), m_control(0), m_trackMgr(0), m_lcdd(0),
100  m_numThreads(1), m_id(ident), m_master(m), m_shared(0), phase(this)
101 {
102  char text[64];
104  m_ident = m_master->m_workers.size();
108  ::snprintf(text,sizeof(text),"/ddg4.%d/",(int)(m_master->m_workers.size()));
109  m_controlName = text;
110  m_control = new G4UIdirectory(m_controlName.c_str());
111  m_control->SetGuidance("Control for thread specific Geant4 actions");
112  setContext(new Geant4Context(this));
114 }
115 
118  if ( this == s_main_instance.get() ) {
119  s_main_instance.release();
120  }
122  if ( isMaster() ) {
125  }
126  destroyPhases();
129  if ( m_lcdd && isMaster() ) {
130  try {
131  m_lcdd->removeExtension < Geant4Kernel > (false);
133  m_lcdd = 0;
134  }
135  catch(...) {
136  }
137  }
139 }
140 
143  if ( 0 == s_main_instance.get() ) {
144  G4AutoLock protection_lock(&kernel_mutex); {
145  if ( 0 == s_main_instance.get() ) { // Need to check again!
146  s_main_instance.adopt(new Geant4Kernel(lcdd));
147  }
148  }
149  }
150  return *(s_main_instance.get());
151 }
152 
154 unsigned long int Geant4Kernel::thread_self() {
155  unsigned long int thr_id = (unsigned long int)::pthread_self();
156  return thr_id;
157 }
158 
161  if ( isMaster() ) {
162  unsigned long identifier = thread_self();
163  Geant4Kernel* w = new Geant4Kernel(this, identifier);
164  m_workers[identifier] = w;
165  printout(INFO,"Geant4Kernel","+++ Created worker instance id=%ul",identifier);
166  return *w;
167  }
168  throw runtime_error(format("Geant4Kernel", "DDG4: Only the master instance may create workers."));
169 }
170 
172 Geant4Kernel& Geant4Kernel::worker(unsigned long identifier, bool create_if) {
173  Workers::iterator i = m_workers.find(identifier);
174  if ( i != m_workers.end() ) {
175  return *((*i).second);
176  }
177  else if ( identifier == m_id ) {
178  return *this;
179  }
180  else if ( !isMultiThreaded() ) {
181  unsigned long self = thread_self();
182  if ( identifier == self ) {
183  return *this;
184  }
185  }
186  else if ( create_if ) {
187  return createWorker();
188  }
189  throw runtime_error(format("Geant4Kernel", "DDG4: The Kernel object 0x%p does not exists!",(void*)identifier));
190 }
191 
194  return m_workers.size();
195 }
196 
198  printout(ALWAYS,"Geant4Kernel","OutputLevel: %d", m_outputLevel);
199  printout(ALWAYS,"Geant4Kernel","UI: %s", m_uiName.c_str());
200  printout(ALWAYS,"Geant4Kernel","NumEvents: %ld",m_numEvent);
201  printout(ALWAYS,"Geant4Kernel","NumThreads: %d", m_numThreads);
202  for(ClientOutputLevels::const_iterator i=m_clientLevels.begin(); i!=m_clientLevels.end();++i) {
203  printout(ALWAYS,"Geant4Kernel","OutputLevel[%s]: %d",(*i).first.c_str(),(*i).second);
204  }
205 }
206 
208 bool Geant4Kernel::hasProperty(const std::string& name) const {
209  return m_properties.exists(name);
210 }
211 
213 DD4hep::Property& Geant4Kernel::property(const std::string& name) {
214  return properties()[name];
215 }
216 
218 void Geant4Kernel::setOutputLevel(const std::string object, PrintLevel new_level) {
219  m_clientLevels[object] = new_level;
220 }
221 
223 DD4hep::PrintLevel Geant4Kernel::getOutputLevel(const std::string object) const {
224  ClientOutputLevels::const_iterator i=m_clientLevels.find(object);
225  if ( i != m_clientLevels.end() ) return (PrintLevel)(*i).second;
227 }
228 
231  int old = m_outputLevel;
232  m_outputLevel = new_level;
233  return (PrintLevel)old;
234 }
235 
237 G4RunManager& Geant4Kernel::runManager() {
238  if ( m_runManager ) {
239  return *m_runManager;
240  }
241  else if ( isMaster() ) {
242 #ifdef G4MULTITHREADED
243  if ( m_numThreads > 0 ) {
244  printout(WARNING,"Geant4Kernel","+++ Multi-threaded mode requested with %d worker threads.",m_numThreads);
245  G4MTRunManager* run_mgr = new G4MTRunManager;
246  run_mgr->SetNumberOfThreads(m_numThreads);
247  m_runManager = run_mgr;
248  return *m_runManager;
249  }
250 #endif
251  if ( m_numThreads > 0 ) {
252  printout(WARNING,"Geant4Kernel","+++ Multi-threaded mode requested, "
253  "but not supported by this compilation of Geant4.");
254  printout(WARNING,"Geant4Kernel","+++ Falling back to single threaded mode.");
255  m_numThreads = 0;
256  }
257  return *(m_runManager = new G4RunManager);
258  }
259  throw runtime_error(format("Geant4Kernel",
260  "DDG4: Only the master thread may instantiate "
261  "a G4RunManager object!"));
262 }
263 
265 void Geant4Kernel::loadGeometry(const std::string& compact_file) {
266  char* arg = (char*) compact_file.c_str();
267  m_lcdd->apply("DD4hepXMLLoader", 1, &arg);
268  //return *this;
269 }
270 
271 // Utility function to load XML files
272 void Geant4Kernel::loadXML(const char* fname) {
273  const char* args[] = { fname, 0 };
274  m_lcdd->apply("DD4hepXMLLoader", 1, (char**) args);
275 }
276 
278  return Geant4Exec::configure(*this);
279 }
280 
282  return Geant4Exec::initialize(*this);
283 }
284 
286  try {
287  return Geant4Exec::run(*this);
288  }
289  catch(const exception& e) {
290  printout(FATAL,"Geant4Kernel","+++ Exception while simulating:%s",e.what());
291  }
292  catch(...) {
293  printout(FATAL,"Geant4Kernel","+++ UNKNOWN exception while simulating.");
294  }
295  return 0;
296 }
297 
298 int Geant4Kernel::runEvents(int num_events) {
299  m_numEvent = num_events;
300  return Geant4Exec::run(*this);
301 }
302 
304  const Geant4Kernel* ptr = s_main_instance.get();
305  printout(INFO,"Geant4Kernel","++ Terminate Geant4 and delete associated actions.");
306  if ( ptr == this ) {
307  Geant4Exec::terminate(*this);
308  }
309  destroyPhases();
312  if ( ptr == this ) {
314  }
316  if ( ptr == this && m_lcdd ) {
317  m_lcdd->removeExtension < Geant4Kernel > (false);
319  m_lcdd = 0;
320  }
321  return 1;
322 }
323 
325 
330  if (action) {
331  string nam = action->name();
332  GlobalActions::const_iterator i = m_globalActions.find(nam);
333  if (i == m_globalActions.end()) {
334  action->addRef();
335  m_globalActions[nam] = action;
336  printout(INFO,"Geant4Kernel","++ Registered global action %s of type %s",
337  nam.c_str(),typeName(typeid(*action)).c_str());
338  return *this;
339  }
340  throw runtime_error(format("Geant4Kernel", "DDG4: The action '%s' is already globally "
341  "registered. [Action-Already-Registered]", nam.c_str()));
342  }
343  throw runtime_error(format("Geant4Kernel", "DDG4: Attempt to globally register an invalid "
344  "action. [Action-Invalid]"));
345 }
346 
348 Geant4Action* Geant4Kernel::globalAction(const std::string& action_name, bool throw_if_not_present) {
349  GlobalActions::iterator i = m_globalActions.find(action_name);
350  if (i == m_globalActions.end()) {
351  if (throw_if_not_present) {
352  throw runtime_error(format("Geant4Kernel", "DDG4: The action '%s' is not globally "
353  "registered. [Action-Missing]", action_name.c_str()));
354  }
355  return 0;
356  }
357  return (*i).second;
358 }
359 
361 
366  if (filter) {
367  string nam = filter->name();
368  GlobalActions::const_iterator i = m_globalFilters.find(nam);
369  if (i == m_globalFilters.end()) {
370  filter->addRef();
371  m_globalFilters[nam] = filter;
372  return *this;
373  }
374  throw runtime_error(format("Geant4Kernel", "DDG4: The filter '%s' is already globally "
375  "registered. [Filter-Already-Registered]", nam.c_str()));
376  }
377  throw runtime_error(format("Geant4Kernel", "DDG4: Attempt to globally register an invalid "
378  "filter. [Filter-Invalid]"));
379 }
380 
382 Geant4Action* Geant4Kernel::globalFilter(const std::string& filter_name, bool throw_if_not_present) {
383  GlobalActions::iterator i = m_globalFilters.find(filter_name);
384  if (i == m_globalFilters.end()) {
385  if (throw_if_not_present) {
386  throw runtime_error(format("Geant4Kernel", "DDG4: The filter '%s' is not already globally "
387  "registered. [Filter-Missing]", filter_name.c_str()));
388  }
389  return 0;
390  }
391  return (*i).second;
392 }
393 
395 bool Geant4Kernel::executePhase(const std::string& nam, const void** arguments) const {
396  Phases::const_iterator i = m_phases.find(nam);
397  if (i != m_phases.end()) {
398  (*i).second->execute(arguments);
399  return true;
400  }
401  return false;
402 }
403 
405 Geant4ActionPhase* Geant4Kernel::getPhase(const std::string& nam) {
406  Phases::const_iterator i = m_phases.find(nam);
407  if (i != m_phases.end()) {
408  return (*i).second;
409  }
410  throw runtime_error(format("Geant4Kernel", "DDG4: The Geant4 action phase '%s' "
411  "does not exist. [No-Entry]", nam.c_str()));
412 }
413 
415 Geant4ActionPhase* Geant4Kernel::addSimplePhase(const std::string& name, bool throw_on_exist) {
416  return addPhase(name,typeid(void),typeid(void),typeid(void),throw_on_exist);
417 }
418 
420 Geant4ActionPhase* Geant4Kernel::addPhase(const std::string& nam, const type_info& arg0, const type_info& arg1,
421  const type_info& arg2, bool throw_on_exist) {
422  Phases::const_iterator i = m_phases.find(nam);
423  if (i == m_phases.end()) {
424  Geant4ActionPhase* p = new Geant4ActionPhase(workerContext(), nam, arg0, arg1, arg2);
425  m_phases.insert(make_pair(nam, p));
426  return p;
427  }
428  else if (throw_on_exist) {
429  throw runtime_error(format("Geant4Kernel", "DDG4: The Geant4 action phase %s "
430  "already exists. [Already-Exists]", nam.c_str()));
431  }
432  return (*i).second;
433 }
434 
436 bool Geant4Kernel::removePhase(const std::string& nam) {
437  Phases::iterator i = m_phases.find(nam);
438  if (i != m_phases.end()) {
439  delete (*i).second;
440  m_phases.erase(i);
441  return true;
442  }
443  return false;
444 }
445 
449 }
virtual Geant4ActionPhase * addPhase(const std::string &name, const std::type_info &arg1, const std::type_info &arg2, const std::type_info &arg3, bool throw_on_exist)
Add a new phase to the phase.
The property class to assign options to actions.
IFACE * addExtension(CONCRETE *c)
Extend the sensitive detector element with an arbitrary structure accessible by the type...
Definition: LCDD.h:290
PropertyManager & properties()
Access to the properties of the object.
Definition: Geant4Kernel.h:167
ClientOutputLevels m_clientLevels
Property: Client output levels.
Definition: Geant4Kernel.h:81
Geant4Kernel & worker(unsigned long thread_identifier, bool create_if=false)
Access worker instance by it's identifier.
virtual long apply(const char *factory, int argc, char **argv)=0
Manipulate geometry using factory converter.
static unsigned long int thread_self()
Access thread identifier.
Geant4Kernel & declareProperty(const std::string &nam, T &val)
Declare property.
Definition: Geant4Kernel.h:262
int numWorkers() const
Access number of workers.
GlobalActions m_globalFilters
Globally registered filters of sensitive detectors.
Definition: Geant4Kernel.h:71
void deletePtr(T *&p)
Helper to delete objects from heap and reset the pointer. Saves many many lines of code...
Definition: Primitives.h:234
void setContext(Geant4Context *ctxt)
Set the thread's context.
virtual Geant4ActionPhase * addSimplePhase(const std::string &name, bool throw_on_exist)
Add a new phase to the phase.
Geant4Kernel * m_kernel
Reference to embedding object.
Definition: Geant4Kernel.h:129
int m_outputLevel
Property: Output level.
Definition: Geant4Kernel.h:79
static void decrement(T *)
Decrement count according to type information.
std::string typeName(const std::type_info &type)
ABI information about type names.
Definition: Primitives.cpp:186
virtual int runEvents(int num_events)
Run the simulation: Simulate the number of events "num_events" and modify the property "NumEvents"...
Geant4ActionPhase & operator[](const std::string &name) const
Phase access to the map.
G4RunManager * m_runManager
Reference to the run manager.
Definition: Geant4Kernel.h:53
GlobalActions m_globalActions
Globally registered actions.
Definition: Geant4Kernel.h:69
static int terminate(Geant4Kernel &kernel)
Terminate the application.
Definition: Geant4Exec.cpp:620
Out version of the std auto_ptr implementation base either on auto_ptr or unique_ptr.
Definition: Memory.h:43
return e
Definition: Volumes.cpp:297
virtual int initialize()
Run the simulation: Initialize Geant4.
PrintLevel printLevel()
Access the current printer level.
Definition: Printout.cpp:323
PrintLevel
Definition: Printout.h:47
Property & property(const std::string &name)
Access single property.
const std::string & name() const
Access name of the action.
Definition: Geant4Action.h:271
std::string m_uiName
Property: Name of the UI action. Must be member of the global actions.
Definition: Geant4Kernel.h:75
std::string format(const std::string &src, const std::string &fmt,...)
Build formatted string.
Definition: Printout.cpp:267
PhaseSelector(Geant4Kernel *kernel)
Standard constructor.
virtual int run()
Run the simulation: Simulate the number of events given by the property "NumEvents".
virtual Geant4Kernel & createWorker()
Create identified worker instance.
Geant4ActionPhase * getPhase(const std::string &name)
Access phase by name.
static int initialize(Geant4Kernel &kernel)
Initialize the application.
Definition: Geant4Exec.cpp:583
Geant4Kernel(Geant4Kernel *m, unsigned long identifier)
Standard constructor for workers.
Class, which allows all Geant4Action derivatives to access the DDG4 kernel structures.
Definition: Geant4Kernel.h:43
Geant4Kernel * m_master
Parent reference.
Definition: Geant4Kernel.h:90
virtual ~Geant4Kernel()
Default destructor.
Class, which allows all Geant4Action to be stored.
void destroyObjects(M &m)
Definition: Primitives.h:293
long addRef()
Increase reference count.
PropertyManager m_properties
Property pool.
Definition: Geant4Kernel.h:61
Geant4Kernel & registerGlobalAction(Geant4Action *action)
Register action by name to be retrieved when setting up and connecting action objects.
Embedded helper class to facilitate map access to the phases.
Definition: Geant4Kernel.h:126
Workers m_workers
Worker threads.
Definition: Geant4Kernel.h:67
PrintLevel setOutputLevel(PrintLevel new_level)
Set the global output level of the kernel object; returns previous value.
virtual void loadXML(const char *fname)
Load XML file.
bool hasProperty(const std::string &name) const
Check property for existence.
void releaseObjects(M &m)
Definition: Primitives.h:344
virtual int terminate()
Run the simulation: Terminate Geant4.
int m_numThreads
Property: Running in multi threaded context.
Definition: Geant4Kernel.h:86
virtual void destroyPhases()
Destroy all phases. To be called only at shutdown.
Geant4Context * workerContext()
Thread's Geant4 execution context.
static void destroyInstance()
Destroy the instance.
Definition: LCDDImp.cpp:94
static void increment(T *)
Increment count according to type information.
Definition: InstanceCount.h:98
G4TrackingManager * m_trackMgr
Reference to Geant4 track manager.
Definition: Geant4Kernel.h:57
std::string m_controlName
Property: Name of the G4UI command tree.
Definition: Geant4Kernel.h:73
bool exists(const std::string &name) const
Check for existence.
LCDD * m_lcdd
Detector description object.
Definition: Geant4Kernel.h:59
Phases m_phases
Action phases.
Definition: Geant4Kernel.h:65
virtual bool executePhase(const std::string &name, const void **args) const
Execute phase action if it exists.
PhaseSelector & operator=(const PhaseSelector &c)
Assignment operator.
G4RunManager & runManager()
Access to the Geant4 run manager.
virtual void loadGeometry(const std::string &compact_file)
Construct detector geometry using lcdd plugin.
static int configure(Geant4Kernel &kernel)
Configure the application.
Definition: Geant4Exec.cpp:514
Geant4Action * globalFilter(const std::string &filter_name, bool throw_if_not_present=true)
Retrieve filter from repository.
class DD4hep::Simulation::Geant4Kernel::PhaseSelector phase
Generic context to extend user, run and event information.
Action phase definition. Client callback at various stage of the simulation processing.
long m_numEvent
Property: Number of events to be executed in batch mode.
Definition: Geant4Kernel.h:77
The main interface to the DD4hep detector description package.
Definition: LCDD.h:82
unsigned long m_id
Flag: Master instance (id<0) or worker (id >= 0)
Definition: Geant4Kernel.h:88
virtual int configure()
Run the simulation: Configure Geant4.
int printout(PrintLevel severity, const char *src, const char *fmt,...)
Calls the display action with a given severity level.
Definition: Printout.cpp:111
static int run(Geant4Kernel &kernel)
Run the application and simulate events.
Definition: Geant4Exec.cpp:595
virtual bool removePhase(const std::string &name)
Remove an existing phase from the phase. If not existing returns false.
Geant4Action * globalAction(const std::string &action_name, bool throw_if_not_present=true)
Retrieve action from repository.
static Geant4Kernel & instance(LCDD &lcdd)
Instance accessor.
T * removeExtension(bool destroy=true)
Remove an existing extension object from the LCDD instance. If not destroyed, the instance is returne...
Definition: LCDD.h:295
G4UIdirectory * m_control
Top level control directory.
Definition: Geant4Kernel.h:55
void printProperties() const
Print the property values.
Default base class for all Geant 4 actions and derivates thereof.
Definition: Geant4Action.h:91
TGeoShape TGeoMedium * m
Definition: Volumes.cpp:294
virtual int terminate()
Terminate all associated action instances.
Geant4Kernel & registerGlobalFilter(Geant4Action *filter)
Register filter by name to be retrieved when setting up and connecting filter objects.
std::string arguments(int argc, char **argv)
Helper function to serialize argument list to a single string.
Definition: Printout.cpp:96
PrintLevel getOutputLevel(const std::string object) const
Retrieve the global output level of a named object.