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']}
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
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
0154 ddg4Gun.MomentumMin = self.momentumMin if self.momentumMin else 0.0
0155 ddg4Gun.MomentumMax = self.momentumMax
0156 except Exception as e:
0157 logger.error("parsing gun options:\n%s\nException: %s " % (self, e))
0158 exit(1)