DDG4.py
Go to the documentation of this file.
1 # ==========================================================================
2 # AIDA Detector description implementation
3 # --------------------------------------------------------------------------
4 # Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 # All rights reserved.
6 #
7 # For the licensing terms see $DD4hepINSTALL/LICENSE.
8 # For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 #
10 # ==========================================================================
11 from __future__ import absolute_import, unicode_literals
12 import logging
13 from dd4hep_base import * # noqa: F403
14 import ddsix as six
15 
16 logger = logging.getLogger(__name__)
17 
18 
19 def loadDDG4():
20  import ROOT
21  from ROOT import gSystem
22 
23  # Try to load libglapi to avoid issues with TLS Static
24  # Turn off all errors from ROOT about the library missing
25  if('libglapi' not in gSystem.GetLibraries()):
26  orgLevel = ROOT.gErrorIgnoreLevel
27  ROOT.gErrorIgnoreLevel = 6000
28  gSystem.Load("libglapi")
29  ROOT.gErrorIgnoreLevel = orgLevel
30 
31  import platform
32  import os
33  if platform.system() == "Darwin":
34  gSystem.SetDynamicPath(os.environ['DD4HEP_LIBRARY_PATH'])
35  os.environ['DYLD_LIBRARY_PATH'] = os.pathsep.join([os.environ['DD4HEP_LIBRARY_PATH'],
36  os.environ.get('DYLD_LIBRARY_PATH', '')]).strip(os.pathsep)
37 
38  result = gSystem.Load("libDDG4Plugins")
39  if result < 0:
40  raise Exception('DDG4.py: Failed to load the DDG4 library libDDG4Plugins: ' + gSystem.GetErrorStr())
41  from ROOT import dd4hep as module
42  return module
43 
44 
45 # We are nearly there ....
46 current = __import__(__name__)
47 
48 
49 def _import_class(ns, nam):
50  scope = getattr(current, ns)
51  setattr(current, nam, getattr(scope, nam))
52 
53 
54 try:
55  dd4hep = loadDDG4()
56 except Exception as X:
57  logger.error('+--%-100s--+', 100 * '-')
58  logger.error('| %-100s |', 'Failed to load DDG4 library:')
59  logger.error('| %-100s |', str(X))
60  logger.error('+--%-100s--+', 100 * '-')
61  exit(1)
62 
63 from ROOT import CLHEP as CLHEP # noqa
64 Core = dd4hep
66 Simulation = dd4hep.sim
67 Kernel = Sim.KernelHandle
68 Interface = Sim.Geant4ActionCreation
69 Detector = Core.Detector
70 
71 
72 def _constant(self, name):
73  return self.constantAsString(name)
74 
75 
76 Detector.globalVal = _constant
77 
78 
79 def importConstants(description, namespace=None, debug=False):
80  """
81  Import the Detector constants into the DDG4 namespace
82  """
83  ns = current
84  if namespace is not None and not hasattr(current, namespace):
85  import imp
86  m = imp.new_module('DDG4.' + namespace)
87  setattr(current, namespace, m)
88  ns = m
89  evaluator = dd4hep.g4Evaluator()
90  cnt = 0
91  num = 0
92  todo = {}
93  strings = {}
94  for c in description.constants():
95  if c.second.dataType == 'string':
96  strings[c.first] = c.second.GetTitle()
97  else:
98  todo[c.first] = c.second.GetTitle().replace('(int)', '')
99  while len(todo) and cnt < 100:
100  cnt = cnt + 1
101  if cnt == 100:
102  logger.error('%s %d out of %d %s "%s": [%s]\n+++ %s',
103  '+++ FAILED to import',
104  len(todo), len(todo) + num,
105  'global values into namespace',
106  ns.__name__, 'Try to continue anyway', 100 * '=')
107  for k, v in todo.items():
108  if not hasattr(ns, k):
109  logger.error('+++ FAILED to import: "' + k + '" = "' + str(v) + '"')
110  logger.info('+++ %s', 100 * '=')
111 
112  for k, v in list(todo.items()):
113  if not hasattr(ns, k):
114  val = evaluator.evaluate(v)
115  status = evaluator.status()
116  if status == 0:
117  evaluator.setVariable(k, val)
118  setattr(ns, k, val)
119  if debug:
120  logger.info('Imported global value: "' + k + '" = "' + str(val) + '" into namespace' + ns.__name__)
121  del todo[k]
122  num = num + 1
123  if cnt < 100:
124  logger.info('+++ Imported %d global values to namespace:%s', num, ns.__name__,)
125 
126 
127 def _registerGlobalAction(self, action):
128  self.get().registerGlobalAction(Interface.toAction(action))
129 
130 
131 def _registerGlobalFilter(self, filter):
132  self.get().registerGlobalFilter(Interface.toAction(filter))
133 
134 
135 def _getKernelProperty(self, name):
136  ret = Interface.getPropertyKernel(self.get(), name)
137  if ret.status > 0:
138  return ret.data
139  elif hasattr(self.get(), name):
140  return getattr(self.get(), name)
141  elif hasattr(self, name):
142  return getattr(self, name)
143  msg = 'Geant4Kernel::GetProperty [Unhandled]: Cannot access Kernel.' + name
144  raise KeyError(msg)
145 
146 
147 def _setKernelProperty(self, name, value):
148  if Interface.setPropertyKernel(self.get(), str(name), str(value)):
149  return
150  msg = 'Geant4Kernel::SetProperty [Unhandled]: Cannot set Kernel.' + name + ' = ' + str(value)
151  raise KeyError(msg)
152 
153 
154 def _kernel_phase(self, name):
155  return self.addSimplePhase(str(name), False)
156 
157 
158 def _kernel_worker(self):
159  return Kernel(self.get().createWorker())
160 
161 
162 def _kernel_terminate(self):
163  return self.get().terminate()
164 
165 
166 Kernel.phase = _kernel_phase
167 Kernel.registerGlobalAction = _registerGlobalAction
168 Kernel.registerGlobalFilter = _registerGlobalFilter
169 Kernel.createWorker = _kernel_worker
170 Kernel.__getattr__ = _getKernelProperty
171 Kernel.__setattr__ = _setKernelProperty
172 Kernel.terminate = _kernel_terminate
173 
174 ActionHandle = Sim.ActionHandle
175 
176 
177 def SensitiveAction(kernel, nam, det, shared=False):
178  return Interface.createSensitive(kernel, str(nam), str(det), shared)
179 
180 
181 def Action(kernel, nam, shared=False):
182  return Interface.createAction(kernel, str(nam), shared)
183 
184 
185 def Filter(kernel, nam, shared=False):
186  return Interface.createFilter(kernel, str(nam), shared)
187 
188 
189 def PhaseAction(kernel, nam, shared=False):
190  return Interface.createPhaseAction(kernel, str(nam), shared)
191 
192 
193 def RunAction(kernel, nam, shared=False):
194  return Interface.createRunAction(kernel, str(nam), shared)
195 
196 
197 def EventAction(kernel, nam, shared=False):
198  return Interface.createEventAction(kernel, str(nam), shared)
199 
200 
201 def GeneratorAction(kernel, nam, shared=False):
202  return Interface.createGeneratorAction(kernel, str(nam), shared)
203 
204 
205 def TrackingAction(kernel, nam, shared=False):
206  return Interface.createTrackingAction(kernel, str(nam), shared)
207 
208 
209 def SteppingAction(kernel, nam, shared=False):
210  return Interface.createSteppingAction(kernel, str(nam), shared)
211 
212 
213 def StackingAction(kernel, nam, shared=False):
214  return Interface.createStackingAction(kernel, str(nam), shared)
215 
216 
217 def DetectorConstruction(kernel, nam):
218  return Interface.createDetectorConstruction(kernel, str(nam))
219 
220 
221 def PhysicsList(kernel, nam):
222  return Interface.createPhysicsList(kernel, str(nam))
223 
224 
225 def UserInitialization(kernel, nam):
226  return Interface.createUserInitialization(kernel, str(nam))
227 
228 
229 def SensitiveSequence(kernel, nam):
230  return Interface.createSensDetSequence(kernel, str(nam))
231 
232 
233 def _setup(obj):
234  def _adopt(self, action):
235  self.__adopt(action.get())
236  _import_class('Sim', obj)
237  o = getattr(current, obj)
238  setattr(o, '__adopt', getattr(o, 'adopt'))
239  setattr(o, 'adopt', _adopt)
240  setattr(o, 'add', _adopt)
241 
242 
243 def _setup_callback(obj):
244  def _adopt(self, action):
245  self.__adopt(action.get(), action.callback())
246  _import_class('Sim', obj)
247  o = getattr(current, obj)
248  setattr(o, '__adopt', getattr(o, 'add'))
249  setattr(o, 'add', _adopt)
250 
251 
252 _setup_callback('Geant4ActionPhase')
253 _setup('Geant4RunActionSequence')
254 _setup('Geant4EventActionSequence')
255 _setup('Geant4GeneratorActionSequence')
256 _setup('Geant4TrackingActionSequence')
257 _setup('Geant4SteppingActionSequence')
258 _setup('Geant4StackingActionSequence')
259 _setup('Geant4PhysicsListActionSequence')
260 _setup('Geant4SensDetActionSequence')
261 _setup('Geant4DetectorConstructionSequence')
262 _setup('Geant4UserInitializationSequence')
263 _setup('Geant4Sensitive')
264 _setup('Geant4ParticleHandler')
265 _import_class('Sim', 'Geant4Vertex')
266 _import_class('Sim', 'Geant4Particle')
267 _import_class('Sim', 'Geant4VertexVector')
268 _import_class('Sim', 'Geant4ParticleVector')
269 _import_class('Sim', 'Geant4Action')
270 _import_class('Sim', 'Geant4Filter')
271 _import_class('Sim', 'Geant4RunAction')
272 _import_class('Sim', 'Geant4TrackingAction')
273 _import_class('Sim', 'Geant4StackingAction')
274 _import_class('Sim', 'Geant4PhaseAction')
275 _import_class('Sim', 'Geant4UserParticleHandler')
276 _import_class('Sim', 'Geant4UserInitialization')
277 _import_class('Sim', 'Geant4DetectorConstruction')
278 _import_class('Sim', 'Geant4GeneratorWrapper')
279 _import_class('Sim', 'Geant4Random')
280 _import_class('CLHEP', 'HepRandom')
281 _import_class('CLHEP', 'HepRandomEngine')
282 
283 
284 def _get(self, name):
285  a = Interface.toAction(self)
286  ret = Interface.getProperty(a, name)
287  if ret.status > 0:
288  return ret.data
289  elif hasattr(self.action, name):
290  return getattr(self.action, name)
291  elif hasattr(a, name):
292  return getattr(a, name)
293  msg = 'Geant4Action::GetProperty [Unhandled]: Cannot access property ' + a.name() + '.' + name
294  raise KeyError(msg)
295 
296 
297 def _deUnicode(value):
298  """Turn any unicode literal into str, needed when passing to c++.
299 
300  Recursively transverses dicts, lists, sets, tuples
301 
302  :return: always a str
303  """
304  if isinstance(value, (bool, float, six.integer_types)):
305  value = value
306  elif isinstance(value, six.string_types):
307  value = str(value)
308  elif isinstance(value, (list, set, tuple)):
309  value = [_deUnicode(x) for x in value]
310  elif isinstance(value, dict):
311  tempDict = {}
312  for key, val in value.items():
313  key = _deUnicode(key)
314  val = _deUnicode(val)
315  tempDict[key] = val
316  value = tempDict
317  return str(value)
318 
319 
320 def _set(self, name, value):
321  """This function is called when properties are passed to the c++ objects."""
322  a = Interface.toAction(self)
323  name = _deUnicode(name)
324  value = _deUnicode(value)
325  if Interface.setProperty(a, name, value):
326  return
327  msg = 'Geant4Action::SetProperty [Unhandled]: Cannot set ' + a.name() + '.' + name + ' = ' + value
328  raise KeyError(msg)
329 
330 
331 def _props(obj):
332  _import_class('Sim', obj)
333  cl = getattr(current, obj)
334  cl.__getattr__ = _get
335  cl.__setattr__ = _set
336 
337 
338 _props('FilterHandle')
339 _props('ActionHandle')
340 _props('PhaseActionHandle')
341 _props('RunActionHandle')
342 _props('EventActionHandle')
343 _props('GeneratorActionHandle')
344 _props('PhysicsListHandle')
345 _props('TrackingActionHandle')
346 _props('SteppingActionHandle')
347 _props('StackingActionHandle')
348 _props('DetectorConstructionHandle')
349 _props('SensitiveHandle')
350 _props('UserInitializationHandle')
351 _props('Geant4ParticleHandler')
352 _props('Geant4UserParticleHandler')
353 
354 _props('GeneratorActionSequenceHandle')
355 _props('RunActionSequenceHandle')
356 _props('EventActionSequenceHandle')
357 _props('TrackingActionSequenceHandle')
358 _props('SteppingActionSequenceHandle')
359 _props('StackingActionSequenceHandle')
360 _props('DetectorConstructionSequenceHandle')
361 _props('PhysicsListActionSequenceHandle')
362 _props('SensDetActionSequenceHandle')
363 _props('UserInitializationSequenceHandle')
364 
365 _props('Geant4PhysicsListActionSequence')
366 
367 
368 class Geant4:
369  """
370  Helper object to perform stuff, which occurs very often.
371  I am sick of typing the same over and over again.
372  Hence, I grouped often used python fragments to this small
373  class to re-usage.
374 
375  \author M.Frank
376  \version 1.0
377  """
378 
379  def __init__(self, kernel=None,
380  calo='Geant4CalorimeterAction',
381  tracker='Geant4SimpleTrackerAction'):
382  kernel.UI = "UI"
383  kernel.printProperties()
384  self._kernel = kernel
385  if kernel is None:
386  self._kernel = Kernel()
387  self.description = self._kernel.detectorDescription()
388  self.sensitive_types = {}
389  self.sensitive_types['tracker'] = tracker
390  self.sensitive_types['calorimeter'] = calo
391  self.sensitive_types['escape_counter'] = 'Geant4EscapeCounter'
392 
393  def kernel(self):
394  """
395  Access the worker kernel object.
396 
397  \author M.Frank
398  """
399  return self._kernel.worker()
400 
401  def master(self):
402  """
403  Access the master kernel object.
404 
405  \author M.Frank
406  """
407  return self._kernel
408 
409  def setupUI(self, typ='csh', vis=False, ui=True, macro=None):
410  """
411  Configure the Geant4 command executive
412 
413  \author M.Frank
414  """
415  ui_action = Action(self.master(), "Geant4UIManager/UI")
416  if vis:
417  ui_action.HaveVIS = True
418  else:
419  ui_action.HaveVIS = False
420  if ui:
421  ui_action.HaveUI = True
422  else:
423  ui_action.HaveUI = False
424  ui_action.SessionType = typ
425  if macro:
426  ui_action.SetupUI = macro
427  self.master().registerGlobalAction(ui_action)
428  return ui_action
429 
430  def setupCshUI(self, typ='csh', vis=False, ui=True, macro=None):
431  """
432  Configure the Geant4 command executive with a csh like command prompt
433 
434  \author M.Frank
435  """
436  return self.setupUI(typ='csh', vis=vis, ui=ui, macro=macro)
437 
438  def addUserInitialization(self, worker, worker_args=None, master=None, master_args=None):
439  """
440  Configure Geant4 user initialization for optionasl multi-threading mode
441 
442  \author M.Frank
443  """
444  init_seq = self.master().userInitialization(True)
445  init_action = UserInitialization(self.master(), 'Geant4PythonInitialization/PyG4Init')
446  #
447  if worker:
448  init_action.setWorkerSetup(worker, worker_args)
449  else:
450  raise RuntimeError('Invalid argument for Geant4 worker initialization')
451  #
452  if master:
453  init_action.setMasterSetup(master, master_args)
454  #
455  init_seq.adopt(init_action)
456  return init_seq, init_action
457 
459  seq = self.master().detectorConstruction(True)
460  return seq
461 
462  def addDetectorConstruction(self, name_type,
463  field=None, field_args=None,
464  geometry=None, geometry_args=None,
465  sensitives=None, sensitives_args=None,
466  allow_threads=False):
467  """
468  Configure Geant4 user initialization for optionasl multi-threading mode
469 
470  \author M.Frank
471  """
472  init_seq = self.master().detectorConstruction(True)
473  init_action = DetectorConstruction(self.master(), name_type)
474  #
475  if geometry:
476  init_action.setConstructGeo(geometry, geometry_args)
477  #
478  if field:
479  init_action.setConstructField(field, field_args)
480  #
481  if sensitives:
482  init_action.setConstructSensitives(sensitives, sensitives_args)
483  #
484  init_seq.adopt(init_action)
485  if allow_threads:
486  last_action = DetectorConstruction(self.master(), "Geant4PythonDetectorConstructionLast/LastDetectorAction")
487  init_seq.adopt(last_action)
488 
489  return init_seq, init_action
490 
491  def addPhaseAction(self, phase_name, factory_specification, ui=True, instance=None):
492  """
493  Add a new phase action to an arbitrary step.
494 
495  \author M.Frank
496  """
497  if instance is None:
498  instance = self.kernel()
499  action = PhaseAction(instance, factory_specification)
500  instance.phase(phase_name).add(action)
501  if ui:
502  action.enableUI()
503  return action
504 
505  def addConfig(self, factory_specification):
506  """
507  Add a new phase action to the 'configure' step.
508  Called at the beginning of Geant4Exec::configure.
509  The factory specification is the typical string "<factory_name>/<instance name>".
510  If no instance name is specified it defaults to the factory name.
511 
512  \author M.Frank
513  """
514  return self.addPhaseAction('configure', factory_specification, instance=self.master())
515 
516  def addInit(self, factory_specification):
517  """
518  Add a new phase action to the 'initialize' step.
519  Called at the beginning of Geant4Exec::initialize.
520  The factory specification is the typical string "<factory_name>/<instance name>".
521  If no instance name is specified it defaults to the factory name.
522 
523  \author M.Frank
524  """
525  return self.addPhaseAction('initialize', factory_specification)
526 
527  def addStart(self, factory_specification):
528  """
529  Add a new phase action to the 'start' step.
530  Called at the beginning of Geant4Exec::run.
531  The factory specification is the typical string "<factory_name>/<instance name>".
532  If no instance name is specified it defaults to the factory name.
533 
534  \author M.Frank
535  """
536  return self.addPhaseAction('start', factory_specification)
537 
538  def addStop(self, factory_specification):
539  """
540  Add a new phase action to the 'stop' step.
541  Called at the end of Geant4Exec::run.
542  The factory specification is the typical string "<factory_name>/<instance name>".
543  If no instance name is specified it defaults to the factory name.
544 
545  \author M.Frank
546  """
547  return self.addPhaseAction('stop', factory_specification)
548 
549  def execute(self, num_events=None):
550  """
551  Execute the Geant 4 program with all steps.
552 
553  \author M.Frank
554  """
555  self.kernel().configure()
556  self.kernel().initialize()
557  if num_events:
558  self.kernel().NumEvents = num_events
559  self.kernel().run()
560  self.kernel().terminate()
561  return self
562 
563  def printDetectors(self):
564  logger.info('+++ List of sensitive detectors:')
565  for i in self.description.detectors():
566  o = DetElement(i.second.ptr()) # noqa: F405
567  sd = self.description.sensitiveDetector(str(o.name()))
568  if sd.isValid():
569  typ = sd.type()
570  sdtyp = 'Unknown'
571  if typ in self.sensitive_types:
572  sdtyp = self.sensitive_types[typ]
573  logger.info('+++ %-32s type:%-12s --> Sensitive type: %s', o.name(), typ, sdtyp)
574 
575  def setupDetector(self, name, action, collections=None):
576  # fg: allow the action to be a tuple with parameter dictionary
577  sensitive_type = ""
578  parameterDict = {}
579  if isinstance(action, tuple) or isinstance(action, list):
580  sensitive_type = action[0]
581  parameterDict = action[1]
582  else:
583  sensitive_type = action
584 
585  seq = SensitiveSequence(self.kernel(), 'Geant4SensDetActionSequence/' + name)
586  seq.enableUI()
587  acts = []
588  if collections is None:
589  sd = self.description.sensitiveDetector(str(name))
590  ro = sd.readout()
591  collections = ro.collectionNames()
592  if len(collections) == 0:
593  act = SensitiveAction(self.kernel(), sensitive_type + '/' + name + 'Handler', name)
594  for parameter, value in six.iteritems(parameterDict):
595  setattr(act, parameter, value)
596  acts.append(act)
597 
598  # Work down the collections if present
599  if collections is not None:
600  for coll in collections:
601  params = {}
602  if isinstance(coll, tuple) or isinstance(coll, list):
603  if len(coll) > 2:
604  coll_nam = str(coll[0])
605  sensitive_type = coll[1]
606  params = str(coll[2])
607  elif len(coll) > 1:
608  coll_nam = str(coll[0])
609  sensitive_type = coll[1]
610  else:
611  coll_nam = str(coll[0])
612  else:
613  coll_nam = str(coll)
614  act = SensitiveAction(self.kernel(), sensitive_type + '/' + coll_nam + 'Handler', name)
615  act.CollectionName = coll_nam
616  for parameter, value in six.iteritems(params):
617  setattr(act, parameter, value)
618  acts.append(act)
619 
620  for act in acts:
621  act.enableUI()
622  seq.add(act)
623  if len(acts) > 1:
624  return (seq, acts)
625  return (seq, acts[0])
626 
627  def setupCalorimeter(self, name, type=None, collections=None):
628  self.description.sensitiveDetector(str(name))
629  # sd.setType('calorimeter')
630  if type is None:
631  type = self.sensitive_types['calorimeter']
632  return self.setupDetector(name, type, collections)
633 
634  def setupTracker(self, name, type=None, collections=None):
635  self.description.sensitiveDetector(str(name))
636  # sd.setType('tracker')
637  if type is None:
638  type = self.sensitive_types['tracker']
639  return self.setupDetector(name, type, collections)
640 
641  def _private_setupField(self, field, stepper, equation, prt):
642  import g4units
643  field.stepper = stepper
644  field.equation = equation
645  field.eps_min = 5e-05 * g4units.mm
646  field.eps_max = 0.001 * g4units.mm
647  field.min_chord_step = 0.01 * g4units.mm
648  field.delta_chord = 0.25 * g4units.mm
649  field.delta_intersection = 0.001 * g4units.mm
650  field.delta_one_step = 0.01 * g4units.mm
651  field.largest_step = 1000 * g4units.m
652  if prt:
653  logger.info('+++++> %s %s %s %s ', field.name, '-> stepper = ', str(field.stepper), '')
654  logger.info('+++++> %s %s %s %s ', field.name, '-> equation = ', str(field.equation), '')
655  logger.info('+++++> %s %s %s %s ', field.name, '-> eps_min = ', str(field.eps_min), '[mm]')
656  logger.info('+++++> %s %s %s %s ', field.name, '-> eps_max = ', str(field.eps_max), '[mm]')
657  logger.info('+++++> %s %s %s %s ', field.name, '-> delta_chord = ', str(field.delta_chord), '[mm]')
658  logger.info('+++++> %s %s %s %s ', field.name, '-> min_chord_step = ', str(field.min_chord_step), '[mm]')
659  logger.info('+++++> %s %s %s %s ', field.name, '-> delta_one_step = ', str(field.delta_one_step), '[mm]')
660  logger.info('+++++> %s %s %s %s ', field.name, '-> delta_intersection = ', str(field.delta_intersection), '[mm]')
661  logger.info('+++++> %s %s %s %s ', field.name, '-> largest_step = ', str(field.largest_step), '[mm]')
662  return field
663 
664  def setupTrackingFieldMT(self, name='MagFieldTrackingSetup',
665  stepper='ClassicalRK4', equation='Mag_UsualEqRhs', prt=False):
666  seq, fld = self.addDetectorConstruction("Geant4FieldTrackingConstruction/" + name)
667  self._private_setupField(fld, stepper, equation, prt)
668  return (seq, fld)
669 
670  def setupTrackingField(self, name='MagFieldTrackingSetup',
671  stepper='ClassicalRK4', equation='Mag_UsualEqRhs', prt=False):
672  field = self.addConfig('Geant4FieldTrackingSetupAction/' + name)
673  self._private_setupField(field, stepper, equation, prt)
674  return field
675 
676  def setupPhysics(self, name):
677  phys = self.master().physicsList()
678  phys.extends = name
679  phys.decays = True
680  phys.enableUI()
681  phys.dump()
682  return phys
683 
684  def addPhysics(self, name):
685  phys = self.master().physicsList()
686  opt = PhysicsList(self.master(), name)
687  opt.enableUI()
688  phys.adopt(opt)
689  return opt
690 
691  def setupGun(self, name, particle, energy, isotrop=True,
692  multiplicity=1, position=(0.0, 0.0, 0.0), register=True, **args):
693  gun = GeneratorAction(self.kernel(), "Geant4ParticleGun/" + name, True)
694  for i in args.items():
695  setattr(gun, i[0], i[1])
696  gun.energy = energy
697  gun.particle = particle
698  gun.multiplicity = multiplicity
699  gun.position = position
700  gun.isotrop = isotrop
701  gun.enableUI()
702  if register:
703  self.kernel().generatorAction().add(gun)
704  return gun
705 
706  def setupROOTOutput(self, name, output, mc_truth=True):
707  """
708  Configure ROOT output for the simulated events
709 
710  \author M.Frank
711  """
712  evt_root = EventAction(self.kernel(), 'Geant4Output2Podio/' + name, True)
713  evt_root.HandleMCTruth = mc_truth
714  evt_root.Control = True
715  if not output.endswith('.root'):
716  output = output + '.root'
717  evt_root.Output = output
718  evt_root.enableUI()
719  self.kernel().eventAction().add(evt_root)
720  return evt_root
721 
722  def setupLCIOOutput(self, name, output):
723  """
724  Configure LCIO output for the simulated events
725 
726  \author M.Frank
727  """
728  evt_lcio = EventAction(self.kernel(), 'Geant4Output2LCIO/' + name, True)
729  evt_lcio.Control = True
730  evt_lcio.Output = output
731  evt_lcio.enableUI()
732  self.kernel().eventAction().add(evt_lcio)
733  return evt_lcio
734 
735  def setupEDM4hepOutput(self, name, output):
736  """Configure EDM4hep root output for the simulated events."""
737  evt_edm4hep = EventAction(self.kernel(), 'Geant4Output2EDM4hep/' + name, True)
738  evt_edm4hep.Control = True
739  evt_edm4hep.Output = output
740  evt_edm4hep.enableUI()
741  self.kernel().eventAction().add(evt_edm4hep)
742  return evt_edm4hep
743 
744  def buildInputStage(self, generator_input_modules, output_level=None, have_mctruth=True):
745  """
746  Generic build of the input stage with multiple input modules.
747 
748  Actions executed are:
749  1) Register Generation initialization action
750  2) Append all modules to build the complete input record
751  These modules are readers/particle sources, boosters and/or smearing actions.
752  3) Merge all existing interaction records
753  4) Add the MC truth handler
754 
755  \author M.Frank
756  """
757  ga = self.kernel().generatorAction()
758  # Register Generation initialization action
759  gen = GeneratorAction(self.kernel(), "Geant4GeneratorActionInit/GenerationInit")
760  if output_level is not None:
761  gen.OutputLevel = output_level
762  ga.adopt(gen)
763 
764  # Now append all modules to build the complete input record
765  # These modules are readers/particle sources, boosters and/or smearing actions
766  for gen in generator_input_modules:
767  gen.enableUI()
768  if output_level is not None:
769  gen.OutputLevel = output_level
770  ga.adopt(gen)
771 
772  # Merge all existing interaction records
773  gen = GeneratorAction(self.kernel(), "Geant4InteractionMerger/InteractionMerger")
774  gen.enableUI()
775  if output_level is not None:
776  gen.OutputLevel = output_level
777  ga.adopt(gen)
778 
779  # Finally generate Geant4 primaries
780  if have_mctruth:
781  gen = GeneratorAction(self.kernel(), "Geant4PrimaryHandler/PrimaryHandler")
782  gen.RejectPDGs = "{1,2,3,4,5,6,21,23,24}"
783  gen.enableUI()
784  if output_level is not None:
785  gen.OutputLevel = output_level
786  ga.adopt(gen)
787  # Puuuhh! All done.
788  return self
789 
790  def run(self):
791  """
792  Execute the main Geant4 action
793  \author M.Frank
794  """
795  from ROOT import PyDDG4
796  PyDDG4.run(self.master().get())
797  return self
798 
799 
800 Simple = Geant4
def addStart(self, factory_specification)
Definition: DDG4.py:527
def Action(kernel, nam, shared=False)
Definition: DDG4.py:181
def kernel(self)
Definition: DDG4.py:393
def buildInputStage(self, generator_input_modules, output_level=None, have_mctruth=True)
Definition: DDG4.py:744
def addPhysics(self, name)
Definition: DDG4.py:684
def setupCalorimeter(self, name, type=None, collections=None)
Definition: DDG4.py:627
def TrackingAction(kernel, nam, shared=False)
Definition: DDG4.py:205
def Filter(kernel, nam, shared=False)
Definition: DDG4.py:185
def setupLCIOOutput(self, name, output)
Definition: DDG4.py:722
def loadDDG4()
Definition: DDG4.py:19
def RunAction(kernel, nam, shared=False)
Definition: DDG4.py:193
def _private_setupField(self, field, stepper, equation, prt)
Definition: DDG4.py:641
def setupCshUI(self, typ='csh', vis=False, ui=True, macro=None)
Definition: DDG4.py:430
def __init__(self, kernel=None, calo='Geant4CalorimeterAction', tracker='Geant4SimpleTrackerAction')
Definition: DDG4.py:379
Kernel
Definition: DDG4.py:67
def setupUI(self, typ='csh', vis=False, ui=True, macro=None)
Definition: DDG4.py:409
def PhysicsList(kernel, nam)
Definition: DDG4.py:221
def addInit(self, factory_specification)
Definition: DDG4.py:516
def UserInitialization(kernel, nam)
Definition: DDG4.py:225
def addConfig(self, factory_specification)
Definition: DDG4.py:505
def setupDetector(self, name, action, collections=None)
Definition: DDG4.py:575
sensitive_types
Definition: DDG4.py:386
def detectorConstruction(self)
Definition: DDG4.py:458
def SensitiveSequence(kernel, nam)
Definition: DDG4.py:229
def GeneratorAction(kernel, nam, shared=False)
Definition: DDG4.py:201
def run(self)
Definition: DDG4.py:790
def setupTrackingFieldMT(self, name='MagFieldTrackingSetup', stepper='ClassicalRK4', equation='Mag_UsualEqRhs', prt=False)
Definition: DDG4.py:664
def setupPhysics(self, name)
Definition: DDG4.py:676
def addDetectorConstruction(self, name_type, field=None, field_args=None, geometry=None, geometry_args=None, sensitives=None, sensitives_args=None, allow_threads=False)
Definition: DDG4.py:462
def setupEDM4hepOutput(self, name, output)
Definition: DDG4.py:735
def SteppingAction(kernel, nam, shared=False)
Definition: DDG4.py:209
def printDetectors(self)
Definition: DDG4.py:563
def setupGun(self, name, particle, energy, isotrop=True, multiplicity=1, position=(0.0, 0.0, 0.0), register=True, **args)
Definition: DDG4.py:691
def execute(self, num_events=None)
Definition: DDG4.py:549
def addStop(self, factory_specification)
Definition: DDG4.py:538
def SensitiveAction(kernel, nam, det, shared=False)
Definition: DDG4.py:177
def PhaseAction(kernel, nam, shared=False)
Definition: DDG4.py:189
def setupTracker(self, name, type=None, collections=None)
Definition: DDG4.py:634
Namespace for the Geant4 based simulation part of the AIDA detector description toolkit.
def addUserInitialization(self, worker, worker_args=None, master=None, master_args=None)
Definition: DDG4.py:438
def setupTrackingField(self, name='MagFieldTrackingSetup', stepper='ClassicalRK4', equation='Mag_UsualEqRhs', prt=False)
Definition: DDG4.py:670
def DetectorConstruction(kernel, nam)
Definition: DDG4.py:217
def addPhaseAction(self, phase_name, factory_specification, ui=True, instance=None)
Definition: DDG4.py:491
def importConstants(description, namespace=None, debug=False)
Definition: DDG4.py:79
def master(self)
Definition: DDG4.py:401
description
Definition: DDG4.py:385
def EventAction(kernel, nam, shared=False)
Definition: DDG4.py:197
def StackingAction(kernel, nam, shared=False)
Definition: DDG4.py:213
def setupROOTOutput(self, name, output, mc_truth=True)
Definition: DDG4.py:706