File indexing completed on 2026-09-20 08:24:20
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 import cppyy
0012 import importlib
0013 import types
0014 import logging
0015
0016 logger = logging.getLogger(__name__)
0017
0018
0019
0020 def dd4hep_directories(g4=True):
0021 """
0022 Return tuple of relevant dd4hep directories: (dd4hep, rootsys, geant4)
0023 """
0024 import os
0025 dd4hep = os.getenv("DD4hepINSTALL", "/usr")
0026 rootsys = os.getenv("ROOTSYS", "/usr")
0027 g4_dir = None
0028 if g4:
0029 g4_dir = os.getenv('G4INSTALL', "/usr")
0030 return (rootsys, g4_dir, dd4hep, )
0031
0032
0033
0034 def root_add_compile_option(option):
0035 from ROOT import gSystem
0036 known = gSystem.GetIncludePath()
0037 idx = known.find(option + ' ')
0038 if idx > 0 and idx + len(option) >= len(known):
0039 return known
0040 gSystem.AddIncludePath(' ' + option)
0041
0042
0043
0044 def root_add_include_path(path):
0045 from ROOT import gSystem
0046 known = gSystem.GetIncludePath()
0047 path = '"' + path + '"'
0048 idx = known.find(path)
0049 if idx > 0 and idx + len(path) == len(known):
0050 return known
0051 gSystem.AddIncludePath(' -I' + path)
0052
0053
0054
0055 def setup_root_include_path(g4=True, opt=None):
0056 """
0057 Setup the ROOT compile options and include directories
0058 """
0059 from ROOT import gSystem
0060 rootsys, geant4, dd4hep = dd4hep_directories(g4)
0061 known = gSystem.GetIncludePath()
0062
0063 root_add_include_path(rootsys + '/include')
0064 root_add_include_path(dd4hep + '/include')
0065 if geant4:
0066 root_add_include_path(geant4 + '/include/Geant4')
0067 root_add_compile_option(' -Wno-shadow -g -O0')
0068 if opt and known.find(opt) < 0:
0069 gSystem.AddIncludePath(' ' + opt)
0070 return gSystem.GetIncludePath()
0071
0072
0073
0074 def root_compile_opts():
0075 """
0076 Return the ROOT compile options and include directories
0077 """
0078 from ROOT import gSystem
0079 return gSystem.GetIncludePath()
0080
0081
0082
0083 def setup_root_library_path(g4=True, opt=None):
0084 """
0085 Setup the ROOT link libraries and link options for A-Click processing of dd4hep in ROOT
0086 """
0087 from ROOT import gSystem
0088 rootsys, geant4, dd4hep = dd4hep_directories(g4)
0089 known = gSystem.GetLinkedLibs()
0090
0091 lib = ' -L' + dd4hep + '/lib64 ' + ' -L' + dd4hep + '/lib -lDDCore -lDDG4 -lDDSegmentation '
0092 if known.find(lib) >= 0:
0093 lib = ''
0094 if geant4:
0095 g4_lib = ' -L' + geant4 + '/lib64 -L' + geant4 + '/lib -lG4event -lG4tracking -lG4particles '
0096 if known.find(g4_lib) < 0:
0097 lib = lib + g4_lib
0098 if opt and known.find(opt) < 0:
0099 lib = lib + ' ' + opt
0100
0101 if len(lib):
0102 gSystem.AddLinkedLibs(lib)
0103 return gSystem.GetLinkedLibs()
0104
0105
0106
0107 def root_linked_libs():
0108 """
0109 Access the ROOT link libraries and link options for A-Click processing of dd4hep in ROOT
0110 """
0111 from ROOT import gSystem
0112 return gSystem.GetLinkedLibs()
0113
0114
0115
0116 def compileAClick(dictionary, g4=True):
0117 """
0118 We compile the DDG4 plugin on the fly if it does not exist using the AClick mechanism.
0119
0120 """
0121 from ROOT import gInterpreter
0122 import os.path
0123
0124 setup_root_include_path(g4)
0125 setup_root_library_path(g4)
0126 logger.info('Loading AClick %s', dictionary)
0127 package_spec = importlib.util.find_spec('DDG4')
0128 dic = os.path.dirname(package_spec.origin) + os.sep + dictionary
0129 gInterpreter.ProcessLine('.L ' + dic + '+')
0130 from ROOT import dd4hep as module
0131 return module
0132
0133
0134
0135 def loaddd4hep():
0136 """
0137 Import DD4hep module from ROOT using ROOT reflection
0138 """
0139 import os
0140 import sys
0141
0142 rootsys = os.getenv("ROOTSYS", "/usr")
0143 sys.path.append(os.path.join(rootsys, 'lib'))
0144 sys.path.append(os.path.join(rootsys, 'lib64'))
0145 sys.path.append(os.path.join(rootsys, 'lib', 'root'))
0146 sys.path.append(os.path.join(rootsys, 'lib64', 'root'))
0147 from ROOT import gSystem
0148
0149 import platform
0150 if platform.system() == "Darwin":
0151 gSystem.SetDynamicPath(os.environ['DD4HEP_LIBRARY_PATH'])
0152 os.environ['DYLD_LIBRARY_PATH'] = os.pathsep.join([os.environ['DD4HEP_LIBRARY_PATH'],
0153 os.environ.get('DYLD_LIBRARY_PATH', '')]).strip(os.pathsep)
0154 result = gSystem.Load("libDDCore")
0155 if result < 0:
0156 raise Exception('dd4hep.py: Failed to load the dd4hep library libDDCore: ' + gSystem.GetErrorStr())
0157 from ROOT import dd4hep as module
0158 return module
0159
0160
0161
0162 name_space = __import__(__name__)
0163
0164
0165
0166 def import_namespace_item(ns, nam):
0167 scope = getattr(name_space, ns)
0168 attr = getattr(scope, nam)
0169 setattr(name_space, nam, attr)
0170 return attr
0171
0172
0173
0174 def import_root(nam):
0175 setattr(name_space, nam, getattr(ROOT, nam))
0176
0177
0178
0179
0180 try:
0181 dd4hep = loaddd4hep()
0182 import ROOT
0183 except Exception as X:
0184 import sys
0185 logger.error('+--%-100s--+', 100 * '-')
0186 logger.error('| %-100s |', 'Failed to load dd4hep base library:')
0187 logger.error('| %-100s |', str(X))
0188 logger.error('+--%-100s--+', 100 * '-')
0189 sys.exit(1)
0190
0191
0192
0193 class _Levels:
0194 def __init__(self):
0195 self.VERBOSE = 1
0196 self.DEBUG = 2
0197 self.INFO = 3
0198 self.WARNING = 4
0199 self.ERROR = 5
0200 self.FATAL = 6
0201 self.ALWAYS = 7
0202
0203
0204
0205 def unicode_2_string(value):
0206 """Turn any unicode literal into str, needed when passing to c++.
0207
0208 Recursively transverses dicts, lists, sets, tuples
0209
0210 :return: always a str
0211 """
0212 if isinstance(value, (bool, float, int)):
0213 value = value
0214 elif isinstance(value, str):
0215 value = str(value)
0216 elif isinstance(value, bytes):
0217 value = value.decode()
0218 elif isinstance(value, (list, set, tuple)):
0219 value = [unicode_2_string(x) for x in value]
0220 elif isinstance(value, dict):
0221 tempDict = {}
0222 for key, val in value.items():
0223 key = unicode_2_string(key)
0224 val = unicode_2_string(val)
0225 tempDict[key] = val
0226 value = tempDict
0227 return str(value)
0228
0229
0230 OutputLevel = _Levels()
0231 VERBOSE = OutputLevel.VERBOSE
0232 DEBUG = OutputLevel.DEBUG
0233 INFO = OutputLevel.INFO
0234 WARNING = OutputLevel.WARNING
0235 ERROR = OutputLevel.ERROR
0236 FATAL = OutputLevel.FATAL
0237
0238
0239
0240
0241
0242
0243
0244
0245 std = cppyy.gbl.std
0246 std_vector = std.vector
0247 std_list = std.list
0248 std_map = std.map
0249 std_pair = std.pair
0250
0251 core = dd4hep
0252 cond = dd4hep.cond
0253 tools = dd4hep.tools
0254 align = dd4hep.align
0255 detail = dd4hep.detail
0256 units = types.ModuleType('units')
0257
0258 import_namespace_item('tools', 'Evaluator')
0259
0260 import_namespace_item('core', 'NamedObject')
0261 import_namespace_item('core', 'run_interpreter')
0262
0263 import_namespace_item('detail', 'interp')
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274 def import_detail():
0275 import_namespace_item('detail', 'DD4hepUI')
0276
0277
0278
0279 def import_geometry():
0280 import_namespace_item('core', 'setPrintLevel')
0281 import_namespace_item('core', 'setPrintFormat')
0282 import_namespace_item('core', 'printLevel')
0283 import_namespace_item('core', 'PrintLevel')
0284
0285 import_namespace_item('core', 'debug')
0286 import_namespace_item('core', 'info')
0287 import_namespace_item('core', 'warning')
0288 import_namespace_item('core', 'error')
0289 import_namespace_item('core', 'fatal')
0290 import_namespace_item('core', 'exception')
0291
0292 import_namespace_item('core', 'Detector')
0293 import_namespace_item('core', 'evaluator')
0294 import_namespace_item('core', 'g4Evaluator')
0295
0296 import_namespace_item('core', 'VolumeManager')
0297 import_namespace_item('core', 'OverlayedField')
0298 import_namespace_item('core', 'Ref_t')
0299
0300
0301 import_namespace_item('core', 'Author')
0302 import_namespace_item('core', 'Header')
0303 import_namespace_item('core', 'Constant')
0304 import_namespace_item('core', 'Atom')
0305 import_namespace_item('core', 'Material')
0306 import_namespace_item('core', 'VisAttr')
0307 import_namespace_item('core', 'Limit')
0308 import_namespace_item('core', 'LimitSet')
0309 import_namespace_item('core', 'LimitSetObject')
0310 import_namespace_item('core', 'Region')
0311 import_namespace_item('core', 'RegionObject')
0312 import_namespace_item('core', 'HitCollection')
0313
0314 import_namespace_item('core', 'Position')
0315 import_namespace_item('core', 'PositionRhoZPhi')
0316 import_namespace_item('core', 'PositionPolar')
0317 import_namespace_item('core', 'Direction')
0318 import_namespace_item('core', 'XYZAngles')
0319 import_namespace_item('core', 'RotationZYX')
0320 import_namespace_item('core', 'RotationX')
0321 import_namespace_item('core', 'RotationY')
0322 import_namespace_item('core', 'RotationZ')
0323 import_namespace_item('core', 'Rotation3D')
0324 import_namespace_item('core', 'EulerAngles')
0325 import_namespace_item('core', 'Transform3D')
0326 import_namespace_item('core', 'Translation3D')
0327
0328
0329 import_namespace_item('core', 'Segmentation')
0330 import_namespace_item('core', 'SegmentationObject')
0331 import_namespace_item('core', 'Readout')
0332 import_namespace_item('core', 'ReadoutObject')
0333
0334
0335 import_namespace_item('core', 'Alignment')
0336 import_namespace_item('core', 'AlignmentCondition')
0337
0338
0339 import_namespace_item('core', 'Condition')
0340 import_namespace_item('core', 'ConditionKey')
0341
0342
0343 import_namespace_item('core', 'World')
0344 import_namespace_item('core', 'DetElement')
0345 import_namespace_item('core', 'SensitiveDetector')
0346
0347
0348 import_namespace_item('core', 'Volume')
0349 import_namespace_item('core', 'PlacedVolume')
0350
0351
0352 import_namespace_item('core', 'Solid')
0353 import_namespace_item('core', 'Box')
0354 import_namespace_item('core', 'HalfSpace')
0355 import_namespace_item('core', 'Polycone')
0356 import_namespace_item('core', 'ConeSegment')
0357 import_namespace_item('core', 'Tube')
0358 import_namespace_item('core', 'CutTube')
0359 import_namespace_item('core', 'TruncatedTube')
0360 import_namespace_item('core', 'EllipticalTube')
0361 import_namespace_item('core', 'Cone')
0362 import_namespace_item('core', 'Trap')
0363 import_namespace_item('core', 'PseudoTrap')
0364 import_namespace_item('core', 'Trapezoid')
0365 import_namespace_item('core', 'Torus')
0366 import_namespace_item('core', 'Sphere')
0367 import_namespace_item('core', 'Paraboloid')
0368 import_namespace_item('core', 'Hyperboloid')
0369 import_namespace_item('core', 'PolyhedraRegular')
0370 import_namespace_item('core', 'Polyhedra')
0371 import_namespace_item('core', 'ExtrudedPolygon')
0372 import_namespace_item('core', 'EightPointSolid')
0373 import_namespace_item('core', 'BooleanSolid')
0374 import_namespace_item('core', 'SubtractionSolid')
0375 import_namespace_item('core', 'UnionSolid')
0376 import_namespace_item('core', 'IntersectionSolid')
0377
0378
0379
0380 def import_tgeo():
0381 import_root('TGeoManager')
0382 import_root('TGeoNode')
0383 import_root('TGeoNodeMatrix')
0384
0385 import_root('TGeoVolume')
0386 import_root('TGeoVolumeMulti')
0387 import_root('TGeoVolumeAssembly')
0388
0389 import_root('TGeoMaterial')
0390 import_root('TGeoMedium')
0391 import_root('TGeoIsotope')
0392 import_root('TGeoElement')
0393
0394 import_root('TGeoMatrix')
0395 import_root('TGeoHMatrix')
0396 import_root('TGeoIdentity')
0397 import_root('TGeoTranslation')
0398 import_root('TGeoRotation')
0399 import_root('TGeoScale')
0400 import_root('TGeoCombiTrans')
0401
0402 import_root('TGeoShape')
0403 import_root('TGeoBBox')
0404 import_root('TGeoArb8')
0405 import_root('TGeoTrap')
0406 import_root('TGeoGtra')
0407 import_root('TGeoCompositeShape')
0408 import_root('TGeoCone')
0409 import_root('TGeoConeSeg')
0410 import_root('TGeoTube')
0411 import_root('TGeoTubeSeg')
0412 import_root('TGeoCtub')
0413 import_root('TGeoEltu')
0414 import_root('TGeoHype')
0415 import_root('TGeoHalfSpace')
0416 import_root('TGeoPara')
0417 import_root('TGeoParaboloid')
0418 import_root('TGeoPcon')
0419 import_root('TGeoPgon')
0420 import_root('TGeoScaledShape')
0421 import_root('TGeoShapeAssembly')
0422 import_root('TGeoSphere')
0423 import_root('TGeoTorus')
0424 import_root('TGeoTrd1')
0425 import_root('TGeoTrd2')
0426 import_root('TGeoXtru')
0427
0428
0429 import_tgeo()
0430 import_geometry()
0431 import_detail()
0432
0433
0434
0435 class Logger:
0436 """
0437 Helper class to use the dd4hep printout functions from python
0438
0439 \author M.Frank
0440 \version 1.0
0441 """
0442
0443 def __init__(self, name):
0444 "Logger constructor"
0445 self.name = name
0446
0447 def setPrintLevel(self, level):
0448 "Adjust printout level of dd4hep"
0449 if isinstance(level, str):
0450 if level == 'VERBOSE':
0451 level = OutputLevel.VERBOSE
0452 elif level == 'DEBUG':
0453 level = OutputLevel.DEBUG
0454 elif level == 'INFO':
0455 level = OutputLevel.INFO
0456 elif level == 'WARNING':
0457 level = OutputLevel.WARNING
0458 elif level == 'ERROR':
0459 level = OutputLevel.ERROR
0460 elif level == 'FATAL':
0461 level = OutputLevel.FATAL
0462 else:
0463 level = int(level)
0464 dd4hep.setPrintLevel(level)
0465
0466 def always(self, msg):
0467 "Call dd4hep printout function with level ALWAYS"
0468 dd4hep.always(self.name, msg)
0469
0470 def verbose(self, msg):
0471 "Call dd4hep printout function with level VERBOSE"
0472 dd4hep.verbose(self.name, msg)
0473
0474 def debug(self, msg):
0475 "Call dd4hep printout function with level DEBUG"
0476 dd4hep.debug(self.name, msg)
0477
0478 def info(self, msg):
0479 "Call dd4hep printout function with level INFO"
0480 dd4hep.info(self.name, msg)
0481
0482 def warning(self, msg):
0483 "Call dd4hep printout function with level WARNING"
0484 dd4hep.warning(self.name, msg)
0485
0486 def error(self, msg):
0487 "Call dd4hep printout function with level ERROR"
0488 dd4hep.error(self.name, msg)
0489
0490 def fatal(self, msg):
0491 "Call dd4hep printout function with level FATAL"
0492 dd4hep.fatal(self.name, msg)
0493
0494 def exception(self, msg):
0495 "Call dd4hep exception function"
0496 dd4hep.exception(self.name, msg)
0497
0498
0499 dd4hep_logger = Logger
0500
0501
0502
0503
0504
0505
0506
0507 class CommandLine:
0508 """
0509 Helper to ease parsing the command line.
0510 Any argument given in the command line is accessible
0511 from the object. If no value is supplied, the returned
0512 value is True. If the argument is not present None is returned.
0513
0514 \author M.Frank
0515 \version 1.0
0516 """
0517 def __init__(self, help=None):
0518 import sys
0519 self.data = {}
0520 help_call = help
0521 have_help = False
0522 for i in range(len(sys.argv)):
0523 if sys.argv[i][0] == '-':
0524 key = sys.argv[i][1:]
0525 val = True
0526 if i + 1 < len(sys.argv):
0527 v = sys.argv[i + 1]
0528 if v[0] != '-':
0529 val = v
0530 self.data[key] = val
0531 if key.upper() == 'HELP' or key.upper() == '?':
0532 have_help = True
0533 if have_help and help_call:
0534 help_call()
0535 if self.data.get('print_level'):
0536 log = Logger('CommandLine')
0537 log.setPrintLevel(self.data.get('print_level'))
0538
0539 def __getattr__(self, attr):
0540 if self.data.get(attr):
0541 return self.data.get(attr)
0542 return None
0543
0544
0545
0546
0547
0548
0549
0550 try:
0551 import_namespace_item('core', 'dd4hep_units')
0552
0553 def import_units(ns=None):
0554 if ns is None:
0555 ns = name_space
0556
0557 logger.debug('Importing units into namespace ' + str(ns.__name__))
0558 count = 0
0559 for nam in dir(dd4hep.dd4hep_units):
0560 if nam[0] != '_':
0561 count = count + 1
0562 setattr(ns, nam, getattr(core.dd4hep_units, nam))
0563
0564 return count
0565
0566 except Exception as e:
0567 logger.warning('No units can be imported. ' + str(e))
0568
0569 def import_units(ns=None):
0570 return 0
0571
0572 import_units(ns=units)