Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-04 07:50:42

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 EXCEPTION_SEVERITY_DICT = {
0012     "0": 0,  # FatalException
0013     "1": 1,  # FatalErrorInArgument
0014     "2": 2,  # RunMustBeAborted
0015     "3": 3,  # EventMustBeAborted
0016     "4": 4,  # JustWarning
0017     "5": 5,  # IgnoreTheIssue
0018     "FatalException": 0,
0019     "FatalErrorInArgument": 1,
0020     "RunMustBeAborted": 2,
0021     "EventMustBeAborted": 3,
0022     "JustWarning": 4,
0023     "IgnoreTheIssue": 5,
0024     }
0025 
0026 
0027 class Physics(ConfigHelper):
0028   """Configuration for the PhysicsList and Monte Carlo particle selection."""
0029 
0030   def __init__(self):
0031     super(Physics, self).__init__()
0032     self._ETolerance = None
0033     self._ESeverity = None
0034     self._ESeverity_EXTRA = {'choices': list(EXCEPTION_SEVERITY_DICT.keys())}
0035     self._rangecut = 0.7 * mm
0036     self._list = "FTFP_BERT"
0037     self._decays = False
0038     self._pdgfile = None
0039     self._rejectPDGs = {1, 2, 3, 4, 5, 6,  # quarks
0040                         21, 23, 24, 25,  # bosons
0041                         1103,  # d? diquarks
0042                         2101, 2103, 2203,  # u? diquarks
0043                         3101, 3103, 3201, 3203, 3303,  # s? diquarks
0044                         4101, 4103, 4201, 4203, 4301, 4303, 4403,  # c? diquarks
0045                         5101, 5103, 5201, 5203, 5301, 5303, 5401, 5403, 5503}  # b? diquarks
0046     self._zeroTimePDGs = {11, 13, 15, 17}
0047     self._decayByGeant = set()
0048     self._alternativeDecayStatuses = set()
0049     self._alternativeStableStatuses = set()
0050     self._userFunctions = []
0051     self._closeProperties()
0052     Physics.__doc__ += "\n\n" + self.setupUserPhysics.__doc__
0053 
0054   @property
0055   def rejectPDGs(self):
0056     """Set of PDG IDs that will not be passed from the input record to Geant4.
0057 
0058     Quarks, gluons and W's Z's etc should not be treated by Geant4
0059     """
0060     return self._rejectPDGs
0061 
0062   @rejectPDGs.setter
0063   def rejectPDGs(self, val):
0064     self._rejectPDGs = self.makeSet(val)
0065 
0066   @property
0067   def zeroTimePDGs(self):
0068     """Set of PDG IDs for particles that should not be passed to Geant4 if their properTime is 0.
0069 
0070     The properTime of 0 indicates a documentation to add FSR to a lepton for example.
0071     """
0072     return self._zeroTimePDGs
0073 
0074   @zeroTimePDGs.setter
0075   def zeroTimePDGs(self, val):
0076     self._zeroTimePDGs = self.makeSet(val)
0077 
0078   @property
0079   def decayByGeant(self):
0080     """Set of PDG IDs for particles that should be decayed according to the lifetime.
0081 
0082     Lifetimes are either configured in Geant4 or particle.tbl instead of their pre-assigned decay time.
0083 
0084     """
0085     return self._decayByGeant
0086 
0087   @decayByGeant.setter
0088   def decayByGeant(self, val):
0089     self._decayByGeant = self.makeSet(val)
0090 
0091   @property
0092   def alternativeDecayStatuses(self):
0093     """Set of Generator Statuses that are used to mark unstable particles that should decay inside of Geant4.
0094     """
0095     return self._alternativeDecayStatuses
0096 
0097   @alternativeDecayStatuses.setter
0098   def alternativeDecayStatuses(self, val):
0099     self._alternativeDecayStatuses = self.makeSet(val)
0100 
0101   @property
0102   def alternativeStableStatuses(self):
0103     """Set of Generator Statuses that are used to mark stable particles that should be forwarded to Geant4.
0104     """
0105     return self._alternativeStableStatuses
0106 
0107   @alternativeStableStatuses.setter
0108   def alternativeStableStatuses(self, val):
0109     self._alternativeStableStatuses = self.makeSet(val)
0110 
0111   @property
0112   def rangecut(self):
0113     """ The global geant4 rangecut for secondary production
0114 
0115     Default is 0.7 mm as is the case in geant4 10
0116 
0117     To disable this plugin and be absolutely sure to use the Geant4 default range cut use "None"
0118 
0119     Set printlevel to DEBUG to see a printout of all range cuts,
0120     but this only works if range cut is not "None"
0121     """
0122     return self._rangecut
0123 
0124   @rangecut.setter
0125   def rangecut(self, val):
0126     if val is None:
0127       self._rangecut = None
0128       return
0129     if isinstance(val, str):
0130       if val == "None":
0131         self._rangecut = None
0132         return
0133     self._rangecut = val
0134 
0135   @property
0136   def pdgfile(self):
0137     """Location of particle.tbl file containing extra particles and their lifetime information
0138 
0139     For example in $DD4HEP/examples/DDG4/examples/particle.tbl
0140 
0141     This is a vital setting if you want to simulate secondary vertices or pre-assigned decays or both. Geant4 has to
0142     know about all particles with non-negligible lifetime. Use this setting together with alternativeStableStatuses and
0143     alternativeDecayStatuses, to configure the simulation to suit your MCGenerator file.
0144     """
0145     return self._pdgfile
0146 
0147   @pdgfile.setter
0148   def pdgfile(self, val):
0149     if not val:
0150       self._pdgfile = None
0151       return
0152     if not os.path.exists(val):
0153       raise RuntimeError("PDGFile: %s not found" % os.path.abspath(val))
0154     self._pdgfile = os.path.abspath(val)
0155 
0156   @property
0157   def decays(self):
0158     """If true, add decay processes for all particles.
0159 
0160     Only enable when creating a physics list not based on an existing Geant4 list!
0161     """
0162     return self._decays
0163 
0164   @decays.setter
0165   def decays(self, val):
0166     self._decays = val
0167 
0168   @property
0169   def list(self):  # noqa: A003
0170     """The name of the Geant4 Physics list."""
0171     return self._list
0172 
0173   @list.setter
0174   def list(self, val):  # noqa: A003
0175     self._list = val
0176 
0177   @property
0178   def ETolerance(self):
0179     """Configure the tolerance for the mass check of dynamic Particles, a.k.a, SetKETolerance
0180     """
0181     return self._ETolerance
0182 
0183   @ETolerance.setter
0184   def ETolerance(self, val):
0185     self._ETolerance = val
0186 
0187   @property
0188   def ESeverity(self):
0189     """Configure the severity for the mass check of dynamic Particles, a.k.a, SetKETolerance
0190     """
0191     return self._ESeverity
0192 
0193   @ESeverity.setter
0194   def ESeverity(self, val):
0195     if val is None:
0196       self._ESeverity = val
0197       return
0198     val = EXCEPTION_SEVERITY_DICT[str(val)]
0199     self._ESeverity = val
0200 
0201   def setupPhysics(self, kernel, name=None):
0202     seq = kernel.physicsList()
0203     seq.extends = name if name is not None else self.list
0204     seq.decays = self.decays
0205     seq.enableUI()
0206     seq.dump()
0207 
0208     from DDG4 import PhysicsList
0209 
0210     # Add special particle types from specialized physics constructor
0211     if self.pdgfile:
0212       seq = kernel.physicsList()
0213       part = PhysicsList(kernel, 'Geant4ExtraParticles/ExtraParticles')
0214       part.enableUI()
0215       seq.adopt(part)
0216       part.pdgfile = self.pdgfile
0217 
0218     # Add global range cut
0219     if self.rangecut is not None:
0220       seq = kernel.physicsList()
0221       rg = PhysicsList(kernel, 'Geant4DefaultRangeCut/GlobalRangeCut')
0222       rg.enableUI()
0223       seq.adopt(rg)
0224       rg.RangeCut = self.rangecut
0225 
0226     # Add setting of KETolerance
0227     if self._ETolerance is not None or self._ESeverity is not None:
0228       seq = kernel.physicsList()
0229       rg = PhysicsList(kernel, 'Geant4SetKETolerance/KETolerance')
0230       rg.enableUI()
0231       seq.adopt(rg)
0232       if self._ETolerance is not None:
0233         rg.Tolerance = self._ETolerance
0234       if self._ESeverity is not None:
0235         rg.Severity = self._ESeverity
0236 
0237     for func in self._userFunctions:
0238       try:
0239         func(kernel)
0240       except Exception as e:
0241         logger.error("Exception in UserFunction: %r", e)
0242         raise RuntimeError("Exception in UserFunction: %r" % e)
0243 
0244     return seq
0245 
0246   def setupUserPhysics(self, userFunction):
0247     """To load arbitrary plugins, add a function to be executed.
0248 
0249     The function must take the DDG4.Kernel() object as the only argument.
0250 
0251     For example, add a function definition and the call to a steering file::
0252 
0253       def setupCerenkov(kernel):
0254         from DDG4 import PhysicsList
0255         seq = kernel.physicsList()
0256         cerenkov = PhysicsList(kernel, 'Geant4CerenkovPhysics/CerenkovPhys')
0257         cerenkov.MaxNumPhotonsPerStep = 10
0258         cerenkov.MaxBetaChangePerStep = 10.0
0259         cerenkov.TrackSecondariesFirst = True
0260         cerenkov.VerboseLevel = 2
0261         cerenkov.enableUI()
0262         seq.adopt(cerenkov)
0263         ph = PhysicsList(kernel, 'Geant4OpticalPhotonPhysics/OpticalGammaPhys')
0264         ph.addParticleConstructor('G4OpticalPhoton')
0265         ph.VerboseLevel = 2
0266         ph.enableUI()
0267         seq.adopt(ph)
0268         return None
0269 
0270       SIM.physics.setupUserPhysics(setupCerenkov)
0271 
0272     # End of example
0273     """
0274     self._userFunctions.append(userFunction)