File indexing completed on 2025-01-30 09:17:28
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 from __future__ import absolute_import, unicode_literals
0012 import logging
0013 import signal
0014 import cppyy
0015 from dd4hep_base import *
0016
0017 logger = logging.getLogger(__name__)
0018
0019
0020 def loadDDG4():
0021 import ROOT
0022 from ROOT import gSystem
0023
0024
0025
0026 if 'libglapi' not in gSystem.GetLibraries():
0027 orgLevel = ROOT.gErrorIgnoreLevel
0028 ROOT.gErrorIgnoreLevel = 6000
0029 gSystem.Load("libglapi")
0030 ROOT.gErrorIgnoreLevel = orgLevel
0031
0032 import platform
0033 import os
0034 if platform.system() == "Darwin":
0035 gSystem.SetDynamicPath(os.environ['DD4HEP_LIBRARY_PATH'])
0036 os.environ['DYLD_LIBRARY_PATH'] = os.pathsep.join([os.environ['DD4HEP_LIBRARY_PATH'],
0037 os.environ.get('DYLD_LIBRARY_PATH', '')]).strip(os.pathsep)
0038
0039 result = gSystem.Load("libDDG4Plugins")
0040 if result < 0:
0041 raise Exception('DDG4.py: Failed to load the DDG4 library libDDG4Plugins: ' + gSystem.GetErrorStr())
0042 from ROOT import dd4hep as module
0043 return module
0044
0045
0046
0047 current = __import__(__name__)
0048
0049
0050 def _import_class(ns, nam):
0051 scope = getattr(current, ns)
0052 setattr(current, nam, getattr(scope, nam))
0053
0054
0055 try:
0056 dd4hep = loadDDG4()
0057 except Exception as X:
0058 logger.error('+--%-100s--+', 100 * '-')
0059 logger.error('| %-100s |', 'Failed to load DDG4 library:')
0060 logger.error('| %-100s |', str(X))
0061 logger.error('+--%-100s--+', 100 * '-')
0062 exit(1)
0063
0064 from ROOT import CLHEP as CLHEP
0065 Core = dd4hep
0066 Sim = dd4hep.sim
0067 Simulation = dd4hep.sim
0068 Kernel = Sim.KernelHandle
0069 Interface = Sim.Geant4ActionCreation
0070 Detector = Core.Detector
0071
0072
0073 def _constant(self, name):
0074 return self.constantAsString(name)
0075
0076
0077 Detector.globalVal = _constant
0078
0079
0080 def importConstants(description, namespace=None, debug=False):
0081 """
0082 Import the Detector constants into the DDG4 namespace
0083 """
0084 ns = current
0085 if namespace is not None and not hasattr(current, namespace):
0086 import types
0087 m = types.ModuleType('DDG4.' + namespace)
0088 setattr(current, namespace, m)
0089 ns = m
0090 evaluator = dd4hep.g4Evaluator()
0091 cnt = 0
0092 num = 0
0093 todo = {}
0094 strings = {}
0095 for c in description.constants():
0096 if c.second.dataType == 'string':
0097 strings[str(c.first)] = c.second.GetTitle()
0098 else:
0099 todo[str(c.first)] = c.second.GetTitle().replace('(int)', '')
0100 while len(todo) and cnt < 100:
0101 cnt = cnt + 1
0102 if cnt == 100:
0103 logger.error('%s %d out of %d %s "%s": [%s]\n+++ %s',
0104 '+++ FAILED to import',
0105 len(todo), len(todo) + num,
0106 'global values into namespace',
0107 ns.__name__, 'Try to continue anyway', 100 * '=')
0108 for k, v in todo.items():
0109 if not hasattr(ns, k):
0110 logger.error('+++ FAILED to import: "' + k + '" = "' + str(v) + '"')
0111 logger.info('+++ %s', 100 * '=')
0112
0113 for k, v in list(todo.items()):
0114 if not hasattr(ns, k):
0115 val = evaluator.evaluate(str(v))
0116 if val.first == 0:
0117 evaluator.setVariable(str(k), val.second)
0118 setattr(ns, k, val.second)
0119 if debug:
0120 logger.info('Imported global value: "' + k + '" = "' + str(val.second) + '" into namespace' + ns.__name__)
0121 del todo[k]
0122 num = num + 1
0123 if cnt < 100:
0124 logger.info('+++ Imported %d global values to namespace:%s', num, ns.__name__,)
0125
0126
0127 def _registerGlobalAction(self, action):
0128 self.get().registerGlobalAction(Interface.toAction(action))
0129
0130
0131 def _registerGlobalFilter(self, filter):
0132 self.get().registerGlobalFilter(Interface.toAction(filter))
0133
0134
0135 def _evalProperty(data):
0136 """
0137 Function necessary to extract real strings from the property value.
0138 Strings may be embraced by quotes: '<value>', or could be cppyy.gbl.std.string with extra "b''"
0139 """
0140 try:
0141 if isinstance(data, (cppyy.gbl.std.string, )):
0142 return _evalProperty(data.decode('utf-8'))
0143 if isinstance(data, str):
0144 import ast
0145 return ast.literal_eval(data)
0146 except ValueError:
0147 pass
0148 except TypeError:
0149 pass
0150 finally:
0151 pass
0152 return data
0153
0154
0155 def _getKernelProperty(self, name):
0156 ret = Interface.getPropertyKernel(self.get(), name)
0157 if ret.status > 0:
0158 return _evalProperty(ret.data)
0159 elif hasattr(self.get(), name):
0160 return _evalProperty(getattr(self.get(), name))
0161 elif hasattr(self, name):
0162 return _evalProperty(getattr(self, name))
0163 msg = 'Geant4Kernel::GetProperty [Unhandled]: Cannot access Kernel.' + name
0164 raise KeyError(msg)
0165
0166
0167 def _setKernelProperty(self, name, value):
0168 if Interface.setPropertyKernel(self.get(), str(name), str(value)):
0169 return
0170 msg = 'Geant4Kernel::SetProperty [Unhandled]: Cannot set Kernel.' + name + ' = ' + str(value)
0171 raise KeyError(msg)
0172
0173
0174 def _kernel_phase(self, name):
0175 return self.addSimplePhase(str(name), False)
0176
0177
0178 def _kernel_worker(self):
0179 return Kernel(self.get().createWorker())
0180
0181
0182 def _kernel_terminate(self):
0183 return self.get().terminate()
0184
0185
0186 Kernel.phase = _kernel_phase
0187 Kernel.registerGlobalAction = _registerGlobalAction
0188 Kernel.registerGlobalFilter = _registerGlobalFilter
0189 Kernel.createWorker = _kernel_worker
0190 Kernel.__getattr__ = _getKernelProperty
0191 Kernel.__setattr__ = _setKernelProperty
0192 Kernel.terminate = _kernel_terminate
0193
0194 ActionHandle = Sim.ActionHandle
0195
0196
0197 def SensitiveAction(kernel, nam, det, shared=False):
0198 return Interface.createSensitive(kernel, str(nam), str(det), shared)
0199
0200
0201 def Action(kernel, nam, shared=False):
0202 return Interface.createAction(kernel, str(nam), shared)
0203
0204
0205 def Filter(kernel, nam, shared=False):
0206 return Interface.createFilter(kernel, str(nam), shared)
0207
0208
0209 def PhaseAction(kernel, nam, shared=False):
0210 return Interface.createPhaseAction(kernel, str(nam), shared)
0211
0212
0213 def RunAction(kernel, nam, shared=False):
0214 return Interface.createRunAction(kernel, str(nam), shared)
0215
0216
0217 def EventAction(kernel, nam, shared=False):
0218 return Interface.createEventAction(kernel, str(nam), shared)
0219
0220
0221 def GeneratorAction(kernel, nam, shared=False):
0222 return Interface.createGeneratorAction(kernel, str(nam), shared)
0223
0224
0225 def TrackingAction(kernel, nam, shared=False):
0226 return Interface.createTrackingAction(kernel, str(nam), shared)
0227
0228
0229 def SteppingAction(kernel, nam, shared=False):
0230 return Interface.createSteppingAction(kernel, str(nam), shared)
0231
0232
0233 def StackingAction(kernel, nam, shared=False):
0234 return Interface.createStackingAction(kernel, str(nam), shared)
0235
0236
0237 def DetectorConstruction(kernel, nam):
0238 return Interface.createDetectorConstruction(kernel, str(nam))
0239
0240
0241 def PhysicsList(kernel, nam):
0242 return Interface.createPhysicsList(kernel, str(nam))
0243
0244
0245 def UserInitialization(kernel, nam):
0246 return Interface.createUserInitialization(kernel, str(nam))
0247
0248
0249 def SensitiveSequence(kernel, nam):
0250 return Interface.createSensDetSequence(kernel, str(nam))
0251
0252
0253 def _setup(obj):
0254 def _adopt(self, action):
0255 self.__adopt(action.get())
0256 _import_class('Sim', obj)
0257 o = getattr(current, obj)
0258 o.__adopt = o.adopt
0259 o.adopt = _adopt
0260 o.add = _adopt
0261
0262
0263 def _setup_callback(obj):
0264 def _adopt(self, action):
0265 self.__adopt(action.get(), action.callback())
0266 _import_class('Sim', obj)
0267 o = getattr(current, obj)
0268 o.__adopt = o.add
0269 o.add = _adopt
0270
0271
0272 _setup_callback('Geant4ActionPhase')
0273 _setup('Geant4RunActionSequence')
0274 _setup('Geant4EventActionSequence')
0275 _setup('Geant4GeneratorActionSequence')
0276 _setup('Geant4TrackingActionSequence')
0277 _setup('Geant4SteppingActionSequence')
0278 _setup('Geant4StackingActionSequence')
0279 _setup('Geant4PhysicsListActionSequence')
0280 _setup('Geant4SensDetActionSequence')
0281 _setup('Geant4DetectorConstructionSequence')
0282 _setup('Geant4UserInitializationSequence')
0283 _setup('Geant4Sensitive')
0284 _setup('Geant4ParticleHandler')
0285 _import_class('Sim', 'Geant4Vertex')
0286 _import_class('Sim', 'Geant4Particle')
0287 _import_class('Sim', 'Geant4VertexVector')
0288 _import_class('Sim', 'Geant4ParticleVector')
0289 _import_class('Sim', 'Geant4Action')
0290 _import_class('Sim', 'Geant4Filter')
0291 _import_class('Sim', 'Geant4RunAction')
0292 _import_class('Sim', 'Geant4TrackingAction')
0293 _import_class('Sim', 'Geant4StackingAction')
0294 _import_class('Sim', 'Geant4PhaseAction')
0295 _import_class('Sim', 'Geant4UserParticleHandler')
0296 _import_class('Sim', 'Geant4UserInitialization')
0297 _import_class('Sim', 'Geant4DetectorConstruction')
0298 _import_class('Sim', 'Geant4GeneratorWrapper')
0299 _import_class('Sim', 'Geant4Random')
0300 _import_class('CLHEP', 'HepRandom')
0301 _import_class('CLHEP', 'HepRandomEngine')
0302
0303
0304 def _get(self, name):
0305 a = Interface.toAction(self)
0306 ret = Interface.getProperty(a, name)
0307 if ret.status > 0:
0308 return _evalProperty(ret.data)
0309 elif hasattr(self.action, name):
0310 return _evalProperty(getattr(self.action, name))
0311 elif hasattr(a, name):
0312 return _evalProperty(getattr(a, name))
0313 msg = 'Geant4Action::GetProperty [Unhandled]: Cannot access property ' + a.name() + '.' + name
0314 raise KeyError(msg)
0315
0316
0317 def _set(self, name, value):
0318 """This function is called when properties are passed to the c++ objects."""
0319 from dd4hep_base import unicode_2_string
0320 a = Interface.toAction(self)
0321 name = unicode_2_string(name)
0322 value = unicode_2_string(value)
0323 if Interface.setProperty(a, name, value):
0324 return
0325 msg = 'Geant4Action::SetProperty [Unhandled]: Cannot set ' + a.name() + '.' + name + ' = ' + value
0326 raise KeyError(msg)
0327
0328
0329 def _props(obj):
0330 _import_class('Sim', obj)
0331 cl = getattr(current, obj)
0332 cl.__getattr__ = _get
0333 cl.__setattr__ = _set
0334
0335
0336 _props('FilterHandle')
0337 _props('ActionHandle')
0338 _props('PhaseActionHandle')
0339 _props('RunActionHandle')
0340 _props('EventActionHandle')
0341 _props('GeneratorActionHandle')
0342 _props('PhysicsListHandle')
0343 _props('TrackingActionHandle')
0344 _props('SteppingActionHandle')
0345 _props('StackingActionHandle')
0346 _props('DetectorConstructionHandle')
0347 _props('SensitiveHandle')
0348 _props('UserInitializationHandle')
0349 _props('Geant4ParticleHandler')
0350 _props('Geant4UserParticleHandler')
0351
0352 _props('GeneratorActionSequenceHandle')
0353 _props('RunActionSequenceHandle')
0354 _props('EventActionSequenceHandle')
0355 _props('TrackingActionSequenceHandle')
0356 _props('SteppingActionSequenceHandle')
0357 _props('StackingActionSequenceHandle')
0358 _props('DetectorConstructionSequenceHandle')
0359 _props('PhysicsListActionSequenceHandle')
0360 _props('SensDetActionSequenceHandle')
0361 _props('UserInitializationSequenceHandle')
0362
0363 _props('Geant4PhysicsListActionSequence')
0364
0365
0366
0367
0368
0369
0370
0371 class Geant4:
0372 """
0373 Helper object to perform stuff, which occurs very often.
0374 I am sick of typing the same over and over again.
0375 Hence, I grouped often used python fragments to this small
0376 class to re-usage.
0377
0378 \author M.Frank
0379 \version 1.0
0380 """
0381
0382 def __init__(self, kernel=None,
0383 calo='Geant4CalorimeterAction',
0384 tracker='Geant4SimpleTrackerAction'):
0385 kernel.UI = "UI"
0386 kernel.printProperties()
0387 self._kernel = kernel
0388 if kernel is None:
0389 self._kernel = Kernel()
0390 self.description = self._kernel.detectorDescription()
0391 self.sensitive_types = {}
0392 self.sensitive_types['tracker'] = tracker
0393 self.sensitive_types['calorimeter'] = calo
0394 self.sensitive_types['escape_counter'] = 'Geant4EscapeCounter'
0395
0396 def kernel(self):
0397 """
0398 Access the worker kernel object.
0399
0400 \author M.Frank
0401 """
0402 return self._kernel.worker()
0403
0404 def master(self):
0405 """
0406 Access the master kernel object.
0407
0408 \author M.Frank
0409 """
0410 return self._kernel
0411
0412 def setupUI(self, typ='csh', vis=False, ui=True, macro=None):
0413 """
0414 Configure the Geant4 command executive
0415
0416 \author M.Frank
0417 """
0418 ui_action = Action(self.master(), "Geant4UIManager/UI")
0419 if vis:
0420 ui_action.HaveVIS = True
0421 else:
0422 ui_action.HaveVIS = False
0423 if ui:
0424 ui_action.HaveUI = True
0425 else:
0426 ui_action.HaveUI = False
0427 ui_action.SessionType = typ
0428 if macro:
0429 ui_action.SetupUI = macro
0430 self.master().registerGlobalAction(ui_action)
0431 return ui_action
0432
0433 def setupCshUI(self, typ='csh', vis=False, ui=True, macro=None):
0434 """
0435 Configure the Geant4 command executive with a csh like command prompt
0436
0437 \author M.Frank
0438 """
0439 return self.setupUI(typ='csh', vis=vis, ui=ui, macro=macro)
0440
0441 def ui(self):
0442 """
0443 Access UI manager action from the kernel object
0444
0445 \author M.Frank
0446 """
0447
0448 ui_name = self.master().UI
0449 return self.master().globalAction(ui_name)
0450
0451 def registerInterruptHandler(self, signum=signal.SIGINT):
0452 """
0453 Enable interrupt handling: smooth handling of CTRL-C
0454 - Finish processing of the current event(s)
0455 - Drain the event loop
0456 - Properly finalize the job
0457
0458 \author M.Frank
0459 """
0460 return self.master().registerInterruptHandler(signum)
0461
0462 def addUserInitialization(self, worker, worker_args=None, master=None, master_args=None):
0463 """
0464 Configure Geant4 user initialization for optionasl multi-threading mode
0465
0466 \author M.Frank
0467 """
0468 init_seq = self.master().userInitialization(True)
0469 init_action = UserInitialization(self.master(), 'Geant4PythonInitialization/PyG4Init')
0470
0471 if worker:
0472 init_action.setWorkerSetup(worker, worker_args)
0473 else:
0474 raise RuntimeError('Invalid argument for Geant4 worker initialization')
0475
0476 if master:
0477 init_action.setMasterSetup(master, master_args)
0478
0479 init_seq.adopt(init_action)
0480 return init_seq, init_action
0481
0482 def detectorConstruction(self):
0483 seq = self.master().detectorConstruction(True)
0484 return seq
0485
0486 def addDetectorConstruction(self, name_type,
0487 field=None, field_args=None,
0488 geometry=None, geometry_args=None,
0489 sensitives=None, sensitives_args=None,
0490 allow_threads=False):
0491 """
0492 Configure Geant4 user initialization for optional multi-threading mode
0493
0494 \author M.Frank
0495 """
0496 init_seq = self.master().detectorConstruction(True)
0497 init_action = DetectorConstruction(self.master(), name_type)
0498
0499 if geometry:
0500 init_action.setConstructGeo(geometry, geometry_args)
0501
0502 if field:
0503 init_action.setConstructField(field, field_args)
0504
0505 if sensitives:
0506 init_action.setConstructSensitives(sensitives, sensitives_args)
0507
0508 init_seq.adopt(init_action)
0509 if allow_threads:
0510 last_action = DetectorConstruction(self.master(), "Geant4PythonDetectorConstructionLast/LastDetectorAction")
0511 init_seq.adopt(last_action)
0512
0513 return init_seq, init_action
0514
0515 def addPhaseAction(self, phase_name, factory_specification, ui=True, instance=None):
0516 """
0517 Add a new phase action to an arbitrary step.
0518
0519 \author M.Frank
0520 """
0521 if instance is None:
0522 instance = self.kernel()
0523 action = PhaseAction(instance, factory_specification)
0524 instance.phase(phase_name).add(action)
0525 if ui:
0526 action.enableUI()
0527 return action
0528
0529 def addConfig(self, factory_specification):
0530 """
0531 Add a new phase action to the 'configure' step.
0532 Called at the beginning of Geant4Exec::configure.
0533 The factory specification is the typical string "<factory_name>/<instance name>".
0534 If no instance name is specified it defaults to the factory name.
0535
0536 \author M.Frank
0537 """
0538 return self.addPhaseAction('configure', factory_specification, instance=self.master())
0539
0540 def addInit(self, factory_specification):
0541 """
0542 Add a new phase action to the 'initialize' step.
0543 Called at the beginning of Geant4Exec::initialize.
0544 The factory specification is the typical string "<factory_name>/<instance name>".
0545 If no instance name is specified it defaults to the factory name.
0546
0547 \author M.Frank
0548 """
0549 return self.addPhaseAction('initialize', factory_specification)
0550
0551 def addStart(self, factory_specification):
0552 """
0553 Add a new phase action to the 'start' step.
0554 Called at the beginning of Geant4Exec::run.
0555 The factory specification is the typical string "<factory_name>/<instance name>".
0556 If no instance name is specified it defaults to the factory name.
0557
0558 \author M.Frank
0559 """
0560 return self.addPhaseAction('start', factory_specification)
0561
0562 def addStop(self, factory_specification):
0563 """
0564 Add a new phase action to the 'stop' step.
0565 Called at the end of Geant4Exec::run.
0566 The factory specification is the typical string "<factory_name>/<instance name>".
0567 If no instance name is specified it defaults to the factory name.
0568
0569 \author M.Frank
0570 """
0571 return self.addPhaseAction('stop', factory_specification)
0572
0573 def execute(self, num_events=None):
0574 """
0575 Execute the Geant 4 program with all steps.
0576
0577 \author M.Frank
0578 """
0579 self.kernel().configure()
0580 self.kernel().initialize()
0581 if num_events:
0582 self.kernel().NumEvents = num_events
0583 self.kernel().run()
0584 self.kernel().terminate()
0585 return self
0586
0587 def printDetectors(self):
0588 """
0589 Scan the list of detectors and print detector name and sensitive type
0590
0591 \author M.Frank
0592 """
0593 logger.info('+++ List of sensitive detectors:')
0594 for i in self.description.detectors():
0595 o = DetElement(i.second.ptr())
0596 sd = self.description.sensitiveDetector(str(o.name()))
0597 if sd.isValid():
0598 typ = sd.type()
0599 sdtyp = 'Unknown'
0600 if typ in self.sensitive_types:
0601 sdtyp = self.sensitive_types[typ]
0602 logger.info('+++ %-32s type:%-12s --> Sensitive type: %s', o.name(), typ, sdtyp)
0603
0604 def setupDetectors(self):
0605 """
0606 Scan the list of detectors and assign the proper sensitive actions
0607
0608 \author M.Frank
0609 """
0610 seq = None
0611 actions = []
0612 logger.info('+++ Setting up sensitive detectors:')
0613 for i in self.description.detectors():
0614 o = DetElement(i.second.ptr())
0615 sd = self.description.sensitiveDetector(str(o.name()))
0616 if sd.isValid():
0617 typ = sd.type()
0618 sdtyp = 'Unknown'
0619 if typ in self.sensitive_types:
0620 sdtyp = self.sensitive_types[typ]
0621 seq, act = self.setupDetector(o.name(), sdtyp, collections=None)
0622 logger.info('+++ %-32s type:%-12s --> Sensitive type: %s', o.name(), typ, sdtyp)
0623 actions.append(act)
0624 continue
0625 logger.info('+++ %-32s --> UNKNOWN Sensitive type: %s', o.name(), typ)
0626 return (seq, actions)
0627
0628 def setupDetector(self, name, action, collections=None):
0629 """
0630 Setup single subdetector and assign the proper sensitive action
0631
0632 \author M.Frank
0633 """
0634
0635 sensitive_type = ""
0636 parameterDict = {}
0637 if isinstance(action, tuple) or isinstance(action, list):
0638 sensitive_type = action[0]
0639 parameterDict = action[1]
0640 else:
0641 sensitive_type = action
0642
0643 seq = SensitiveSequence(self.kernel(), 'Geant4SensDetActionSequence/' + name)
0644 seq.enableUI()
0645 acts = []
0646 if collections is None:
0647 sd = self.description.sensitiveDetector(str(name))
0648 ro = sd.readout()
0649 collections = ro.collectionNames()
0650 if len(collections) == 0:
0651 act = SensitiveAction(self.kernel(), sensitive_type + '/' + name + 'Handler', name)
0652 for parameter, value in parameterDict.items():
0653 setattr(act, parameter, value)
0654 acts.append(act)
0655
0656
0657 if collections is not None:
0658 for coll in collections:
0659 params = {}
0660 if isinstance(coll, tuple) or isinstance(coll, list):
0661 if len(coll) > 2:
0662 coll_nam = str(coll[0])
0663 sensitive_type = coll[1]
0664 params = str(coll[2])
0665 elif len(coll) > 1:
0666 coll_nam = str(coll[0])
0667 sensitive_type = coll[1]
0668 else:
0669 coll_nam = str(coll[0])
0670 else:
0671 coll_nam = str(coll)
0672 act = SensitiveAction(self.kernel(), sensitive_type + '/' + coll_nam + 'Handler', name)
0673 act.CollectionName = coll_nam
0674 for parameter, value in params.items():
0675 setattr(act, parameter, value)
0676 acts.append(act)
0677
0678 for act in acts:
0679 act.enableUI()
0680 seq.add(act)
0681 if len(acts) > 1:
0682 return (seq, acts)
0683 return (seq, acts[0])
0684
0685 def setupCalorimeter(self, name, type=None, collections=None):
0686 """
0687 Setup subdetector of type 'calorimeter' and assign the proper sensitive action
0688
0689 \author M.Frank
0690 """
0691 typ = type
0692 self.description.sensitiveDetector(str(name))
0693
0694 if typ is None:
0695 typ = self.sensitive_types['calorimeter']
0696 return self.setupDetector(name, typ, collections)
0697
0698 def setupTracker(self, name, type=None, collections=None):
0699 """
0700 Setup subdetector of type 'tracker' and assign the proper sensitive action
0701
0702 \author M.Frank
0703 """
0704 typ = type
0705 self.description.sensitiveDetector(str(name))
0706
0707 if typ is None:
0708 typ = self.sensitive_types['tracker']
0709 return self.setupDetector(name, typ, collections)
0710
0711 def _private_setupField(self, field, stepper, equation, prt):
0712 import g4units
0713 field.stepper = stepper
0714 field.equation = equation
0715 field.eps_min = 5e-05 * g4units.mm
0716 field.eps_max = 0.001 * g4units.mm
0717 field.min_chord_step = 0.01 * g4units.mm
0718 field.delta_chord = 0.25 * g4units.mm
0719 field.delta_intersection = 0.001 * g4units.mm
0720 field.delta_one_step = 0.01 * g4units.mm
0721 field.largest_step = 1000 * g4units.m
0722 if prt:
0723 logger.info('+++++> %s %s %s %s ', field.name, '-> stepper = ', str(field.stepper), '')
0724 logger.info('+++++> %s %s %s %s ', field.name, '-> equation = ', str(field.equation), '')
0725 logger.info('+++++> %s %s %s %s ', field.name, '-> eps_min = ', str(field.eps_min), '[mm]')
0726 logger.info('+++++> %s %s %s %s ', field.name, '-> eps_max = ', str(field.eps_max), '[mm]')
0727 logger.info('+++++> %s %s %s %s ', field.name, '-> delta_chord = ', str(field.delta_chord), '[mm]')
0728 logger.info('+++++> %s %s %s %s ', field.name, '-> min_chord_step = ', str(field.min_chord_step), '[mm]')
0729 logger.info('+++++> %s %s %s %s ', field.name, '-> delta_one_step = ', str(field.delta_one_step), '[mm]')
0730 logger.info('+++++> %s %s %s %s ', field.name, '-> delta_intersection = ', str(field.delta_intersection), '[mm]')
0731 logger.info('+++++> %s %s %s %s ', field.name, '-> largest_step = ', str(field.largest_step), '[mm]')
0732 return field
0733
0734 def setupTrackingFieldMT(self, name='MagFieldTrackingSetup',
0735 stepper='ClassicalRK4', equation='Mag_UsualEqRhs', prt=False):
0736 seq, fld = self.addDetectorConstruction("Geant4FieldTrackingConstruction/" + name)
0737 self._private_setupField(fld, stepper, equation, prt)
0738 return (seq, fld)
0739
0740 def setupTrackingField(self, name='MagFieldTrackingSetup',
0741 stepper='ClassicalRK4', equation='Mag_UsualEqRhs', prt=False):
0742 field = self.addConfig('Geant4FieldTrackingSetupAction/' + name)
0743 self._private_setupField(field, stepper, equation, prt)
0744 return field
0745
0746 def setupPhysics(self, name):
0747 phys = self.master().physicsList()
0748 phys.extends = name
0749 phys.decays = True
0750 phys.enableUI()
0751 phys.dump()
0752 return phys
0753
0754 def addPhysics(self, name):
0755 phys = self.master().physicsList()
0756 opt = PhysicsList(self.master(), name)
0757 opt.enableUI()
0758 phys.adopt(opt)
0759 return opt
0760
0761 def setupGun(self, name, particle, energy, typ="Geant4ParticleGun", isotrop=True,
0762 multiplicity=1, position=(0.0, 0.0, 0.0), register=True, **args):
0763 gun = GeneratorAction(self.kernel(), typ + "/" + name, True)
0764 for i in args.items():
0765 setattr(gun, i[0], i[1])
0766 gun.Energy = energy
0767 gun.particle = particle
0768 gun.multiplicity = multiplicity
0769 gun.position = position
0770 gun.isotrop = isotrop
0771 gun.enableUI()
0772 if register:
0773 self.kernel().generatorAction().add(gun)
0774 return gun
0775
0776 def setupROOTOutput(self, name, output, mc_truth=True):
0777 """
0778 Configure ROOT output for the simulated events
0779
0780 \author M.Frank
0781 """
0782 evt_root = EventAction(self.kernel(), 'Geant4Output2ROOT/' + name, True)
0783 evt_root.HandleMCTruth = mc_truth
0784 evt_root.Control = True
0785 if not output.endswith('.root'):
0786 output = output + '.root'
0787 evt_root.Output = output
0788 evt_root.enableUI()
0789 self.kernel().eventAction().add(evt_root)
0790 return evt_root
0791
0792 def setupLCIOOutput(self, name, output):
0793 """
0794 Configure LCIO output for the simulated events
0795
0796 \author M.Frank
0797 """
0798 evt_lcio = EventAction(self.kernel(), 'Geant4Output2LCIO/' + name, True)
0799 evt_lcio.Control = True
0800 evt_lcio.Output = output
0801 evt_lcio.enableUI()
0802 self.kernel().eventAction().add(evt_lcio)
0803 return evt_lcio
0804
0805 def setupEDM4hepOutput(self, name, output):
0806 """Configure EDM4hep root output for the simulated events."""
0807 evt_edm4hep = EventAction(self.kernel(), 'Geant4Output2EDM4hep/' + name, True)
0808 evt_edm4hep.Control = True
0809 evt_edm4hep.Output = output
0810 evt_edm4hep.enableUI()
0811 self.kernel().eventAction().add(evt_edm4hep)
0812 return evt_edm4hep
0813
0814 def buildInputStage(self, generator_input_modules, output_level=None, have_mctruth=True):
0815 """
0816 Generic build of the input stage with multiple input modules.
0817
0818 Actions executed are:
0819 1) Register Generation initialization action
0820 2) Append all modules to build the complete input record
0821 These modules are readers/particle sources, boosters and/or smearing actions.
0822 3) Merge all existing interaction records
0823 4) Add the MC truth handler
0824
0825 \author M.Frank
0826 """
0827 ga = self.kernel().generatorAction()
0828
0829 gen = GeneratorAction(self.kernel(), "Geant4GeneratorActionInit/GenerationInit")
0830 if output_level is not None:
0831 gen.OutputLevel = output_level
0832 ga.adopt(gen)
0833
0834
0835
0836 for gen in generator_input_modules:
0837 gen.enableUI()
0838 if output_level is not None:
0839 gen.OutputLevel = output_level
0840 ga.adopt(gen)
0841
0842
0843 gen = GeneratorAction(self.kernel(), "Geant4InteractionMerger/InteractionMerger")
0844 gen.enableUI()
0845 if output_level is not None:
0846 gen.OutputLevel = output_level
0847 ga.adopt(gen)
0848
0849
0850 if have_mctruth:
0851 gen = GeneratorAction(self.kernel(), "Geant4PrimaryHandler/PrimaryHandler")
0852 gen.RejectPDGs = "{1,2,3,4,5,6,21,23,24}"
0853 gen.enableUI()
0854 if output_level is not None:
0855 gen.OutputLevel = output_level
0856 ga.adopt(gen)
0857
0858 return self
0859
0860 def run(self):
0861 """
0862 Execute the main Geant4 action
0863 \author M.Frank
0864 """
0865 from ROOT import PyDDG4
0866 PyDDG4.run(self.master().get())
0867 return self
0868
0869
0870 Simple = Geant4