11 from __future__
import absolute_import, unicode_literals
13 from dd4hep_base
import *
16 logger = logging.getLogger(__name__)
21 from ROOT
import gSystem
25 if(
'libglapi' not in gSystem.GetLibraries()):
26 orgLevel = ROOT.gErrorIgnoreLevel
27 ROOT.gErrorIgnoreLevel = 6000
28 gSystem.Load(
"libglapi")
29 ROOT.gErrorIgnoreLevel = orgLevel
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)
38 result = gSystem.Load(
"libDDG4Plugins")
40 raise Exception(
'DDG4.py: Failed to load the DDG4 library libDDG4Plugins: ' + gSystem.GetErrorStr())
41 from ROOT
import dd4hep
as module
46 current = __import__(__name__)
49 def _import_class(ns, nam):
50 scope = getattr(current, ns)
51 setattr(current, nam, getattr(scope, nam))
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 *
'-')
63 from ROOT
import CLHEP
as CLHEP
67 Kernel = Sim.KernelHandle
68 Interface = Sim.Geant4ActionCreation
69 Detector = Core.Detector
72 def _constant(self, name):
73 return self.constantAsString(name)
76 Detector.globalVal = _constant
81 Import the Detector constants into the DDG4 namespace
84 if namespace
is not None and not hasattr(current, namespace):
86 m = imp.new_module(
'DDG4.' + namespace)
87 setattr(current, namespace, m)
89 evaluator = dd4hep.g4Evaluator()
94 for c
in description.constants():
95 if c.second.dataType ==
'string':
96 strings[c.first] = c.second.GetTitle()
98 todo[c.first] = c.second.GetTitle().replace(
'(int)',
'')
99 while len(todo)
and 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 *
'=')
112 for k, v
in list(todo.items()):
113 if not hasattr(ns, k):
114 val = evaluator.evaluate(v)
115 status = evaluator.status()
117 evaluator.setVariable(k, val)
120 logger.info(
'Imported global value: "' + k +
'" = "' + str(val) +
'" into namespace' + ns.__name__)
124 logger.info(
'+++ Imported %d global values to namespace:%s', num, ns.__name__,)
127 def _registerGlobalAction(self, action):
128 self.get().registerGlobalAction(Interface.toAction(action))
131 def _registerGlobalFilter(self, filter):
132 self.get().registerGlobalFilter(Interface.toAction(filter))
135 def _getKernelProperty(self, name):
136 ret = Interface.getPropertyKernel(self.get(), name)
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
147 def _setKernelProperty(self, name, value):
148 if Interface.setPropertyKernel(self.get(), str(name), str(value)):
150 msg =
'Geant4Kernel::SetProperty [Unhandled]: Cannot set Kernel.' + name +
' = ' + str(value)
154 def _kernel_phase(self, name):
155 return self.addSimplePhase(str(name),
False)
158 def _kernel_worker(self):
159 return Kernel(self.get().createWorker())
162 def _kernel_terminate(self):
163 return self.get().terminate()
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
174 ActionHandle = Sim.ActionHandle
178 return Interface.createSensitive(kernel, str(nam), str(det), shared)
182 return Interface.createAction(kernel, str(nam), shared)
186 return Interface.createFilter(kernel, str(nam), shared)
190 return Interface.createPhaseAction(kernel, str(nam), shared)
194 return Interface.createRunAction(kernel, str(nam), shared)
198 return Interface.createEventAction(kernel, str(nam), shared)
202 return Interface.createGeneratorAction(kernel, str(nam), shared)
206 return Interface.createTrackingAction(kernel, str(nam), shared)
210 return Interface.createSteppingAction(kernel, str(nam), shared)
214 return Interface.createStackingAction(kernel, str(nam), shared)
218 return Interface.createDetectorConstruction(kernel, str(nam))
222 return Interface.createPhysicsList(kernel, str(nam))
226 return Interface.createUserInitialization(kernel, str(nam))
230 return Interface.createSensDetSequence(kernel, str(nam))
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)
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)
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')
284 def _get(self, name):
285 a = Interface.toAction(self)
286 ret = Interface.getProperty(a, name)
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
297 def _deUnicode(value):
298 """Turn any unicode literal into str, needed when passing to c++.
300 Recursively transverses dicts, lists, sets, tuples
302 :return: always a str
304 if isinstance(value, (bool, float, six.integer_types)):
306 elif isinstance(value, six.string_types):
308 elif isinstance(value, (list, set, tuple)):
309 value = [_deUnicode(x)
for x
in value]
310 elif isinstance(value, dict):
312 for key, val
in value.items():
313 key = _deUnicode(key)
314 val = _deUnicode(val)
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):
327 msg =
'Geant4Action::SetProperty [Unhandled]: Cannot set ' + a.name() +
'.' + name +
' = ' + value
332 _import_class(
'Sim', obj)
333 cl = getattr(current, obj)
334 cl.__getattr__ = _get
335 cl.__setattr__ = _set
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')
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')
365 _props(
'Geant4PhysicsListActionSequence')
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
380 calo='Geant4CalorimeterAction',
381 tracker='Geant4SimpleTrackerAction'):
383 kernel.printProperties()
395 Access the worker kernel object.
403 Access the master kernel object.
409 def setupUI(self, typ='csh', vis=False, ui=True, macro=None):
411 Configure the Geant4 command executive
417 ui_action.HaveVIS =
True
419 ui_action.HaveVIS =
False
421 ui_action.HaveUI =
True
423 ui_action.HaveUI =
False
424 ui_action.SessionType = typ
426 ui_action.SetupUI = macro
427 self.
master().registerGlobalAction(ui_action)
430 def setupCshUI(self, typ='csh', vis=False, ui=True, macro=None):
432 Configure the Geant4 command executive with a csh like command prompt
436 return self.
setupUI(typ=
'csh', vis=vis, ui=ui, macro=macro)
440 Configure Geant4 user initialization for optionasl multi-threading mode
444 init_seq = self.
master().userInitialization(
True)
448 init_action.setWorkerSetup(worker, worker_args)
450 raise RuntimeError(
'Invalid argument for Geant4 worker initialization')
453 init_action.setMasterSetup(master, master_args)
455 init_seq.adopt(init_action)
456 return init_seq, init_action
463 field=None, field_args=None,
464 geometry=None, geometry_args=None,
465 sensitives=None, sensitives_args=None,
466 allow_threads=False):
468 Configure Geant4 user initialization for optionasl multi-threading mode
476 init_action.setConstructGeo(geometry, geometry_args)
479 init_action.setConstructField(field, field_args)
482 init_action.setConstructSensitives(sensitives, sensitives_args)
484 init_seq.adopt(init_action)
487 init_seq.adopt(last_action)
489 return init_seq, init_action
491 def addPhaseAction(self, phase_name, factory_specification, ui=True, instance=None):
493 Add a new phase action to an arbitrary step.
499 action =
PhaseAction(instance, factory_specification)
500 instance.phase(phase_name).add(action)
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.
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.
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.
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.
551 Execute the Geant 4 program with all steps.
556 self.
kernel().initialize()
558 self.
kernel().NumEvents = num_events
564 logger.info(
'+++ List of sensitive detectors:')
566 o = DetElement(i.second.ptr())
567 sd = self.
description.sensitiveDetector(str(o.name()))
573 logger.info(
'+++ %-32s type:%-12s --> Sensitive type: %s', o.name(), typ, sdtyp)
579 if isinstance(action, tuple)
or isinstance(action, list):
580 sensitive_type = action[0]
581 parameterDict = action[1]
583 sensitive_type = action
588 if collections
is None:
591 collections = ro.collectionNames()
592 if len(collections) == 0:
594 for parameter, value
in six.iteritems(parameterDict):
595 setattr(act, parameter, value)
599 if collections
is not None:
600 for coll
in collections:
602 if isinstance(coll, tuple)
or isinstance(coll, list):
604 coll_nam = str(coll[0])
605 sensitive_type = coll[1]
606 params = str(coll[2])
608 coll_nam = str(coll[0])
609 sensitive_type = coll[1]
611 coll_nam = str(coll[0])
615 act.CollectionName = coll_nam
616 for parameter, value
in six.iteritems(params):
617 setattr(act, parameter, value)
625 return (seq, acts[0])
641 def _private_setupField(self, field, stepper, equation, prt):
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
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]')
665 stepper='ClassicalRK4', equation='Mag_UsualEqRhs', prt=False):
671 stepper='ClassicalRK4', equation='Mag_UsualEqRhs', prt=False):
672 field = self.
addConfig(
'Geant4FieldTrackingSetupAction/' + name)
677 phys = self.
master().physicsList()
685 phys = self.
master().physicsList()
691 def setupGun(self, name, particle, energy, isotrop=True,
692 multiplicity=1, position=(0.0, 0.0, 0.0), register=
True, **args):
694 for i
in args.items():
695 setattr(gun, i[0], i[1])
697 gun.particle = particle
698 gun.multiplicity = multiplicity
699 gun.position = position
700 gun.isotrop = isotrop
703 self.
kernel().generatorAction().add(gun)
708 Configure ROOT output for the simulated events
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
719 self.
kernel().eventAction().add(evt_root)
724 Configure LCIO output for the simulated events
729 evt_lcio.Control =
True
730 evt_lcio.Output = output
732 self.
kernel().eventAction().add(evt_lcio)
736 """Configure EDM4hep root output for the simulated events."""
738 evt_edm4hep.Control =
True
739 evt_edm4hep.Output = output
740 evt_edm4hep.enableUI()
741 self.
kernel().eventAction().add(evt_edm4hep)
744 def buildInputStage(self, generator_input_modules, output_level=None, have_mctruth=True):
746 Generic build of the input stage with multiple input modules.
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
757 ga = self.
kernel().generatorAction()
760 if output_level
is not None:
761 gen.OutputLevel = output_level
766 for gen
in generator_input_modules:
768 if output_level
is not None:
769 gen.OutputLevel = output_level
775 if output_level
is not None:
776 gen.OutputLevel = output_level
782 gen.RejectPDGs =
"{1,2,3,4,5,6,21,23,24}"
784 if output_level
is not None:
785 gen.OutputLevel = output_level
792 Execute the main Geant4 action
795 from ROOT
import PyDDG4
796 PyDDG4.run(self.
master().get())