create_neutrino_nucleon_file.py
Go to the documentation of this file.
1 # Author: M. Reichert
2 # Date : 11.04.2023
3 import numpy as np
4 import matplotlib.pyplot as plt
5 import scipy.constants as const
6 from scipy.integrate import quad
7 
8 
9 class nunucleon(object):
10 
11  def __init__(self):
12  """
13  Class to calculate the charged particle neutrino-nucleon cross sections
14  and average cross sections.
15  """
16 
17  # Define constants
18  self.MeV2erg = 1.60218e-6 # Conversion MeV -> Erg
19  self.mec2 = 0.510998910e0 # MeV
20  self.mnc2 = 939.56533e0 # MeV
21  self.mpc2 = 938.271998e0 # MeV
22  self.Gf = 1.436e-49 # erg/ccm
23  self.c = const.c*100 # cm/s
24  self.hbar = const.hbar*1e7 # erg*s
25  self.ga = 1.26 # Axial vector coupling constant
26 
27  # Energy difference between neutron and proton
28  self.Dnp = self.mnc2-self.mpc2
29 
30  # Define constants as in Horowitz 2002
31  self.cv = 1
32  self.ca = self.ga
33  self.F2 = 3.706
34 
35  # Calculate sigma 0. Equation 9 of Burrows 2006
36  self.sigma_0 = 4*self.Gf**2*(self.mec2*self.MeV2erg)**2/((self.c*self.hbar)**4*np.pi)
37 
38  # Define the temperature Grid that is used in WinNet
39  self.T_grid = np.array([2.8e0,3.5e0,4.0e0,5.0e0,6.4e0,8.0e0,10.0e0])
40 
41 
42  def __cor(self,E,nu):
43  """
44  Correction for weak magnetism and recoil according to Horowitz 2002
45  (https://ui.adsabs.harvard.edu/abs/2002PhRvD..65d3001H/abstract, Equation 22).
46  """
47  # Make the constant writing a bit shorter
48  cv = self.cv
49  ca = self.ca
50  F2 = self.F2
51 
52  # Express energy in units of mnc2
53  E = E/self.mnc2
54 
55  # Equation 22 in Horowitz 2002
56  R = cv**2*(1+4*E+16/3.*E**2)+3*ca**2*(1+4/3*E)**2
57  # Difference between neutrino and antineutrino
58  if nu:
59  R = R + 4*(cv+F2)*ca*E*(1+4/3*E)
60  else:
61  R = R - 4*(cv+F2)*ca*E*(1+4/3*E)
62  R = R + 8/3*cv*F2*E**2
63  R = R+5/3*E**2*(1+2/5*E)*F2**2
64  # Calculate denominator
65  denom = ((cv**2+3*ca**2)*(1+2*E)**3)
66 
67  R = R/denom
68 
69  return R
70 
71  def sigma_nu_n(self,E):
72  """
73  Calculate the electron neutrino cross section according to Equation 10 of
74  Burrows et al. 2006 (https://ui.adsabs.harvard.edu/abs/2006NuPhA.777..356B/abstract).
75  Outputs the cross section in 10^42 cm^2.
76  """
77  res = self.sigma_0*1e42*((1+3*self.ga**2)/4.)*((E+self.Dnp)/self.mec2)**2
78  res = res * (1-(self.mec2/(E+self.Dnp))**2.0)**(0.5)*self.WM(E,0)
79  return res
80 
81  def WM(self,E,mode=0):
82  """
83  Weak magnetism and recoil corrections.
84  Mode 0 returns a higher order of this correction according to Horowitz 2002,
85  mode 1 returns a simplified value of Burrows et al. 2006.
86  """
87  if mode==0:
88  res = self.__cor(E,True)
89  elif mode==1:
90  res = 1+1.1*E/self.mnc2
91  else:
92  raise ValueError("Mode not defined!")
93 
94  return res
95 
96 
97  def sigma_anu_p(self,E):
98  """
99  Calculate the electron anti neutrino cross section according to Equation 11 of
100  Burrows et al. 2006 (https://ui.adsabs.harvard.edu/abs/2006NuPhA.777..356B/abstract).
101  Outputs the cross section in 10^42 cm^2.
102  """
103  res = self.sigma_0*1e42*((1+3*self.ga**2)/4.)*((E-self.Dnp)/self.mec2)**2
104  res = res * (1-(self.mec2/(E-self.Dnp))**2.0)**(0.5)*self.WMbar(E,0)
105 
106  return res
107 
108 
109  def WMbar(self,E,mode=0):
110  """
111  Weak magnetism and recoil corrections.
112  Mode 0 returns a higher order of this correction according to Horowitz 2002,
113  mode 1 returns a simplified value of Burrows et al. 2006.
114  """
115  if mode==0:
116  res = self.__cor(E,False)
117  elif mode==1:
118  res = 1-7.1*E/self.mnc2
119  else:
120  raise ValueError("Mode not defined!")
121 
122  return res
123 
124 
125  def Fermi_Dirac(self,E,T):
126  """
127  Calculate the Fermi-Dirac distribution.
128  """
129  res = E**2/(1+np.exp(E/T))
130  return res
131 
132 
133  def sigma_avg_nu_n(self,T):
134  """
135  Calculate the average neutrino cross section:
136  nu_e + n -> e + p
137  The average neutrino cross section is calculated according
138  to the integral of the cross sections multiplied by the normalized
139  Fermi-Dirac distribution.
140  """
141  integrand = lambda E: self.sigma_nu_n(E) * self.Fermi_Dirac(E, T)
142  result, _ = quad(integrand, 0, np.inf)
143 
144  # Integrate the Fermi-Dirac distribution for the normalization
145  integrand = lambda E: self.Fermi_Dirac(E, T)
146  result2, _ = quad(integrand, 0, np.inf)
147 
148  return result/result2
149 
150  def averageE_nu_n(self,T):
151  """
152  Calculate the average energy of the absorped neutrino for the reaction:
153  nu_e + n -> e + p
154  """
155  integrand = lambda E: self.sigma_nu_n(E) * self.Fermi_Dirac(E, T)*E
156  result, _ = quad(integrand, 0, np.inf)
157 
158  integrand = lambda E: self.Fermi_Dirac(E, T)
159  result2, _ = quad(integrand, 0, np.inf)
160 
161  result3 = self.sigma_avg_nu_n(T)
162  return (result/result2)/result3
163 
164 
165  def averageE_anu_p(self,T):
166  """
167  Calculate the average energy of the absorped neutrino for the reaction:
168  bar(nu)_e + p -> n + positron
169  """
170  integrand = lambda E: self.sigma_anu_p(E) * self.Fermi_Dirac(E, T)*E
171  result, _ = quad(integrand, self.Dnp+self.mec2, np.inf)
172 
173  integrand = lambda E: self.Fermi_Dirac(E, T)
174  result2, _ = quad(integrand, self.Dnp+self.mec2, np.inf)
175 
176  result3 = self.sigma_avg_anu_p(T)
177  return (result/result2)/result3
178 
179 
180  def sigma_avg_anu_p(self,T):
181  """
182  Calculate the average neutrino cross section:
183  bar(nu)_e + p -> n + positron
184  The average neutrino cross section is calculated according
185  to the integral of the cross sections multiplied by the normalized
186  Fermi-Dirac distribution.
187  """
188  integrand = lambda E: self.sigma_anu_p(E) * self.Fermi_Dirac(E, T)
189  result, _ = quad(integrand, self.Dnp+self.mec2, np.inf)
190 
191  # Integrate the Fermi-Dirac distribution for the normalization
192  integrand = lambda E: self.Fermi_Dirac(E, T)
193  result2, _ = quad(integrand, self.Dnp+self.mec2, np.inf)
194  return result/result2
195 
196 
197  def create_WinNet_file_cross_section(self,file_name):
198  """
199  Create the WinNet file with the calculated cross sections
200  and the average energy of the absorped neutrino.
201  """
202  # The temperature grid that is used in WinNet
203  Tgrid = self.T_grid
204 
205  # Create a line in the correct format, note that also
206  # the source label is important here.
207  out = " n p nen"+"\n"
208  # Calculate and write the neutrino cross sections
209  line = ""
210  for ind,T in enumerate(Tgrid):
211  line += "{:6.2f}".format(self.sigma_avg_nu_n(T))+" "
212  line = line.rstrip()
213  out += line+"\n"
214  # Calculate and write the average energy of the absorped neutrino
215  line = ""
216  for ind,T in enumerate(Tgrid):
217  line += "{:6.2f}".format(self.averageE_nu_n(T))+" "
218  line = line.rstrip()
219  out += line+"\n"
220 
221  out += " p n nebp"+"\n"
222  line = ""
223  for ind,T in enumerate(Tgrid):
224  line += "{:6.2f}".format(self.sigma_avg_anu_p(T))+" "
225  line = line.rstrip()
226  out += line+"\n"
227  # Calculate and write the average energy of the absorped neutrino
228  line = ""
229  for ind,T in enumerate(Tgrid):
230  line += "{:6.2f}".format(self.averageE_anu_p(T))+" "
231  line = line.rstrip()
232  out += line+"\n"
233 
234  # Save the file
235  with open(file_name,"w") as f:
236  f.write(out)
237 
238 
239 
240 if __name__ == "__main__":
241  """
242  Create the cross section file when executing this script.
243  Furthermore, plot the cross sections for a range of temperatures.
244  """
245  # File name to save the cross sections and average energies of absorbed neutrinos
246  filename_crosssection = "neunucleons.dat"
247  # Create an instance of the class
248  n_class = nunucleon()
249  n_class.create_WinNet_file_cross_section(filename_crosssection)
250 
251  # Prepare everything for plotting
252  fig = plt.figure(figsize=(5,3))
253 
254  # Create a range of neutrino temperatures
255  # and calculate the cross sections
256  n_temp = 100
257  T_more = np.linspace(2,13.0,n_temp)
258  nu = np.zeros(n_temp)
259  anu = np.zeros(n_temp)
260  for ind,T in enumerate(T_more):
261  nu[ind] = n_class.sigma_avg_nu_n(T)
262  anu[ind] = n_class.sigma_avg_anu_p(T)
263 
264  # Plot them
265  plt.plot(T_more,nu,label=r"$\nu_e n$")
266  plt.plot(T_more,anu,label=r"$\bar{\nu}_e p$")
267 
268  # Now the same for the Grid that is used in WinNet
269  Tgrid = np.array([2.8e0,3.5e0,4.0e0,5.0e0,6.4e0,8.0e0,10.0e0])
270  nu = np.zeros(len(Tgrid))
271  anu = np.zeros(len(Tgrid))
272  for ind,T in enumerate(Tgrid):
273  nu[ind] = n_class.sigma_avg_nu_n(T)
274  anu[ind] = n_class.sigma_avg_anu_p(T)
275 
276  # Also plot this
277  plt.scatter(Tgrid,nu,facecolors='none',edgecolors='k')
278  plt.scatter(Tgrid,anu,facecolors='none',edgecolors='k')
279 
280  # Make the axis more pretty
281  plt.xlabel("T [MeV]")
282  plt.ylabel(r"$<\sigma> (10^{-42}$ cm$^2)$")
283  plt.legend()
284  plt.tight_layout()
285  # Show the plot
286  plt.show()
bin.create_neutrino_nucleon_file.nunucleon.__cor
def __cor(self, E, nu)
Definition: create_neutrino_nucleon_file.py:42
bin.create_neutrino_nucleon_file.nunucleon.sigma_0
sigma_0
Definition: create_neutrino_nucleon_file.py:36
bin.create_neutrino_nucleon_file.nunucleon.sigma_nu_n
def sigma_nu_n(self, E)
Definition: create_neutrino_nucleon_file.py:71
bin.create_neutrino_nucleon_file.nunucleon.create_WinNet_file_cross_section
def create_WinNet_file_cross_section(self, file_name)
Definition: create_neutrino_nucleon_file.py:197
bin.create_neutrino_nucleon_file.nunucleon.averageE_anu_p
def averageE_anu_p(self, T)
Definition: create_neutrino_nucleon_file.py:165
bin.create_neutrino_nucleon_file.nunucleon.c
c
Definition: create_neutrino_nucleon_file.py:23
bin.create_neutrino_nucleon_file.nunucleon.ga
ga
Definition: create_neutrino_nucleon_file.py:25
bin.create_neutrino_nucleon_file.nunucleon.sigma_avg_nu_n
def sigma_avg_nu_n(self, T)
Definition: create_neutrino_nucleon_file.py:133
bin.create_neutrino_nucleon_file.nunucleon.WMbar
def WMbar(self, E, mode=0)
Definition: create_neutrino_nucleon_file.py:109
bin.create_neutrino_nucleon_file.nunucleon.averageE_nu_n
def averageE_nu_n(self, T)
Definition: create_neutrino_nucleon_file.py:150
bin.create_neutrino_nucleon_file.nunucleon.Gf
Gf
Definition: create_neutrino_nucleon_file.py:22
bin.create_neutrino_nucleon_file.nunucleon.mec2
mec2
Definition: create_neutrino_nucleon_file.py:19
bin.create_neutrino_nucleon_file.nunucleon.hbar
hbar
Definition: create_neutrino_nucleon_file.py:24
bin.create_neutrino_nucleon_file.nunucleon.cv
cv
Definition: create_neutrino_nucleon_file.py:31
bin.create_neutrino_nucleon_file.nunucleon.sigma_avg_anu_p
def sigma_avg_anu_p(self, T)
Definition: create_neutrino_nucleon_file.py:180
bin.create_neutrino_nucleon_file.nunucleon.__init__
def __init__(self)
Definition: create_neutrino_nucleon_file.py:11
bin.create_neutrino_nucleon_file.nunucleon.T_grid
T_grid
Definition: create_neutrino_nucleon_file.py:39
bin.create_neutrino_nucleon_file.nunucleon.sigma_anu_p
def sigma_anu_p(self, E)
Definition: create_neutrino_nucleon_file.py:97
bin.create_neutrino_nucleon_file.nunucleon.MeV2erg
MeV2erg
Definition: create_neutrino_nucleon_file.py:18
bin.create_neutrino_nucleon_file.nunucleon.F2
F2
Definition: create_neutrino_nucleon_file.py:33
bin.create_neutrino_nucleon_file.nunucleon
Definition: create_neutrino_nucleon_file.py:9
bin.create_neutrino_nucleon_file.nunucleon.mnc2
mnc2
Definition: create_neutrino_nucleon_file.py:20
bin.create_neutrino_nucleon_file.nunucleon.WM
def WM(self, E, mode=0)
Definition: create_neutrino_nucleon_file.py:81
bin.create_neutrino_nucleon_file.nunucleon.mpc2
mpc2
Definition: create_neutrino_nucleon_file.py:21
bin.create_neutrino_nucleon_file.nunucleon.ca
ca
Definition: create_neutrino_nucleon_file.py:32
bin.create_neutrino_nucleon_file.nunucleon.Dnp
Dnp
Definition: create_neutrino_nucleon_file.py:28
bin.create_neutrino_nucleon_file.nunucleon.Fermi_Dirac
def Fermi_Dirac(self, E, T)
Definition: create_neutrino_nucleon_file.py:125