File indexing completed on 2025-01-18 09:14:22
0001 """Helper object for physicslist properties"""
0002
0003 import os
0004
0005 from DDSim.Helper.ConfigHelper import ConfigHelper
0006 from g4units import mm
0007 import logging
0008
0009 logger = logging.getLogger(__name__)
0010
0011
0012 class Physics(ConfigHelper):
0013 """Configuration for the PhysicsList and Monte Carlo particle selection."""
0014
0015 def __init__(self):
0016 super(Physics, self).__init__()
0017 self._rangecut = 0.7 * mm
0018 self._list = "FTFP_BERT"
0019 self._decays = False
0020 self._pdgfile = None
0021 self._rejectPDGs = {1, 2, 3, 4, 5, 6,
0022 21, 23, 24, 25,
0023 1103,
0024 2101, 2103, 2203,
0025 3101, 3103, 3201, 3203, 3303,
0026 4101, 4103, 4201, 4203, 4301, 4303, 4403,
0027 5101, 5103, 5201, 5203, 5301, 5303, 5401, 5403, 5503}
0028 self._zeroTimePDGs = {11, 13, 15, 17}
0029 self._alternativeDecayStatuses = set()
0030 self._userFunctions = []
0031 self._closeProperties()
0032 Physics.__doc__ += "\n\n" + self.setupUserPhysics.__doc__
0033
0034 @property
0035 def rejectPDGs(self):
0036 """Set of PDG IDs that will not be passed from the input record to Geant4.
0037
0038 Quarks, gluons and W's Z's etc should not be treated by Geant4
0039 """
0040 return self._rejectPDGs
0041
0042 @rejectPDGs.setter
0043 def rejectPDGs(self, val):
0044 self._rejectPDGs = self.makeSet(val)
0045
0046 @property
0047 def zeroTimePDGs(self):
0048 """Set of PDG IDs for particles that should not be passed to Geant4 if their properTime is 0.
0049
0050 The properTime of 0 indicates a documentation to add FSR to a lepton for example.
0051 """
0052 return self._zeroTimePDGs
0053
0054 @zeroTimePDGs.setter
0055 def zeroTimePDGs(self, val):
0056 self._zeroTimePDGs = self.makeSet(val)
0057
0058 @property
0059 def alternativeDecayStatuses(self):
0060 """Set of Generator Statuses that are used to mark unstable particles that should decay inside of Geant4.
0061 """
0062 return self._alternativeDecayStatuses
0063
0064 @alternativeDecayStatuses.setter
0065 def alternativeDecayStatuses(self, val):
0066 self._alternativeDecayStatuses = self.makeSet(val)
0067
0068 @property
0069 def rangecut(self):
0070 """ The global geant4 rangecut for secondary production
0071
0072 Default is 0.7 mm as is the case in geant4 10
0073
0074 To disable this plugin and be absolutely sure to use the Geant4 default range cut use "None"
0075
0076 Set printlevel to DEBUG to see a printout of all range cuts,
0077 but this only works if range cut is not "None"
0078 """
0079 return self._rangecut
0080
0081 @rangecut.setter
0082 def rangecut(self, val):
0083 if val is None:
0084 self._rangecut = None
0085 return
0086 if isinstance(val, str):
0087 if val == "None":
0088 self._rangecut = None
0089 return
0090 self._rangecut = val
0091
0092 @property
0093 def pdgfile(self):
0094 """ location of particle.tbl file containing extra particles and their lifetime information
0095
0096 For example in $DD4HEP/examples/DDG4/examples/particle.tbl
0097 """
0098 return self._pdgfile
0099
0100 @pdgfile.setter
0101 def pdgfile(self, val):
0102 if not val:
0103 self._pdgfile = None
0104 return
0105 if not os.path.exists(val):
0106 raise RuntimeError("PDGFile: %s not found" % os.path.abspath(val))
0107 self._pdgfile = os.path.abspath(val)
0108
0109 @property
0110 def decays(self):
0111 """If true, add decay processes for all particles.
0112
0113 Only enable when creating a physics list not based on an existing Geant4 list!
0114 """
0115 return self._decays
0116
0117 @decays.setter
0118 def decays(self, val):
0119 self._decays = val
0120
0121 @property
0122 def list(self):
0123 """The name of the Geant4 Physics list."""
0124 return self._list
0125
0126 @list.setter
0127 def list(self, val):
0128 self._list = val
0129
0130 def setupPhysics(self, kernel, name=None):
0131 seq = kernel.physicsList()
0132 seq.extends = name if name is not None else self.list
0133 seq.decays = self.decays
0134 seq.enableUI()
0135 seq.dump()
0136
0137 from DDG4 import PhysicsList
0138
0139
0140 if self.pdgfile:
0141 seq = kernel.physicsList()
0142 part = PhysicsList(kernel, 'Geant4ExtraParticles/ExtraParticles')
0143 part.enableUI()
0144 seq.adopt(part)
0145 part.pdgfile = self.pdgfile
0146
0147
0148 if self.rangecut is not None:
0149 seq = kernel.physicsList()
0150 rg = PhysicsList(kernel, 'Geant4DefaultRangeCut/GlobalRangeCut')
0151 rg.enableUI()
0152 seq.adopt(rg)
0153 rg.RangeCut = self.rangecut
0154
0155 for func in self._userFunctions:
0156 try:
0157 func(kernel)
0158 except Exception as e:
0159 logger.error("Exception in UserFunction: %r", e)
0160 raise RuntimeError("Exception in UserFunction: %r" % e)
0161
0162 return seq
0163
0164 def setupUserPhysics(self, userFunction):
0165 """To load arbitrary plugins, add a function to be executed.
0166
0167 The function must take the DDG4.Kernel() object as the only argument.
0168
0169 For example, add a function definition and the call to a steering file::
0170
0171 def setupCerenkov(kernel):
0172 from DDG4 import PhysicsList
0173 seq = kernel.physicsList()
0174 cerenkov = PhysicsList(kernel, 'Geant4CerenkovPhysics/CerenkovPhys')
0175 cerenkov.MaxNumPhotonsPerStep = 10
0176 cerenkov.MaxBetaChangePerStep = 10.0
0177 cerenkov.TrackSecondariesFirst = True
0178 cerenkov.VerboseLevel = 2
0179 cerenkov.enableUI()
0180 seq.adopt(cerenkov)
0181 ph = PhysicsList(kernel, 'Geant4OpticalPhotonPhysics/OpticalGammaPhys')
0182 ph.addParticleConstructor('G4OpticalPhoton')
0183 ph.VerboseLevel = 2
0184 ph.enableUI()
0185 seq.adopt(ph)
0186 return None
0187
0188 SIM.physics.setupUserPhysics(setupCerenkov)
0189
0190 # End of example
0191 """
0192 self._userFunctions.append(userFunction)