forked from CRPropa/CRPropa3-data
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalc_electromagnetic.py
154 lines (124 loc) · 5.3 KB
/
calc_electromagnetic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from __future__ import division
import numpy as np
import interactionRate
import photonField
import os
eV = 1.60217657E-19 # [J]
me2 = (510.998918E3 * eV)**2 # squared electron mass [J^2/c^4]
sigmaThompson = 6.6524E-29 # Thompson cross section [m^2]
alpha = 1 / 137.035999074 # fine structure constant
def sigmaPP(s):
""" Pair production cross section (Bethe-Heitler), see Lee 1996 """
smin = 4 * me2
if (s < smin):
return 0
else:
b = np.sqrt(1 - smin / s)
return sigmaThompson * 3 / 16 * (1 - b**2) * ((3 - b**4) * np.log((1 + b) / (1 - b)) - 2 * b * (2 - b**2))
def sigmaDPP(s):
""" Double-pair production cross section, see R.W. Brown eq. (4.5) with k^2 = q^2 = 0 """
smin = 16 * me2
if (s < smin):
return 0
else:
return 6.45E-34 * (1 - smin / s)**6
def sigmaICS(s):
""" Inverse Compton scattering cross sections, see Lee 1996 """
smin = me2
if (s < smin): # numerically unstable close to smin
return 0
else:
# note: formula unstable for (s - smin) / smin < 1E-5
b = (s - smin) / (s + smin)
A = 2 / b / (1 + b) * (2 + 2 * b - b**2 - 2 * b**3)
B = (2 - 3 * b**2 - b**3) / b**2 * np.log((1 + b) / (1 - b))
return sigmaThompson * 3 / 8 * smin / s / b * (A - B)
def sigmaTPP(s):
""" Triplet-pair production cross section, see Lee 1996 """
beta = 28 / 9 * np.log(s / me2) - 218 / 27
if beta < 0:
return 0
else:
return sigmaThompson * 3 / 8 / np.pi * alpha * beta
def getTabulatedXS(sigma, skin):
""" Get crosssection for tabulated s_kin """
if sigma in (sigmaPP, sigmaDPP): # photon interactions
return np.array([sigma(s) for s in skin])
if sigma in (sigmaTPP, sigmaICS): # electron interactions
return np.array([sigma(s) for s in skin + me2])
return False
def getSmin(sigma):
""" Return minimum required s_kin = s - (mc^2)^2 for interaction """
return {sigmaPP: 4 * me2,
sigmaDPP: 16 * me2,
sigmaTPP: np.exp((218 / 27) / (28 / 9)) * me2 - me2,
sigmaICS: 1E-9 * me2
}[sigma]
def getEmin(sigma, field):
""" Return minimum required cosmic ray energy for interaction *sigma* with *field* """
return getSmin(sigma) / 4 / field.getEmax()
def process(sigma, field, name):
# output folder
folder = 'data/' + name
if not os.path.exists(folder):
os.makedirs(folder)
# tabulated energies, limit to energies where the interaction is possible
Emin = getEmin(sigma, field)
E = np.logspace(10, 23, 261) * eV
E = E[E > Emin]
# -------------------------------------------
# calculate interaction rates
# -------------------------------------------
# tabulated values of s_kin = s - mc^2
# Note: integration method (Romberg) requires 2^n + 1 log-spaced tabulation points
s_kin = np.logspace(6, 23, 2049) * eV**2
xs = getTabulatedXS(sigma, s_kin)
rate = interactionRate.calc_rate_s(s_kin, xs, E, field)
# save
fname = folder + '/rate_%s.txt' % field.name
data = np.c_[np.log10(E / eV), rate]
fmt = '%.2f\t%.6g'
header = '%s interaction rates\nphoton field: %s\nlog10(E/eV), 1/lambda [1/Mpc]' % (name, field.info)
np.savetxt(fname, data, fmt=fmt, header=header)
# -------------------------------------------
# calculate cumulative differential interaction rates for sampling s values
# -------------------------------------------
# find minimum value of s_kin
skin1 = getSmin(sigma) # s threshold for interaction
skin2 = 4 * field.getEmin() * E[0] # minimum achievable s in collision with background photon (at any tabulated E)
skin_min = max(skin1, skin2)
# tabulated values of s_kin = s - mc^2, limit to relevant range
# Note: use higher resolution and then downsample
skin = np.logspace(6.2, 23, 1680 + 1) * eV**2
skin = skin[skin > skin_min]
xs = getTabulatedXS(sigma, skin)
rate = interactionRate.calc_rate_s(skin, xs, E, field, cdf=True)
# downsample
skin_save = np.logspace(6.2, 23, 168 + 1) * eV**2
skin_save = skin_save[skin_save > skin_min]
rate_save = np.array([np.interp(skin_save, skin, r) for r in rate])
# save
data = np.c_[np.log10(E / eV), rate_save] # prepend log10(E/eV) as first column
row0 = np.r_[0, np.log10(skin_save / eV**2)][np.newaxis]
data = np.r_[row0, data] # prepend log10(s_kin/eV^2) as first row
fname = folder + '/cdf_%s.txt' % field.name
fmt = '%.2f' + '\t%.6g' * np.shape(rate_save)[1]
header = '%s cumulative differential rate\nphoton field: %s\nlog10(E/eV), d(1/lambda)/ds_kin [1/Mpc/eV^2] for log10(s_kin/eV^2) as given in first row' % (name, field.info)
np.savetxt(fname, data, fmt=fmt, header=header)
fields = [
photonField.CMB(),
photonField.EBL_Kneiske04(),
photonField.EBL_Stecker05(),
photonField.EBL_Franceschini08(),
photonField.EBL_Finke10(),
photonField.EBL_Dominguez11(),
photonField.EBL_Gilmore12(),
photonField.EBL_Stecker16('lower'),
photonField.EBL_Stecker16('upper'),
photonField.URB_Protheroe96()]
for field in fields:
print(field.name)
process(sigmaPP, field, 'EMPairProduction')
process(sigmaDPP, field, 'EMDoublePairProduction')
process(sigmaTPP, field, 'EMTripletPairProduction')
process(sigmaICS, field, 'EMInverseComptonScattering')