Skip to content
Snippets Groups Projects
lcdd.py 15.7 KiB
Newer Older
# $Id: Handle.h 570 2013-05-17 07:47:11Z markus.frank $
#==========================================================================
#  AIDA Detector description implementation for LCD
#--------------------------------------------------------------------------
# Copyright (C) Organisation européenne pour la Recherche nucléaire (CERN)
# All rights reserved.
#
# For the licensing terms see $DD4hepINSTALL/LICENSE.
# For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
#
#==========================================================================

from math import cos, sin, pi, tan
from os import path, listdir
import SystemOfUnits
import math
from ROOT import SetOwnership, DD4hep, TGeoMixture, TGeoMedium, gGeoManager, TNamed

LCDD       = DD4hep.Geometry.LCDD
Constant   = DD4hep.Geometry.Constant
Material   = DD4hep.Geometry.Material
VisAttr    = DD4hep.Geometry.VisAttr
AlignmentEntry = DD4hep.Geometry.AlignmentEntry
Limit      = DD4hep.Geometry.Limit
DetElement = DD4hep.Geometry.DetElement
Box        = DD4hep.Geometry.Box
Tube       = DD4hep.Geometry.Tube
Trapezoid  = DD4hep.Geometry.Trapezoid
Volume     = DD4hep.Geometry.Volume
PlacedVolume = DD4hep.Geometry.PlacedVolume
Position   = DD4hep.Geometry.Position
Rotation   = DD4hep.Geometry.Rotation
Handle     = DD4hep.Geometry.Handle
Pere Mato's avatar
Pere Mato committed
GridXYZ = DD4hep.Geometry.GridXYZ
GlobalGridXY = DD4hep.Geometry.GlobalGridXY
CartesianGridXY = DD4hep.Geometry.CartesianGridXY
ProjectiveCylinder = DD4hep.Geometry.ProjectiveCylinder
Pere Mato's avatar
Pere Mato committed
NonProjectiveCylinder = DD4hep.Geometry.NonProjectiveCylinder
ProjectiveZPlane = DD4hep.Geometry.ProjectiveZPlane
_toDictionary = DD4hep.Geometry._toDictionary

import xml.etree.ElementTree as xml
unique_mat_id = 0x7FFEFEED

Pere Mato's avatar
Pere Mato committed
current_xmlfile = None

constants = {}
constants.update(SystemOfUnits.__dict__)
drivers = {}
drivers.update(math.__dict__)
drivers.update(DD4hep.Geometry.__dict__)


#---Enhancing the Element class with dedicated accessors--------------------------
def _getInt(self,attrib): return int(eval(self.get(attrib).replace('(int)',''),constants))
def _getFloat(self,*attrib):
  sval = self.get(attrib[0], None)
  if not sval and len(attrib) > 1: return attrib[1]
  else: return float(eval(sval.replace('(int)',''), constants))
def _getBool(self,attrib): 
  return self.get(attrib, '').lower() in ('true', 'yes', 'on') 
xml._ElementInterface.getI = _getInt
xml._ElementInterface.getF = _getFloat
xml._ElementInterface.getB = _getBool

xml._ElementInterface.name = property(lambda self: self.get('name'))
xml._ElementInterface.type = property(lambda self: self.get('type'))
xml._ElementInterface.vis  = property(lambda self: self.get('vis'))
Pere Mato's avatar
Pere Mato committed
xml._ElementInterface.ref  = property(lambda self: self.get('ref'))
xml._ElementInterface.value  = property(lambda self: self.getF('value'))
xml._ElementInterface.material = property(lambda self: self.get('material'))
xml._ElementInterface.module = property(lambda self: self.get('module'))
xml._ElementInterface.id   = property(lambda self: self.getI('id'))
Pere Mato's avatar
Pere Mato committed
xml._ElementInterface.number = property(lambda self: self.getI('number'))
xml._ElementInterface.x1   = property(lambda self: self.getF('x1'))
xml._ElementInterface.x2   = property(lambda self: self.getF('x2'))
xml._ElementInterface.x    = property(lambda self: self.getF('x'))
xml._ElementInterface.y    = property(lambda self: self.getF('y'))
xml._ElementInterface.z    = property(lambda self: self.getF('z'))
xml._ElementInterface.zstart = property(lambda self: self.getF('zstart'))
Pere Mato's avatar
Pere Mato committed
xml._ElementInterface.offset = property(lambda self: self.getF('offset'))
xml._ElementInterface.radius = property(lambda self: self.getF('radius'))
xml._ElementInterface.zhalf = property(lambda self: self.getF('zhalf'))
xml._ElementInterface.phi0 = property(lambda self: self.getF('phi0'))
xml._ElementInterface.r    = property(lambda self: self.getF('r'))
xml._ElementInterface.dz   = property(lambda self: self.getF('dz'))
xml._ElementInterface.thickness = property(lambda self: self.getF('thickness'))
xml._ElementInterface.length = property(lambda self: self.getF('length'))
xml._ElementInterface.width = property(lambda self: self.getF('width'))
xml._ElementInterface.inner_r = property(lambda self: self.getF('inner_r'))
xml._ElementInterface.outer_r = property(lambda self: self.getF('outer_r'))
xml._ElementInterface.z_length = property(lambda self: self.getF('z_length'))
Pere Mato's avatar
Pere Mato committed
xml._ElementInterface.rmin = property(lambda self: self.getF('rmin'))
xml._ElementInterface.rmax = property(lambda self: self.getF('rmax'))


