Source code for ParallelGeometry.Configuration

###############################################################################
# (c) Copyright 2021 CERN for the benefit of the LHCb Collaboration           #
#                                                                             #
# This software is distributed under the terms of the GNU General Public      #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
#                                                                             #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization  #
# or submit itself to any jurisdiction.                                       #
###############################################################################
from Gaudi.Configuration import ConfigurableUser
from Gaudi.Configuration import log
import Configurables

__author__ = "Michal Mazurek"
__email__ = "michal.mazurek@cern.ch"


[docs]class ParallelGeometry(ConfigurableUser): """This class sets up external detectors (from ``ExternalDetector`` package) in parallel worlds on top of mass geometry. This can be used in studies where we would like to have volumes / sensitive detectors overlapping each other. :var ParallelWorlds: Properties of the parallel worlds (there can be more than one parallel world). :vartype ParallelWorlds: dict, required :var ParallelPhysics: Properties of the physics factories that add a special behaviour of the particles tracked in the parallel worlds. :vartype ParallelPhysics: dict, required .. note:: Note! Make sure that all your detectors have materials if you want to export a GDML ( in parallel geometry volumes do not have have materials defined) i.e. material != nullptr, as G4GDMLParser will most likely crash :Example: .. highlight:: python .. code-block:: python from Configurables import ParallelGeometry ParallelGeometry().ParallelWorlds = { 'ParallelWorld1': { 'ExternalDetectorEmbedder': 'ParallelEmbedder', 'ExportGDML': { 'GDMLFileName': 'ParallelWorld1.gdml', 'GDMLFileNameOverwrite': True, 'GDMLExportSD': True, 'GDMLExportEnergyCuts': True, }, }, } ParallelGeometry().ParallelPhysics = { 'ParallelWorld1': { 'LayeredMass': False, # -> False = see material of the world below in stack 'ParticlePIDs': [22], # -> empty means track all particles }, } # then define ParallelEmbedder as in the ``ExternalDetector`` # section """ __slots__ = { "ParallelWorlds": {}, # # # Note! Make sure that all your detectors have materials # if you want to export a GDML # i.e. material != nullptr, as G4GDMLParser will most likely crash # # ex. { # "ParWorld1": { # "Type": "DefaultWorld", # default # "ExternalDetectorEmbedder": "ExtDetEmb1", # "CustomSimulation": "MyCustomSimCreator", # "ExportGDML: { # 'GDMLFileName': 'ParWorld1.gdml', # 'GDMLFileNameOverwrite': True, # 'GDMLExportSD': True, # 'GDMLExportEnergyCuts': True, # }, # }, # }, # "ParallelPhysics": {}, # # ex. { # "ParWorld1": { # "Type": "DefaultParallelPhysics", # default # "LayeredMass": "", # default # }, # }, } _external_embedders = []
[docs] def attach(self, dettool): """Takes care of setting up the right tools and factories responsible for the parallel geometries as defined in ``ParallelWorlds`` property. :param dettool: Detector construction tool, should be ``GiGaMTDetectorConstructionFAC`` """ algs = [] worlds = self.getProp("ParallelWorlds") if type(worlds) is dict: par_worlds_tools = [] for world_name, props in worlds.items(): self._check_props(world_name, props) factype = props.get("Type") if not factype: log.warning( "No factory type specified for {}. Using default world factory".format( world_name ) ) factype = "DefaultParallelWorld" fac_conf = getattr(Configurables, factype) fac = fac_conf( world_name, **self._refine_props( props, [ "Type", "ExternalDetectorEmbedder", "CustomSimulation", "ExportGDML", ], ) ) embedder_name = props.get("ExternalDetectorEmbedder") if embedder_name: from Configurables import ExternalDetectorEmbedder embedder = ExternalDetectorEmbedder(embedder_name) embedder.embed(fac) algs += embedder.activate_hits_alg() # no slot for now! algs += embedder.activate_moni_alg() # no slot for now! self._external_embedders.append(embedder_name) # Add custom simulation models for parallel geometry cust_sim_creator_name = props.get("CustomSimulation") if cust_sim_creator_name: from Configurables import CustomSimulation CustomSimulation(cust_sim_creator_name).create(fac) # Save as a GDML File gdml_export = props.get("ExportGDML") if gdml_export: if type(gdml_export) is not dict: raise RuntimeError( "ExportGDML should be a dictionary of options" ) else: for name, value in gdml_export.items(): if name.startswith("GDML"): setattr(fac, name, value) else: raise RuntimeError("GDML options start with GDML") dettool.addTool(fac, name=world_name) par_worlds_tools.append(getattr(dettool, world_name)) dettool.ParallelWorlds = par_worlds_tools return algs
[docs] def attach_physics(self, modular_list): """Takes care of setting up the right tools and factories responsible for the parallel physics factories that correspond to the parallel worlds. All these properties should be provided in ``ParallelPhysics`` property. :param modular_list: Modular physics list tool, should be ``GiGaMTModularPhysListFAC`` """ physics = self.getProp("ParallelPhysics") if type(physics) is dict: for world_name, phys_props in physics.items(): name = world_name + "Physics" self._check_props(name, phys_props) factype = phys_props.get("Type") factype = "DefaultParallelPhysics" if not factype: log.warning( "No factory type specified for {}. Using default physics world factory".format( world_name ) ) factype = "DefaultParallelPhysics" if factype == "DefaultParallelPhysics": phys_props["WorldName"] = world_name fac_conf = getattr(Configurables, factype) pwph = fac_conf(name, **self._refine_props(phys_props)) modular_list.addTool(pwph) modular_list.PhysicsConstructors.append(getattr(modular_list, name)) # Add custom simulation physics in the parallel world cust_sim_creator_name = self.getProp("ParallelWorlds")[world_name].get( "CustomSimulation" ) if cust_sim_creator_name: from Configurables import CustomSimulation CustomSimulation(cust_sim_creator_name).attach_physics( modular_list, world_name )
[docs] def _refine_props(self, props, keys_to_refine=["Type"]): return {key: prop for key, prop in props.items() if key not in keys_to_refine}
[docs] def _check_props(self, name, props): if type(props) is not dict: raise RuntimeError( "ERROR: Dictionary of {} properties not provided.".format(name) )