Adding a new DD4hep sub-detector with Detector [TO BE MOVED]

Preparing Gauss for adding new sub-detectors

Attention

This section will be moved to a new documentation website dedicated to Gauss.

Make sure that before you start this tutorial you have followed the examples that show how to build Gaussino with DD4hep support. In particular, the decision has to be made if you want work with your local copy of the Detector or the Detector project built in the nightly system:

Tip

Use x86_64_v2-centos7-gcc11+dd4hep-opt if you want to work with Detector/DD4hep.

Checklist to activate a sub-detector

Once you have correctly configured Gauss, you can start integrating your sub-detector with the simulation framework. We have prepared a list of the required tasks:

  1. Modify the XML geometry description

  2. Implement python configuration

  3. Check if extra modifications are needed

  4. Create a MR in Gauss targeting Futurev4 branch

  5. Put the sub-detector in the nighlty and LHCbPR tests

Modify the XML geometry description

In order to load the geometry in Gauss from the Detector project, you have to make sure that your sub-detector is completely described in XML files in Detector/compact/trunk directory of the Detector project. Therefore, Gauss has to know what is the hiararchy of the volumes in the geometry and this has to be implemented in xml_writer.py. We will use VP as an example. VP has to be added in /world/BeforeMagnetRegion and therefore the following changes

+     ET.SubElement(define, "constant", name="VP:parent",
+                   value="/world/BeforeMagnetRegion", type="string")

are needed in the xml_writer.py:

# Combine the includes into a valid LHCb DD4hep xml and return name of temporary
# file
def create_xml(includesfiles):
    unique_includes = list(OrderedDict.fromkeys(includesfiles))
    detectorroot = os.path.join(os.environ['DETECTOR_PROJECT_ROOT'], 'compact/trunk/')

    def addroot(p):
        if p[0] != '.' and p[0] != '/':
            return detectorroot + p
        return p

    root = ET.Element("lccdd")
    ET.SubElement(root, "std_conditions", type="STP")
    debug = ET.SubElement(root, "debug")
    ET.SubElement(debug, "type", name="includes", value="0")
    ET.SubElement(debug, "type", name="materials", value="0")
    includes = ET.SubElement(root, "includes")
    ET.SubElement(includes, "gdmlFile", ref=addroot("defaults.xml"))
    define = ET.SubElement(root, "define")
    ET.SubElement(define, "constant", name="Bls:parent",
                  value="/world/BeforeMagnetRegion/BeforeVelo", type="string")
    ET.SubElement(define, "constant", name="BcmUp:parent",
                  value="/world/BeforeMagnetRegion/BeforeVelo", type="string")
    ET.SubElement(define, "constant", name="BcmDown:parent",
                  value="/world/DownstreamRegion/AfterMuon", type="string")
    ET.SubElement(define, "constant", name="GValve:parent",
                  value="/world/BeforeMagnetRegion/BeforeVelo", type="string")
    ET.SubElement(define, "constant", name="MBXWUp:parent",
                  value="/world/UpstreamRegion", type="string")
    ET.SubElement(define, "constant", name="Cavern:parent",
                  value="/world/Infrastructure", type="string")
    ET.SubElement(define, "constant", name="Tunnel:parent",
                  value="/world/Infrastructure", type="string")
    ET.SubElement(define, "constant", name="Bunker:parent",
                  value="/world/Infrastructure", type="string")
    # here we added VP
    ET.SubElement(define, "constant", name="VP:parent",
                  value="/world/BeforeMagnetRegion", type="string")
    ET.SubElement(define, "constant", name="UT:parent",
                  value="/world/BeforeMagnetRegion", type="string")
    ET.SubElement(define, "constant", name="FT:parent",
                  value="/world/AfterMagnetRegion/T", type="string")
    ET.SubElement(define, "constant", name="Magnet:parent",
                  value="/world/MagnetRegion", type="string")
    ET.SubElement(define, "constant", name="Magnet:ignore", value="0")
    ET.SubElement(define, "constant", name="UpstreamRegion:ignore", value="0")
    ET.SubElement(define, "constant", name="BeforeMagnetRegion:ignore", value="0")  # NOQA
    ET.SubElement(define, "constant", name="MagnetRegion:ignore", value="0")
    ET.SubElement(define, "constant", name="AfterMagnetRegion:ignore", value="0")  # NOQA
    ET.SubElement(define, "constant", name="DownstreamRegion:ignore", value="0")

    ET.SubElement(root, "include", ref=addroot("global/conditions.xml"))

    # FIXME: Regions need something from this file
    ET.SubElement(root, "include", ref=addroot("T/parameters.xml"))
    ET.SubElement(root, "include", ref=addroot("Regions/detector.xml"))

    for inc in unique_includes:
        ET.SubElement(root, "include", ref=addroot(inc))

    _, tmpfile = tempfile.mkstemp('.xml')
    xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml(indent="   ")
    with open(tmpfile, "w") as f:
        f.write(xmlstr)
    log.info('Wrote xml file to {}'.format(tmpfile))
    return tempfile.tempdir, tmpfile.replace(tempfile.tempdir + '/', '')