def getRotation(rot):
  if rot is not None : return Rotation(rot.getF('x',0.0),rot.getF('y',0.0), rot.getF('z',0.0))
  else   : return Rotation()
Pere Mato's avatar
Pere Mato committed
def getPosition(pos):
  if pos is not None : return Position(pos.getF('x',0.0),pos.getF('y',0.0), pos.getF('z',0.0))
  else   : return Position()

Pere Mato's avatar
Pere Mato committed
drivers['getRotation'] = getRotation
drivers['getPosition'] = getPosition
#---------------------------------------------------------------------------------
Pere Mato's avatar
Pere Mato committed
def load_drivers(*args):
  if not args:
    args = [path.join(path.dirname(__file__),'drivers')]
  for arg in args:
    if path.exists(arg):
      if path.isfile(arg):
        print "Loading driver file ... %s" % arg
        execfile(arg, drivers)
      elif path.isdir(arg):
        for f in listdir(arg) : 
          if path.splitext(f)[1] == '.py':
            print "Loading driver file ... %s" % path.join(arg,f)
            execfile(path.join(arg,f), drivers)
      else: raise "Path '%s' is not a directory or file" % arg 
    else: raise "Path '%s' does not exists" % arg


#---------------------------------------------------------------------------------
def process_xmlfile(lcdd, file):
Pere Mato's avatar
Pere Mato committed
  global current_xmlfile
  root = xml.parse(file).getroot()
Pere Mato's avatar
Pere Mato committed
  last_xmlfile, current_xmlfile = current_xmlfile, file
  tags = ('includes', 'define', 'materials', 'properties', 'limits', 'display',
          'readouts', 'detectors', 'alignments', 'fields', 'sensitive_detectors')
  if root.tag in tags :
    process_tag(lcdd, root)
  else :
    for tag in tags:
      for e in root.findall(tag):
        process_tag(lcdd, e)
Pere Mato's avatar
Pere Mato committed
  current_xmlfile = last_xmlfile
def process_tag(lcdd, elem):
  if elem.tag == 'detectors' :
    lcdd.init() # call init before processing 'detectors' (need world volume)
  procs = globals().get('process_%s'% elem.tag, None)
  if not procs :
    procs = drivers.get('process_%s'% elem.tag, None)
  if procs :
    apply(procs,(lcdd, elem))
  else : print 'XML tag %s not processed!!! No function found.' % elem.tag


#--------------------------------------------------------------------------------
def fromXML(xmlfile):
  print 'Converting Compact file: ', xmlfile
  lcdd = LCDD.getInstance()
  process_xmlfile(lcdd, xmlfile)
  return lcdd

Pere Mato's avatar
Pere Mato committed
#---------------------------------------------------------------------------------
def process_includes(lcdd, elem):
  for c in elem.findall('gdmlFile'):
    print 'Adding Gdml file ...', c.get('ref')
    fname = c.get('ref').replace('file:','')
    if not path.isabs(fname): fname = path.join(path.dirname(current_xmlfile),fname)
    process_xmlfile(lcdd, fname)
Pere Mato's avatar
Pere Mato committed
  for c in elem.findall('pyBuilder'):
    print 'Adding PyBuilder ...', c.get('ref')
    fname = c.get('ref')
    if not path.isabs(fname): fname = path.join(path.dirname(current_xmlfile),fname)
    load_drivers(fname)
  for c in elem.findall('alignment'):
    print 'Adding Alignment file ...', c.get('ref')
    fname = c.get('ref').replace('file:','')
    if not path.isabs(fname): fname = path.join(path.dirname(current_xmlfile),fname)
    process_xmlfile(lcdd, fname)

#---------------------------------------------------------------------------------
def process_info(lcdd, elem):
  pass
Pere Mato's avatar
Pere Mato committed

