1
1
import numpy as np
2
+ import astropy .units as u
2
3
4
+ POINT_SOURCE_FLUX_UNIT = (1 / u .GeV / u .s / u .m ** 2 ).unit
5
+ FLUX_UNIT = POINT_SOURCE_FLUX_UNIT / u .sr
3
6
4
- def random_power (spectral_index , e_min , e_max , size ):
7
+
8
+ @u .quantity_input
9
+ def random_power (
10
+ spectral_index ,
11
+ e_min : u .TeV ,
12
+ e_max : u .TeV ,
13
+ size ,
14
+ e_ref : u .TeV = 1 * u .TeV ,
15
+ ) -> u .TeV :
5
16
r'''
6
17
Draw random numbers from a power law distribution
7
18
8
19
.. math::
9
20
f(E) =
10
21
\frac{1 - \gamma}
11
- {E_{\max}^{1 - \gamma } - E_{\min}^{1 - \gamma }}
12
- E^{- \gamma}
22
+ ( {E_{\max} / E_{\mathrm{ref}})^{\gamma - 1 } - ( E_{\min} / E_{\mathrm{ref}})^{\gamma - 1 }}
23
+ (E / E_{\mathrm{ref}})^{ \gamma}
13
24
14
25
Parameters
15
26
----------
16
27
spectral_index: float
17
28
The differential spectral index of the power law
18
- e_min: float
29
+ e_min: Quantity[energy]
19
30
lower energy border
20
- e_max: float
31
+ e_max: Quantity[energy]
21
32
upper energy border, can be np.inf
22
33
size: int or tuple[int]
23
34
Number of events to draw or a shape like (100, 2)
24
35
'''
25
- assert spectral_index > 1.0 , 'spectral_index must be > 1.0'
36
+ if spectral_index > - 1.0 :
37
+ raise ValueError ('spectral_index must be < -1.0' )
38
+
26
39
u = np .random .uniform (0 , 1 , size )
27
40
28
- exponent = 1 - spectral_index
41
+ exponent = spectral_index + 1
29
42
30
43
if e_max == np .inf :
31
- diff = - e_min ** exponent
44
+ diff = - ( e_min / e_ref ) ** exponent
32
45
else :
33
- diff = e_max ** exponent - e_min ** exponent
46
+ diff = ( e_max / e_ref ) ** exponent - ( e_min / e_ref ) ** exponent
34
47
35
- return (diff * u + e_min ** exponent ) ** (1 / exponent )
48
+ return e_ref * (diff * u + ( e_min / e_ref ) ** exponent ) ** (1 / exponent )
36
49
37
50
38
- def power_law (energy , flux_normalization , spectral_index ):
51
+ def power_law (
52
+ energy : u .TeV ,
53
+ flux_normalization : (FLUX_UNIT , POINT_SOURCE_FLUX_UNIT ),
54
+ spectral_index ,
55
+ e_ref : u .TeV = 1 * u .TeV ,
56
+ ):
39
57
r'''
40
58
Simple power law
41
59
42
60
.. math::
43
- \phi = \phi_0 \cdot E ^{- \gamma}
61
+ \phi = \phi_0 \cdot (E / E_{}\mathrm{ref}})^{ \gamma}
44
62
45
63
Parameters
46
64
----------
47
- energy: number or array-like
65
+ energy: Quantity[energy]
48
66
energy points to evaluate
49
- flux_normalization: float
67
+ flux_normalization: Quantity[m**-2 s**-2 TeV**-1]
50
68
Flux normalization
51
69
spectral_index: float
52
70
Spectral index
71
+ e_ref: Quantity[energy]
72
+ The reference energy
53
73
'''
54
- return flux_normalization * energy ** (- spectral_index )
74
+ return flux_normalization * ( energy / e_ref ) ** (spectral_index )
55
75
56
76
57
- def curved_power_law (energy , flux_normalization , a , b ):
77
+ @u .quantity_input
78
+ def curved_power_law (
79
+ energy : u .TeV ,
80
+ flux_normalization : (FLUX_UNIT , POINT_SOURCE_FLUX_UNIT ),
81
+ a ,
82
+ b ,
83
+ e_ref : u .TeV = 1 * u .TeV ,
84
+ ):
58
85
r'''
59
86
Curved power law
60
87
61
88
.. math::
62
- \phi = \phi_0 \cdot E ^ {a - b \cdot \log (E)}
89
+ \phi = \phi_0 \cdot E ^ {a + b \cdot \log_{10} (E)}
63
90
64
91
Parameters
65
92
----------
@@ -70,9 +97,12 @@ def curved_power_law(energy, flux_normalization, a, b):
70
97
a: float
71
98
Parameter `a` of the curved power law
72
99
b: float
73
- Parameter `b` of the curved power law
100
+ Parameter `b` of the curved power law
101
+ e_ref: Quantity[energy]
102
+ The reference energy
74
103
'''
75
- return flux_normalization * energy ** (a + b * np .log10 (energy ))
104
+ exp = a + b * np .log10 ((energy / e_ref ))
105
+ return flux_normalization * (energy / e_ref ) ** exp
76
106
77
107
78
108
def li_ma_significance (n_on , n_off , alpha = 0.2 ):
@@ -115,7 +145,14 @@ def li_ma_significance(n_on, n_off, alpha=0.2):
115
145
return significance
116
146
117
147
118
- def calc_weight_simple_to_curved (energy , spectral_index , a , b ):
148
+ @u .quantity_input
149
+ def calc_weight_simple_to_curved (
150
+ energy : u .TeV ,
151
+ spectral_index ,
152
+ a ,
153
+ b ,
154
+ e_ref : u .TeV = 1 * u .TeV ,
155
+ ):
119
156
'''
120
157
Reweight simulated events from a simulated power law with
121
158
spectral index `spectral_index` to a curved power law with parameters `a` and `b`
@@ -131,10 +168,16 @@ def calc_weight_simple_to_curved(energy, spectral_index, a, b):
131
168
b: float
132
169
Parameter `b` of the target curved power law
133
170
'''
134
- return energy ** (spectral_index + a + b * np .log10 (energy ))
171
+ return ( energy / e_ref ) ** (spectral_index + a + b * np .log10 (energy / e_ref ))
135
172
136
173
137
- def calc_weight_change_index (energy , simulated_index , target_index ):
174
+ @u .quantity_input
175
+ def calc_weight_change_index (
176
+ energy : u .TeV ,
177
+ simulated_index ,
178
+ target_index ,
179
+ e_ref : u .TeV = 1 * u .TeV ,
180
+ ):
138
181
'''
139
182
Reweight simulated events from one power law index to another
140
183
@@ -147,60 +190,109 @@ def calc_weight_change_index(energy, simulated_index, target_index):
147
190
target_index: float
148
191
Spectral index of the target power law
149
192
'''
150
- return energy ** (target_index - simulated_index )
193
+ return (energy / e_ref ) ** (target_index - simulated_index )
194
+
195
+
196
+ @u .quantity_input
197
+ def calc_gamma_obstime (
198
+ n_events ,
199
+ spectral_index ,
200
+ flux_normalization : (FLUX_UNIT , POINT_SOURCE_FLUX_UNIT ),
201
+ max_impact : u .m ,
202
+ e_min : u .TeV ,
203
+ e_max : u .TeV ,
204
+ e_ref : u .TeV = 1 * u .TeV ,
205
+ ) -> u .s :
206
+ r'''
207
+ Calculate the equivalent observation time for a number of simulation enents
151
208
209
+ The number of events produced by sampling from a power law with
210
+ spectral index γ is given by
152
211
153
- def calc_gamma_obstime (n_events , spectral_index , flux_normalization , max_impact , e_min , e_max ):
154
- '''
155
- Calculate the equivalent observation time for a spectral_index montecarlo set
212
+ .. math::
213
+ N =
214
+ A t \Phi_0 \int_{E_{\min}}^{E_{\max}}
215
+ \left(\frac{E}{E_{\mathrm{ref}}}\right)^{\gamma}
216
+ \,\mathrm{d}E
217
+
218
+ Solving this for t yields
219
+
220
+ .. math::
221
+ t = \frac{N \cdot (\gamma - 1)}{
222
+ E_{\mathrm{ref}} A \Phi_0
223
+ \left(
224
+ \left(\frac{E_{\max}}{E_{\mathrm{ref}}}\right)^{\gamma - 1}
225
+ - \left(\frac{E_{\max}}{E_{\mathrm{ref}}}\right)^{\gamma - 1}
226
+ \right)
227
+ }
156
228
157
229
Parameters
158
230
----------
159
231
n_events: int
160
232
Number of simulated events
161
233
spectral_index: float
162
- Spectral index of the simulated power law
234
+ Spectral index of the simulated power law, including the sign,
235
+ so typically -2.7 or -2
163
236
flux_normalization: float
164
237
Flux normalization of the simulated power law
165
- max_impact: float
238
+ max_impact: Quantity[length]
166
239
Maximal simulated impact
167
- e_min: float
240
+ e_min: Quantity[energy]
168
241
Mimimal simulated energy
169
- e_max: float
242
+ e_max: Quantity[energy]
170
243
Maximal simulated energy
244
+ e_ref: Quantity[energy]
245
+ The e_ref energy
171
246
'''
172
247
if spectral_index >= - 1 :
173
248
raise ValueError ('spectral_index must be < -1' )
174
249
175
- numerator = n_events * (1 - spectral_index )
250
+ numerator = n_events * (spectral_index + 1 )
176
251
177
- t1 = flux_normalization * max_impact ** 2 * np .pi
178
- t2 = e_max ** (1 - spectral_index ) - e_min ** (1 - spectral_index )
252
+ A = max_impact ** 2 * np .pi
253
+ t1 = A * flux_normalization * e_ref
254
+ t2 = (e_max / e_ref )** (spectral_index + 1 )
255
+ t3 = (e_min / e_ref )** (spectral_index + 1 )
179
256
180
- denominator = t1 * t2
257
+ denominator = t1 * ( t2 - t3 )
181
258
182
259
return numerator / denominator
183
260
184
261
185
- def power_law_integral (flux_normalisation , spectral_index , e_min , e_max ):
262
+ @u .quantity_input
263
+ def power_law_integral (
264
+ flux_normalization : (FLUX_UNIT , POINT_SOURCE_FLUX_UNIT ),
265
+ spectral_index ,
266
+ e_min : u .TeV ,
267
+ e_max : u .TeV ,
268
+ e_ref : u .TeV = 1 * u .TeV ,
269
+ ):
186
270
'''
187
271
Return the integral of a power_law with normalisation
188
272
`flux_normalization` and index `spectral_index`
189
273
between `e_min` and `e_max`
190
274
'''
191
- int_index = 1 - spectral_index
192
- return flux_normalisation / int_index * ( e_max ** (int_index ) - e_min ** (int_index ) )
275
+ int_index = spectral_index + 1
276
+ e_term = ( e_max / e_ref ) ** (int_index ) - ( e_min / e_ref ) ** (int_index )
193
277
278
+ res = flux_normalization * e_ref / int_index * e_term
194
279
280
+ if flux_normalization .unit .is_equivalent (FLUX_UNIT ):
281
+ return res .to (1 / u .m ** 2 / u .s / u .sr )
282
+ return res .to (1 / u .m ** 2 / u .s )
283
+
284
+
285
+ @u .quantity_input
195
286
def calc_proton_obstime (
196
- n_events ,
197
- spectral_index ,
198
- max_impact ,
199
- viewcone ,
200
- e_min ,
201
- e_max ,
202
- flux_normalization = 1.8e4 ,
203
- ):
287
+ n_events ,
288
+ spectral_index ,
289
+ max_impact : u .m ,
290
+ viewcone : u .deg ,
291
+ e_min : u .TeV ,
292
+ e_max : u .TeV ,
293
+ flux_normalization : FLUX_UNIT = 1.8e4 * FLUX_UNIT ,
294
+ e_ref : u .GeV = 1 * u .GeV ,
295
+ ) -> u .s :
204
296
'''
205
297
Calculate the equivalent observation time for a proton montecarlo set
206
298
@@ -214,18 +306,20 @@ def calc_proton_obstime(
214
306
Maximal simulated impact in m
215
307
viewcone: float
216
308
Viewcone in degrees
217
- e_min: float
218
- Mimimal simulated energy in GeV
219
- e_max: float
220
- Maximal simulated energy in GeV
309
+ e_min: Quantity[energy]
310
+ Mimimal simulated energy
311
+ e_max: Quantity[energy]
312
+ Maximal simulated energy
221
313
flux_normalization: float
222
314
Flux normalisation of the cosmic rays in nucleons / (m² s sr GeV)
223
315
Default value is (29.2) of
224
316
http://pdg.lbl.gov/2016/reviews/rpp2016-rev-cosmic-rays.pdf
225
317
'''
226
318
area = np .pi * max_impact ** 2
227
- solid_angle = 2 * np .pi * (1 - np .cos (np . deg2rad ( viewcone )))
319
+ solid_angle = 2 * np .pi * (1 - np .cos (viewcone )) * u . sr
228
320
229
- expected_integral_flux = power_law_integral (flux_normalization , 2.7 , e_min , e_max )
321
+ expected_integral_flux = power_law_integral (
322
+ flux_normalization , spectral_index , e_min , e_max , e_ref
323
+ )
230
324
231
325
return n_events / area / solid_angle / expected_integral_flux
0 commit comments