Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:14:22

0001 """Helper object for particle gun properties"""
0002 
0003 from DDSim.Helper.ConfigHelper import ConfigHelper
0004 from g4units import GeV
0005 from math import atan, exp
0006 import logging
0007 
0008 logger = logging.getLogger(__name__)
0009 
0010 
0011 class Gun(ConfigHelper):
0012   """Configuration for the DDG4 ParticleGun"""
0013 
0014   def __init__(self):
0015     super(Gun, self).__init__()
0016     self.particle = "mu-"
0017     self.multiplicity = 1
0018     self._position = (0.0, 0.0, 0.0)
0019     self._isotrop = False
0020     self._direction = (0, 0, 1)
0021 
0022     self._phiMin_EXTRA = {'help': "Minimal azimuthal angle for random distribution"}
0023     self.phiMin = None
0024     self._phiMax_EXTRA = {'help': "Maximal azimuthal angle for random distribution"}
0025     self.phiMax = None
0026     self._thetaMin_EXTRA = {'help': "Minimal polar angle for random distribution"}
0027     self.thetaMin = None
0028     self._thetaMax_EXTRA = {'help': "Maximal polar angle for random distribution"}
0029     self.thetaMax = None
0030     self._etaMin_EXTRA = {'help': "Minimal pseudorapidity for random distibution (overrides thetaMax)"}
0031     self.etaMin = None
0032     self._etaMax_EXTRA = {'help': "Maximal pseudorapidity for random distibution (overrides thetaMin)"}
0033     self.etaMax = None
0034     self._momentumMin_EXTRA = {'help': "Minimal momentum when using distribution (default = 0.0)"}
0035     self.momentumMin = 0 * GeV
0036     self._momentumMax_EXTRA = {'help': "Maximal momentum when using distribution (default = 0.0)"}
0037     self.momentumMax = 10 * GeV
0038     self._energy_EXTRA = {'help': "Total energy (including mass) for the particle gun.\n\n"
0039                           "If not None, it will overwrite the setting of momentumMin and momentumMax"}
0040     self.energy = None
0041 
0042     self._distribution_EXTRA = {'choices': ['uniform', 'cos(theta)',
0043                                             'eta', 'pseudorapidity',
0044                                             'ffbar']}  # (1+cos^2 theta)
0045     self._distribution = None
0046     self._closeProperties()
0047 
0048   @property
0049   def distribution(self):
0050     """choose the distribution of the random direction for theta
0051 
0052     Options for random distributions:
0053 
0054     'uniform' is the default distribution, flat in theta
0055     'cos(theta)' is flat in cos(theta)
0056     'eta', or 'pseudorapidity' is flat in pseudorapity
0057     'ffbar' is distributed according to 1+cos^2(theta)
0058 
0059     Setting a distribution will set isotrop = True
0060     """
0061     return self._distribution
0062 
0063   @distribution.setter
0064   def distribution(self, val):
0065     if val is None:
0066       return
0067     possibleDistributions = self._distribution_EXTRA['choices']
0068     if not isinstance(val, str):
0069       raise RuntimeError("malformed input '%s' for gun.distribution. Need a string : %s " %
0070                          (val, ",".join(possibleDistributions)))
0071     if val not in possibleDistributions:
0072       # surround options by quots to be explicit
0073       stringified = ["'%s'" % _ for _ in possibleDistributions]
0074       raise RuntimeError("Unknown distribution '%s', Use one of: %s " % (val,
0075                                                                          ", ".join(stringified)))
0076     self._distribution = val
0077     self._isotrop = True
0078 
0079   @property
0080   def isotrop(self):
0081     """ isotropic distribution for the particle gun
0082 
0083     use the options phiMin, phiMax, thetaMin, and thetaMax to limit the range of randomly distributed directions
0084     if one of these options is not None the random distribution will be set to True and cannot be turned off!
0085     """
0086     return self._isotrop or bool(self._distribution)
0087 
0088   @isotrop.setter
0089   def isotrop(self, val):
0090     """check that value is equivalent to bool"""
0091     try:
0092       self._isotrop = ConfigHelper.makeBool(val)
0093     except RuntimeError:
0094       raise RuntimeError("malformed input '%s' for gun.isotrop " % val)
0095     if val and self.distribution is None:
0096       self.distribution = 'uniform'
0097 
0098   @property
0099   def direction(self):
0100     """ direction of the particle gun, 3 vector """
0101     return self._direction
0102 
0103   @direction.setter
0104   def direction(self, val):
0105     """ make sure the direction is parseable by boost, i.e. (1.0, 1.0, 1.0) """
0106     self._direction = ConfigHelper.makeTuple(val)
0107     if len(self._direction) != 3:
0108       raise RuntimeError(
0109           " gun.direction: malformed input '%s', needs to be a string representing a three vector " % (val,))
0110 
0111   @property
0112   def position(self):
0113     """ position of the particle gun, 3 vector """
0114     return self._position
0115 
0116   @position.setter
0117   def position(self, val):
0118     """check that the position is a three vector and can be parsed by ddg4"""
0119     self._position = ConfigHelper.makeTuple(val)
0120     if len(self._position) != 3:
0121       raise RuntimeError(
0122           " gun.position: malformed input '%s', needs to be a string representing a three vector " % (val,))
0123 
0124   def setOptions(self, ddg4Gun):
0125     """set the starting properties of the DDG4 particle gun"""
0126     try:
0127       if self.energy:
0128         ddg4Gun.Energy = self.energy
0129       ddg4Gun.particle = self.particle
0130       ddg4Gun.multiplicity = self.multiplicity
0131       ddg4Gun.position = self.position
0132       ddg4Gun.isotrop = self.isotrop
0133       ddg4Gun.direction = self.direction
0134       ddg4Gun.Distribution = self.distribution
0135       if self.thetaMin is not None:
0136         ddg4Gun.ThetaMin = self.thetaMin
0137         ddg4Gun.isotrop = True
0138       if self.thetaMax is not None:
0139         ddg4Gun.ThetaMax = self.thetaMax
0140         ddg4Gun.isotrop = True
0141       if self.phiMin is not None:
0142         ddg4Gun.PhiMin = self.phiMin
0143         ddg4Gun.isotrop = True
0144       if self.phiMax is not None:
0145         ddg4Gun.PhiMax = self.phiMax
0146         ddg4Gun.isotrop = True
0147       if self.etaMin is not None:
0148         ddg4Gun.ThetaMax = 2. * atan(exp(-float(self.etaMin)))
0149         ddg4Gun.isotrop = True
0150       if self.etaMax is not None:
0151         ddg4Gun.ThetaMin = 2. * atan(exp(-float(self.etaMax)))
0152         ddg4Gun.isotrop = True
0153       # this avoids issues if momentumMin is None because of previous default
0154       ddg4Gun.MomentumMin = self.momentumMin if self.momentumMin else 0.0
0155       ddg4Gun.MomentumMax = self.momentumMax
0156     except Exception as e:  # pylint: disable=W0703
0157       logger.error("parsing gun options:\n%s\nException: %s " % (self, e))
0158       exit(1)