#---------------------------------------------------------------------------------
def process_define(lcdd, elem):
  for c in elem.findall('constant'):
    #print 'Adding constant ...', c.get('name')
    lcdd.addConstant(Constant(c.get('name'),c.get('value')))
    _toDictionary(c.get('name'),c.get('value')) #-- Make it known to the evaluator
    constants[c.get('name')] = c.getF('value')

#---------------------------------------------------------------------------------
def process_element(lcdd, elem):
  #print 'Adding element ...', elem.get('name')
  ename = elem.get('name')
  element = tab.FindElement(ename)
  if not element:
    atom = elem.find('atom')
Pere Mato's avatar
Pere Mato committed
    tab.AddElement(atom.get('name'), atom.get('formula'), atom.getI('Z'), atom.getI('value'))

#---------------------------------------------------------------------------------
def process_materials(lcdd, elem):
  for m in elem.findall('material'):
    process_material(lcdd, m)

#---------------------------------------------------------------------------------
Pere Mato's avatar
Pere Mato committed
# <material formula="Ac" name="Actinium" state="solid" >
#  <RL type="X0" unit="cm" value="0.601558" />
#  <NIL type="lambda" unit="cm" value="21.2048" />
#  <D type="density" unit="g/cm3" value="10.07" />
#  <composite n="1" ref="Ac" />
#</material>
#<material name="G10">
#  <D type="density" value="1.7" unit="g/cm3"/>
#  <fraction n="0.08" ref="Cl"/>
#  <fraction n="0.773" ref="Quartz"/>
#  <fraction n="0.147" ref="Epoxy"/>
#</material>


def process_material(lcdd, m):
  #print 'Adding material ...', m.get('name')
  density = m.find('D')
Pere Mato's avatar
Pere Mato committed
  radlen  = m.find('RL')
  intlen  = m.find('NIL')
  composites = m.findall('fraction') or m.findall('composite')
Pere Mato's avatar
Pere Mato committed
  mat = gGeoManager.GetMaterial(m.name)
Pere Mato's avatar
Pere Mato committed
    mat = TGeoMixture(m.name, len(composites), eval(density.get('value')+'*'+density.get('unit')+'/(g/cm3)',constants))
    SetOwnership( mat, False )
Pere Mato's avatar
Pere Mato committed
  rl = (radlen is not None) and eval(radlen.get('value')+'*'+radlen.get('unit'),constants) or 0.0
  il = (intlen is not None) and eval(intlen.get('value')+'*'+intlen.get('unit'),constants) or 0.0
  #mat.SetRadLen(-rl, -il)
  elts = [mat.GetElement(i).GetName() for i in range(mat.GetNelements())]
  for c in composites:
Pere Mato's avatar
Pere Mato committed
    nam = c.ref
    if nam not in elts:
Pere Mato's avatar
Pere Mato committed
      if c.tag == 'composite' : fraction = c.getI('n')
      elif c.tag == 'fraction' : fraction = c.getF('n')
      if table.FindElement(nam):
        mat.AddElement(table.FindElement(nam), fraction)
      elif gGeoManager.GetMaterial(nam):
        mat.AddElement(gGeoManager.GetMaterial(nam), fraction)
      else:
        raise 'Something going very wrong. Undefined material:' + nam
Pere Mato's avatar
Pere Mato committed
  medium = gGeoManager.GetMedium(m.name)
  if not medium:
    global unique_mat_id
    unique_mat_id = unique_mat_id - 1
Pere Mato's avatar
Pere Mato committed
    medium = TGeoMedium(m.name, unique_mat_id, mat)
    SetOwnership(medium, False)
    medium.SetTitle('material')
    medium.SetUniqueID(unique_mat_id)


#----------------------------------------------------------------------------------
def process_display(lcdd, elem):
  for v in elem.findall('vis'):
    visattr = VisAttr(v.name)
    r,g,b = 1.,1.,1.
    if 'r' in v.keys() : r = v.getF('r')    
    if 'g' in v.keys() : g = v.getF('g')
    if 'b' in v.keys() : b = v.getF('b')
    if 'showDaughters' in v.keys() : visattr.setShowDaughters(v.getB('showDaughters'))
    if 'visible' in v.keys() : visattr.setVisible(v.getB('visible'))
    if 'alpha' in v.keys() : visattr.setAlpha(v.getF('alpha'))
    if 'lineStyle' in v.keys() :
      ls = v.get('lineStyle')
      if ls == 'unbroken' : visattr.setLineStyle(VisAttr.SOLID)
      if ls == 'broken' : visattr.setLineStyle(VisAttr.DASHED)
    else:
      visattr.setLineStyle(VisAttr.SOLID)
    if 'drawingStyle' in v.keys() :
      ds = v.get('drawingStyle')
      if ds == 'wireframe' : visattr.setDrawingStyle(VisAttr.WIREFRAME)
    lcdd.addVisAttribute(visattr)