A temporary XML file will be created in /tmp on your local machine.

Implement python configuration

What happens in Gauss is that we use the python configuration to decide which sub-detectors should be included and which not. If a sub-detector is added, then all of its XML files have to be imported. Please note that Gauss has to support both DD4hep and DetDesc geometries and therefore we need a separate configuration for each of them. Python configuration of each sub-detector should be handled in a separate python file in Sim/Gauss/python/Gauss/Geometry/. We will use VP again as an example. In this case, a file VP.py is already there. If the sub-detector is completely new, you should create a new file and add the following import in init.py:

+ from Gauss.Geometry.VP import *

You have to make sure that you sub-detector class inherits from det_base and uses the subdetector decorator. There is also a set of functions that have to be implemented. For VP:

from Gauss.Geometry.det_base import det_base
from Gauss.Geometry.Helpers import subdetector

@subdetector
class VP(det_base):

    def ApplyDetectorDetDesc(self, basePieces, detPieces):
        # Add the necessary detector pieces for DetDesc
  
    def ApplyDetectorDD4hep(self, basePieces, detPieces):
        # Add a list of all the necessary DD4hep includes

    def SetupExtractionImpl(self, slot=''):
        # Configure the hit getter that transforms the Geant4 hit collection
        # to our event model. Wrapping function in base class configures SimConf.

    def SetupMonitor(self, slot=''):
        # Setup any necessary monitoring algorithms

Therefore, in order to use the DD4hep implementation of your sub-detector you have to implement ApplyDetectorDetDesc and populate the LHCbGeo._listOfXMLIncludes_ list with the XML files required for your sub-detector. If your sub-detector is registering hits, then you should also provide a mapping between the name of the sensitive volume and the name of the factory used to construct the sensitive detector object. For VP we have:

def ApplyDetectorDD4hep(self, basePieces, detPieces):
    # Configuring the DD4hep detector conversion.
    # 1. Add the mapping to have the LHCbDD4hepCnvSvc instrument
    # the G4 volume with the correct sensdet factory if marked with a
    # dd4hep sensitive detector named VP
    from Configurables import LHCbDD4hepCnvSvc
    mappings = LHCbDD4hepCnvSvc().getProp('SensDetMappings')
    mappings['VP'] = 'GiGaSensDetTrackerDD4hep/VPSDet'
    LHCbDD4hepCnvSvc().SensDetMappings = mappings

    # Add the necessary dd4hep includes for the VP. Also added all the
    # dependencies for material definitions that were identified using
    # trial and error. As the list is made unique before being added to
    # the xml this should be fine if they appear in multiple places
    from Gauss.Geometry import LHCbGeo
    go = LHCbGeo._listOfXMLIncludes_

    go += ["Pipe/parameters.xml"]
    go += ["Rich1/DetElem/RichRun3PropertySpecParam.xml"]
    go += ["Rich1/RichMatDir/RichMaterials.xml"]
    go += ["VP/parameters.xml"]
    go += ["VP/visualization.xml"]
    go += ["VP/detector.xml"]
    go += ["VP/conditions.xml"]

Check if extra modifications are needed

This is more as a reminder. You have to make sure that the extraction hits classes and monitoring classes are implemented or modernized. Moreover, some sub-detectors use non-standard classes that might need additional changes for the Detector/DD4hep implementation. This has to be checked.

Create a MR in Gauss targeting Futurev4 branch

Simply follow the same procedure as in: Developing Gauss-on-Gaussino.

Put the sub-detector in the nighlty and LHCbPR tests

Attention

The generic way of doing this is a work-in-progress.