2# ==================================================================
5# This module provides methods to compute the lifetime and
6# branching ratio of SUSY RPV neutralino given its mass and couplings as
9# Created: 30/04/2016 Konstantinos A. Petridis (konstantinos.petridis@cern.ch)
12# ipython -i rpvsusy.py
13# In [1]: b = RPVSYSY(1.,[1, 1],1e3,1,True)
14# HNLbranchings instance initialized with couplings:
15# \lambda_{production} = 1GeV
16# \lambda_{decay} = 1GeV
17# universal sfermion mass = 1e3GeV
20# 1 (values between 1 and 5)
23# In [2]: b.computeNLifetime()
24# Out[2]: 0.0219634078804
25# In [3]: b.findBranchingRatio('N -> K+ mu-')
26# Out[3]: 0.11826749348890987
28# ==================================================================
31from __future__
import division
32from __future__
import print_function
39pdg = ROOT.TDatabasePDG.Instance()
43 Trim particle name for use with the PDG database
45 if 'down' in particle:
return 'd'
46 if 'up' in particle:
return 'u'
47 if 'strange' in particle:
return 's'
48 if 'charm' in particle:
return 'c'
49 if 'bottom' in particle:
return 'b'
50 if 'beauty' in particle:
return 'b'
51 if 'top' in particle:
return 't'
53 particle = particle.replace(
'1',
"'")
54 if (
not ((
'-' in particle)
or (
'+' in particle)
or (
'0' in particle)
55 or (
'nu_' in particle)
or (
'eta' in particle)
or (
'phi' in particle) )
56 and (particle
not in [
'd',
'u',
's',
'c',
'b',
't'])):
62 Read particle ID from PDG database
64 particle = PDGname(particle)
65 tPart = pdg.GetParticle(particle)
66 return int(tPart.PdgCode())
70 Read particle mass from PDG database
72 particle = PDGname(particle)
73 tPart = pdg.GetParticle(particle)
78 Read particle width from PDG database
80 particle = PDGname(particle)
81 tPart = pdg.GetParticle(particle)
86 Read particle lifetime from PDG database
88 particle = PDGname(particle)
89 tPart = pdg.GetParticle(particle)
90 if particle==
"D0" or particle==
"D0bar" :
92 elif particle==
"D+" or particle==
"D-":
94 elif particle==
"D_s+" or particle==
"D_s-":
96 elif particle==
"B0" or particle==
"B0bar":
98 elif particle==
"B+" or particle==
"B-":
101 return tPart.Lifetime()
106 Store some constants useful for HNL physics
111 'K_L0':0.156/math.sqrt(2)*u.GeV,
112 'K_S0':0.156/math.sqrt(2)*u.GeV,
114 'K*0_bar':0.230*u.GeV,
120 'D+':0.205*u.GeV,
'D*+':0.205*u.GeV,
121 'D-':0.205*u.GeV,
'D*-':0.205*u.GeV,
122 'D_s+':0.259*u.GeV,
'D*_s+':0.259*u.GeV,
123 'D_s-':0.259*u.GeV,
'D*_s-':0.259*u.GeV,
124 'B+':0.191*u.GeV,
'B-':0.191*u.GeV,
125 'B0':0.191*u.GeV,
'B_s0':0.228*u.GeV,
126 'B0_bar':0.191*u.GeV,
'B_s0_bar':0.228*u.GeV}
128 self.
GF = 1.166379e-05/(u.GeV*u.GeV)
129 self.
MW = 80.385*u.GeV
133 self.
heV = 6.58211928*pow(10.,-16)
149 Lifetime and total and partial decay widths of an RPV neutralino
151 def __init__(self, mass, couplings, sfmass, benchmark,debug=False):
153 Initialize with mass and couplings of the RPV neutralino
157 which benchmark scenario (1,2,3,4,5)
158 couplings (list of [\lambda production, \lambda decay])
159 sfermion mass to normalise the couplings by (GeV)
163 self.
U2 = [ui*ui
for ui
in self.
U]
166 self.
decays = {1:[
'N -> K+ mu-',
'N -> K*+ mu-',
'N -> K*0 nu_mu',
'N -> K_L0 nu_mu',
'N -> K_S0 nu_mu'],
167 2:[
'N -> K+ mu-',
'N -> K*+ mu-',
'N -> K*0 nu_mu',
'N -> K_L0 nu_mu',
'N -> K_S0 nu_mu',
168 'N -> eta nu_mu',
'N -> eta\' nu_mu',
'N -> phi nu_mu'],
169 3:[
'N -> K+ mu-',
'N -> K*+ mu-',
'N -> K*0 nu_mu',
'N -> K_L0 nu_mu',
'N -> K_S0 nu_mu'],
170 4:[
'N -> D+ mu-',
'N -> D*+ mu-',
'N -> K*0 nu_mu',
'N -> K_L0 nu_mu',
'N -> K_S0 nu_mu'],
171 5:[
'N -> K+ tau-',
'N -> K*+ tau-',
'N -> K*0 nu_tau',
'N -> K_L0 nu_tau',
'N -> K_S0 nu_tau']}
177 5:[
'B0 -> N nu_tau',
'B+ -> N tau+']}
181 print(
"RPVSUSYbranchings instance initialized with couplings:")
182 print(
"\t benchmark scenario = %d"%self.
bench)
183 print(
"\t decay coupling = %s"%self.
U[0])
184 print(
"\t production coupling = %s"%self.
U[1])
185 print(
"\t sfermion mass = %s"%self.
sfmass)
186 print(
"\t total prod coupling = %s"%(self.
U[0]/self.
sfmass**2))
187 print(
"\t total decay coupling = %s"%(self.
U[1]/self.
sfmass**2))
189 print(
"\tm = %s GeV"%(self.
MN))
199 for decay
in decays_tmp:
201 decay_cpy = decay_cpy.replace(
"N -> ",
"")
202 particles = decay_cpy.split()
203 codes = [
PDGcode(p)
for p
in particles]
206 if any(
"K+" in s
for s
in particles)
or\
207 any(
"K-" in s
for s
in particles)
or\
208 any(
"K*+" in s
for s
in particles)
or\
209 any(
"K*-" in s
for s
in particles)
or\
210 any(
"K*0" in s
for s
in particles)
or\
211 any(
"K*0_bar" in s
for s
in particles):
213 P8Gen.SetParameters(
"9900015:addChannel = 1 {:.12} 0 {}"\
214 .format(bf,
' '.join(str(code)
for code
in codes)))
215 P8Gen.SetParameters(
"9900015:addChannel = 1 {:.12} 0 {}"\
216 .format(bf,
' '.join(str(-code)
for code
in codes)))
218 P8Gen.SetParameters(
"9900015:addChannel = 1 {:.12} 0 {}"\
219 .format(bf,
' '.join(str(code)
for code
in codes)))
221 print(
"debug readdecay table",particles,codes,bf)
227 Returns the RPV neutralino decay width into neutral meson and lepton
230 - H is a string (name of the meson)
231 - L is a string (name of the lepton)
233 if self.
MN < (mass(H)+mass(L)):
236 phsp=math.sqrt(self.
MN**4+mass(H)**4+mass(L)**4-\
237 2*self.
MN**2*mass(H)**2-2*self.
MN**2*mass(L)**2-\
238 2*mass(H)**2*mass(L)**2)
240 if 'nu_mu' in L
or 'nu_e' in L
or 'nu_tau' in L:
241 tmp_width = phsp/(self.
sfmass**4*128*u.pi*self.
MN**3)*\
242 c.GST2[
'sneutrino']*c.decayConstant[H]**2*\
243 (self.
MN**2+mass(L)**2-mass(H)**2)
245 tmp_width = phsp/(self.
sfmass**4*128*u.pi*self.
MN**3)*\
246 c.GST2[
'slepton']*c.decayConstant[H]**2*\
247 (self.
MN**2+mass(L)**2-mass(H)**2)
249 if 'K*' in H
or 'D*' in H
or "phi" in H:
250 if 'nu_mu' in L
or 'nu_e' in L
or 'nu_tau' in L:
251 tmp_width = phsp/(self.
sfmass**4*2*u.pi*self.
MN**3)*\
252 c.GST2[
'tneutrino']*c.decayConstant[H]**2*\
253 (2*(self.
MN**2-mass(L)**2)**2-mass(H)**2*(mass(H)**2+self.
MN**2+mass(L)**2))
255 tmp_width = phsp/(self.
sfmass**4*2*u.pi*self.
MN**3)*\
256 c.GST2[
'tlepton']*c.decayConstant[H]**2*\
257 (2*(self.
MN**2-mass(L)**2)**2-mass(H)**2*(mass(H)**2+self.
MN**2+mass(L)**2))
258 width=self.
U2[1]*tmp_width
260 if self.
bench==1
and (
'K_' in H
or 'K*' in H):
261 width=(self.
U2[0]+self.
U2[1])*tmp_width
263 if self.
bench==2
and (
'eta' in H
or 'phi' in H):
264 width=self.
U2[0]*tmp_width
273 Returns the Meson decay width to RPV neutralino and lepton
275 - H is a string (name of the meson)
276 - L is a string (name of the lepton)
279 if mass(H) < (self.
MN+mass(L)):
281 phsp=math.sqrt(self.
MN**4+mass(H)**4+mass(L)**4-\
282 2*self.
MN**2*mass(H)**2-2*self.
MN**2*mass(L)**2-\
283 2*mass(H)**2*mass(L)**2)
286 if 'nu_mu' in L
or 'nu_e' in L
or 'nu_tau' in L:
287 tmp_width = phsp/(self.
sfmass**4*64*u.pi*mass(H)**3)*\
288 c.GST2[
'sneutrino']*c.decayConstant[H]**2*\
289 (mass(H)**2-self.
MN**2-mass(L)**2)
291 tmp_width = phsp/(self.
sfmass**4*64*u.pi*mass(H)**3)*\
292 c.GST2[
'slepton']*c.decayConstant[H]**2*\
293 (mass(H)**2-self.
MN**2-mass(L)**2)
295 if 'K*' in H
or 'D*' in H
or "phi" in H:
296 if 'nu_mu' in L
or 'nu_e' in L
or 'nu_tau' in L:
297 tmp_width = phsp/(self.
sfmass**4*3*u.pi*mass(H)**3)*\
298 c.GST2[
'tneutrino']*c.decayConstant[H]**2*\
299 (mass(H)**2*(mass(H)**2+self.
MN**2+mass(L)**2-2*(self.
MN**2-mass(L)**2)**2))
301 tmp_width = phsp/(self.
sfmass**4*3*u.pi*mass(H)**3)*\
302 c.GST2[
'tlepton']*c.decayConstant[H]**2*\
303 (mass(H)**2*(mass(H)**2+self.
MN**2+mass(L)**2-2*(self.
MN**2-mass(L)**2)**2))
305 width=self.
U2[0]*tmp_width
313 Returns the total SUSYRPV neutralino decay width
316 hadlist = [re.search(
'->\ (.+?)\ ',dec).group(1)
for dec
in declist]
317 leplist = [dlist[1].strip()
for dlist
in [re.findall(
r"\ \w+",dec)
for dec
in declist]]
318 print(leplist,hadlist)
319 totalwidth = sum([self.
Width_H_L(hadlist[i],leplist[i])
for i
in range(0,len(hadlist))])
324 Returns the total SUSYRPV neutralino production width
327 hadlist = [re.search(
'(.+?)\ ->',dec).group(1)
for dec
in declist]
328 leplist = [dlist[1].strip()
for dlist
in [re.findall(
r"\ \w+",dec)
for dec
in declist]]
329 totalwidth = sum([self.
Width_N_L(hadlist[i],leplist[i])
for i
in range(0,len(hadlist))])
335 Returns the branching ratio of the selected SUSY RPV neutralino decay channel
338 - decayString is a string describing the decay, in the form 'N -> stuff1 ... stuffN'
340 had = re.search(
'->\ (.+?)\ ',decayString).group(1)
341 decaysplit = decayString.split(
' ')
342 for split
in decaysplit:
343 if split.find(
'mu')>-1
or split.find(
'e')>-1
or split.find(
'tau')>-1:
345 if had ==
'pi+' or had ==
'pi-' or had ==
'pi0':
346 print(
"findBranchingRatio() ERROR: Pions in final "\
347 "state have not been implemented, please choose "\
348 "a different decay mode of out...\n")
352 corrdecstring =
'N -> %s %s'%(had,lep)
355 print(
"findBranchingRation() INFO: "\
356 "You have chosen the decay: '",\
359 if corrdecstring
in dec:
362 print(
"findBranchingRation() ERROR: Badly "\
363 "formulated decay string, please choose "\
364 "one of the following\n")
377 Returns the branching ratio of the selected SUSY RPV neutralino product channel
380 - decayString is a string describing the decay, in the form 'H -> N ... stuffN'
382 had = re.search(
'(.+?)\ ->',decayString).group(1)
383 decaysplit = decayString.split(
' ')
384 for split
in decaysplit:
385 if split.find(
'mu')>-1
or split.find(
'e')>-1
or split.find(
'tau')>-1:
387 if had ==
'pi+' or had ==
'pi-' or had ==
'pi0':
388 print(
"findProdBranchingRatio() ERROR: Pions in final "\
389 "state have not been implemented, please choose "\
390 "a different decay mode of out...\n")
394 corrdecstring =
'%s -> N %s'%(had,lep)
397 print(
"findProdBranchingRation() INFO: "\
398 "You have chosen the decay: '",\
401 if corrdecstring
in dec:
404 print(
"findProdBranchingRation() ERROR: Badly "\
405 "formulated decay string, please choose "\
406 "one of the following\n")
415 SUSY RPV neutralino physics according to the nuMSM
417 def __init__(self, mass, couplings, sfmass, benchmark, debug=False):
419 Initialize with mass and couplings of the HNL
423 couplings (list of [\lambda_{production}^{2}, \lambda_{decay}^{2}])
424 mass of universal sfermion
425 which benchmark (integer between 1 and 5 inclusive)
427 RPVSUSYbranchings.__init__(self, mass, couplings, sfmass, benchmark, debug)
430 Compute the RPV neutralino lifetime
433 - system: choose between default (i.e. SI, result in s) or FairShip (result in ns)
439 if system ==
"FairShip": self.
NLifetime *= 1.e9
computeNLifetime(self, system="SI")
__init__(self, mass, couplings, sfmass, benchmark, debug=False)
__init__(self, mass, couplings, sfmass, benchmark, debug=False)
AddChannelsToPythia(self, P8Gen, verbose=True)
findDecayBranchingRatio(self, decayString)
findProdBranchingRatio(self, decayString)