Pere Mato's avatar
Pere Mato committed
def process_limits(lcdd, elem):
  # <limit name="step_length_max" particles="*" value="5.0" unit="mm" />    
  for l in elem.findall('limit'):
    limit = Limit(lcdd.document(), l.get('name'))
    limit.setParticles(l.get('particles'))
    limit.setValue(l.getF('value'))
    limit.setUnit(l.get('unit'))
    lcdd.addLimit(limit)

#-----------------------------------------------------------------------------------
def process_detectors(lcdd, elem):
  for d in elem.findall('detector'):
    procs = drivers.get('detector_%s'% d.get('type'), None)
    if procs : 
      detector = apply(procs,(lcdd, d))
      lcdd.addDetector(detector)
    else : 
      print 'Detector type %s not found' % d.get('type')

#-----------------------------------------------------------------------------------
def process_alignments(lcdd, elem):
  for a in elem.findall('alignment'):
    process_alignment(lcdd, a)

#-----------------------------------------------------------------------------------
def process_alignment(lcdd, elem):
  alignment = AlignmentEntry(lcdd, elem.name)
  pos = getPosition(elem.find('position'))
  rot = getRotation(elem.find('rotation'))
  print pos.isNull(), rot.isNull()
  alignment.align(pos,rot)
  return alignment

#-----------------------------------------------------------------------------------
def process_readouts(lcdd, elem):
  for a in elem.findall('readout'):
    process_readout(lcdd, a)
#-----------------------------------------------------------------------------------
def process_readout(lcdd, elem):
  readout = Readout(elem.name)
  seg = elem.find('segmentation')
  if seg is not None:
    procs = globals().get('create_%s'% seg.get('type'), None)
    if not procs :
      procs = drivers.get('create_%s'% seg.get('type'), None)
    if procs :
      segment = apply(procs,(lcdd, seg))
      readout.setSegmentation(segment)
    else :
      print 'Segmentation type %s not found' % seg.get('type')
  id = elem.find('id')
  if id is not None:
    idSpec = IDDescriptor(id.text)
    idSpec.SetName(elem.name)
    readout.setIDDescriptor(idSpec)
    lcdd.addIDSpecification(idSpec)
  lcdd.addReadout(readout)

#---Segmentations--------------------------------------------------------------------
Pere Mato's avatar
Pere Mato committed
def create_GridXYZ(lcdd, elem) :
  obj = GridXYZ()
  if 'gridSizeX' in elem.keys() : obj.setGridSizeX(elem.getF('gridSizeX'))
  if 'gridSizeY' in elem.keys() : obj.setGridSizeY(elem.getF('gridSizeY'))
  if 'gridSizeZ' in elem.keys() : obj.setGridSizeZ(elem.getF('gridSizeZ'))
  return obj

def create_GlobalGridXY(lcdd, elem) :
  obj = GlobalGridXY()
  if 'gridSizeX' in elem.keys() : obj.setGridSizeX(elem.getF('gridSizeX'))
  if 'gridSizeY' in elem.keys() : obj.setGridSizeY(elem.getF('gridSizeY'))
  return obj

def create_CartesianGridXY(lcdd, elem) :
  obj = CartesianGridXY()
  if 'gridSizeX' in elem.keys() : obj.setGridSizeX(elem.getF('gridSizeX'))
  if 'gridSizeY' in elem.keys() : obj.setGridSizeY(elem.getF('gridSizeY'))
  return obj

def create_ProjectiveCylinder(lcdd, elem) :
  obj = ProjectiveCylinder()
Pere Mato's avatar
Pere Mato committed
  if 'phiBins' in elem.keys() : obj.setPhiBins(elem.getI('phiBins'))
  if 'thetaBins' in elem.keys() : obj.setThetaBins(elem.getI('thetaBins'))
Pere Mato's avatar
Pere Mato committed
def create_NonProjectiveCylinder(lcdd, elem) :
  obj = NonProjectiveCylinder()
  if 'gridSizePhi' in elem.keys() : obj.setThetaBinSize(elem.getF('gridSizePhi'))
  if 'gridSizeZ' in elem.keys() : obj.setPhiBinSize(elem.getI('gridSizeZ'))
  return obj

def create_ProjectiveZPlane(lcdd, elem) :
  obj = ProjectiveZPlaner()
  if 'phiBins' in elem.keys() : obj.setPhiBins(elem.getI('phiBins'))
  if 'thetaBins' in elem.keys() : obj.setThetaBins(elem.getI('thetaBins'))
  return obj