11import numpy as np
22import astropy .units as u
3+ from functools import partial
34
45POINT_SOURCE_FLUX_UNIT = (1 / u .GeV / u .s / u .m ** 2 ).unit
56FLUX_UNIT = POINT_SOURCE_FLUX_UNIT / u .sr
67
8+ PDG_COSMIC_RAY_FLUX = 1.8e4 * FLUX_UNIT
9+ PDG_COSMIC_RAY_E_REF = 1 * u .GeV
10+ PDG_COSMIC_RAY_INDEX = - 2.7
11+
712
813@u .quantity_input
914def random_power (
1015 spectral_index ,
1116 e_min : u .TeV ,
1217 e_max : u .TeV ,
1318 size ,
14- e_ref : u .TeV = 1 * u .TeV ,
19+ e_ref : u .TeV = 1 * u .TeV ,
1520) -> u .TeV :
1621 r'''
1722 Draw random numbers from a power law distribution
@@ -98,7 +103,7 @@ def power_law_exponential_cutoff(
98103 e_ref: Quantity[energy]
99104 The reference energy
100105 '''
101- tau = np .exp (energy / e_cutoff )
106+ tau = np .exp (- energy / e_cutoff )
102107 return power_law (energy , flux_normalization , spectral_index , e_ref ) * tau
103108
104109
@@ -175,63 +180,152 @@ def li_ma_significance(n_on, n_off, alpha=0.2):
175180
176181
177182@u .quantity_input
178- def calc_weight_power_to_logparabola (
183+ def calc_weights_powerlaw (
179184 energy : u .TeV ,
185+ obstime : u .hour ,
186+ n_events ,
187+ e_min : u .TeV ,
188+ e_max : u .TeV ,
180189 simulated_index ,
181- target_a ,
182- target_b ,
190+ scatter_radius : u .m ,
191+ target_index ,
192+ flux_normalization : (POINT_SOURCE_FLUX_UNIT , FLUX_UNIT ),
183193 e_ref : u .TeV = 1 * u .TeV ,
194+ sample_fraction = 1 ,
195+ viewcone = None ,
184196):
185197 '''
186- Reweight simulated events from a simulated power law with
187- spectral index `spectral_index` to a curved power law with parameters `a` and `b`
198+ Calculate event weights, so that simulated
199+ events are reweighted to a physical power law flux
200+ '''
188201
189- phi(E) = phi_0 (E / E_ref)^(a + b * log10(E / E_ref))
202+ phi_sim = calc_simulated_flux_normalization (
203+ obstime = obstime ,
204+ n_events = n_events ,
205+ e_min = e_min ,
206+ e_max = e_max ,
207+ e_ref = e_ref ,
208+ simulated_index = simulated_index ,
209+ scatter_radius = scatter_radius ,
210+ viewcone = viewcone ,
211+ )
190212
191- Parameters
192- ----------
193- energy: float or array-like
194- Energy of the events
195- simulated_index: float
196- Spectral index of the simulated power law
197- target_a: float
198- Parameter `a` of the target curved power law
199- target_b: float
200- Parameter `b` of the target curved power law
213+ e = (energy / e_ref ).to_value (u .dimensionless_unscaled )
214+ weights = flux_normalization / phi_sim * e ** (target_index - simulated_index )
215+ return weights .to (u .dimensionless_unscaled ) / sample_fraction
216+
217+
218+ @u .quantity_input
219+ def calc_weights_logparabola (
220+ energy : u .TeV ,
221+ obstime : u .hour ,
222+ n_events ,
223+ e_min : u .TeV ,
224+ e_max : u .TeV ,
225+ simulated_index ,
226+ scatter_radius : u .m ,
227+ target_a ,
228+ target_b ,
229+ flux_normalization : (POINT_SOURCE_FLUX_UNIT , FLUX_UNIT ),
230+ e_ref : u .TeV = 1 * u .TeV ,
231+ sample_fraction = 1 ,
232+ viewcone = None ,
233+ ):
201234 '''
202- return (energy / e_ref ) ** (
203- target_a + target_b * np .log10 (energy / e_ref ) - simulated_index
235+ Calculate event weights, so that simulated
236+ events are reweighted to a physical power law flux
237+ '''
238+
239+ phi_sim = calc_simulated_flux_normalization (
240+ obstime = obstime ,
241+ n_events = n_events ,
242+ e_min = e_min ,
243+ e_max = e_max ,
244+ e_ref = e_ref ,
245+ simulated_index = simulated_index ,
246+ scatter_radius = scatter_radius ,
247+ viewcone = viewcone ,
204248 )
205249
250+ e = (energy / e_ref ).to_value (u .dimensionless_unscaled )
251+ exp = target_a + np .log10 (e ) * target_b - simulated_index
252+ weights = flux_normalization / phi_sim * e ** exp
253+ return weights .to (u .dimensionless_unscaled ) / sample_fraction
254+
206255
207256@u .quantity_input
208- def calc_weight_change_index (
257+ def calc_weights_exponential_cutoff (
209258 energy : u .TeV ,
259+ obstime : u .hour ,
260+ n_events ,
261+ e_min : u .TeV ,
262+ e_max : u .TeV ,
210263 simulated_index ,
264+ scatter_radius : u .m ,
211265 target_index ,
266+ target_e_cutoff ,
267+ flux_normalization : (POINT_SOURCE_FLUX_UNIT , FLUX_UNIT ),
212268 e_ref : u .TeV = 1 * u .TeV ,
269+ sample_fraction = 1 ,
270+ viewcone = None ,
213271):
214272 '''
215- Reweight simulated events from one power law index to another
273+ Calculate event weights, so that simulated
274+ events are reweighted to a physical power law flux with exponential cutoff
275+ '''
216276
217- Parameters
218- ----------
219- energy: float or array-like
220- Energy of the events
221- simulated_index: float
222- Spectral index of the simulated power law
223- target_index: float
224- Spectral index of the target power law
277+ phi_sim = calc_simulated_flux_normalization (
278+ obstime = obstime ,
279+ n_events = n_events ,
280+ e_min = e_min ,
281+ e_max = e_max ,
282+ e_ref = e_ref ,
283+ simulated_index = simulated_index ,
284+ scatter_radius = scatter_radius ,
285+ viewcone = viewcone ,
286+ )
287+
288+ e = (energy / e_ref ).to_value (u .dimensionless_unscaled )
289+ tau = np .exp (- energy / target_e_cutoff )
290+ weights = flux_normalization / phi_sim * e ** (target_index - simulated_index ) * tau
291+ return weights .to (u .dimensionless_unscaled ) / sample_fraction
292+
293+
294+ def calc_simulated_flux_normalization (
295+ obstime : u .hour ,
296+ n_events ,
297+ e_min : u .TeV ,
298+ e_max : u .TeV ,
299+ simulated_index ,
300+ scatter_radius : u .m ,
301+ e_ref : u .TeV ,
302+ viewcone = None ,
303+ ):
304+ '''
305+ Calculate the flux normalization for simulated events drawn
306+ from a power law for a certain observation time.
225307 '''
226- return (energy / e_ref ) ** (target_index - simulated_index )
308+ if viewcone is not None :
309+ solid_angle = 2 * np .pi * (1 - np .cos (viewcone )) * u .sr
310+ else :
311+ solid_angle = 1
312+
313+ A = np .pi * scatter_radius ** 2
314+
315+ delta = e_max ** (simulated_index + 1 ) - e_min ** (simulated_index + 1 )
316+
317+ nom = (simulated_index + 1 ) * e_ref ** simulated_index * n_events
318+ denom = (A * obstime * solid_angle ) * delta
319+
320+ return nom / denom
227321
228322
229323@u .quantity_input
230324def calc_gamma_obstime (
231325 n_events ,
232326 spectral_index ,
233327 flux_normalization : (FLUX_UNIT , POINT_SOURCE_FLUX_UNIT ),
234- max_impact : u .m ,
328+ scatter_radius : u .m ,
235329 e_min : u .TeV ,
236330 e_max : u .TeV ,
237331 e_ref : u .TeV = 1 * u .TeV ,
@@ -267,8 +361,8 @@ def calc_gamma_obstime(
267361 Spectral index of the simulated power law, including the sign,
268362 so typically -2.7 or -2
269363 flux_normalization: float
270- Flux normalization of the simulated power law
271- max_impact : Quantity[length]
364+ Flux normalization of the target power law
365+ scatter_radius : Quantity[length]
272366 Maximal simulated impact
273367 e_min: Quantity[energy]
274368 Mimimal simulated energy
@@ -280,16 +374,18 @@ def calc_gamma_obstime(
280374 if spectral_index >= - 1 :
281375 raise ValueError ('spectral_index must be < -1' )
282376
283- numerator = n_events * (spectral_index + 1 )
284-
285- A = max_impact ** 2 * np .pi
286- t1 = A * flux_normalization * e_ref
287- t2 = (e_max / e_ref )** (spectral_index + 1 )
288- t3 = (e_min / e_ref )** (spectral_index + 1 )
289-
290- denominator = t1 * (t2 - t3 )
377+ t_ref = 1 * u .hour
378+ phi_sim = calc_simulated_flux_normalization (
379+ obstime = t_ref ,
380+ n_events = n_events ,
381+ e_min = e_min ,
382+ e_max = e_max ,
383+ e_ref = e_ref ,
384+ simulated_index = spectral_index ,
385+ scatter_radius = scatter_radius ,
386+ )
291387
292- return numerator / denominator
388+ return ( t_ref * phi_sim / flux_normalization ). to ( u . hour )
293389
294390
295391@u .quantity_input
@@ -311,20 +407,20 @@ def power_law_integral(
311407 res = flux_normalization * e_ref / int_index * e_term
312408
313409 if flux_normalization .unit .is_equivalent (FLUX_UNIT ):
314- return res .to (1 / u . m ** 2 / u . s / u . sr )
315- return res .to (1 / u . m ** 2 / u . s )
410+ return res .to (FLUX_UNIT )
411+ return res .to (POINT_SOURCE_FLUX_UNIT )
316412
317413
318414@u .quantity_input
319415def calc_proton_obstime (
320416 n_events ,
321417 spectral_index ,
322- max_impact : u .m ,
418+ scatter_radius : u .m ,
323419 viewcone : u .deg ,
324420 e_min : u .TeV ,
325421 e_max : u .TeV ,
326- flux_normalization : FLUX_UNIT = 1.8e4 * FLUX_UNIT ,
327- e_ref : u .GeV = 1 * u . GeV ,
422+ flux_normalization : FLUX_UNIT = PDG_COSMIC_RAY_FLUX ,
423+ e_ref : u .GeV = PDG_COSMIC_RAY_E_REF ,
328424) -> u .s :
329425 '''
330426 Calculate the equivalent observation time for a proton montecarlo set
@@ -335,7 +431,7 @@ def calc_proton_obstime(
335431 Number of simulated events
336432 spectral_index: float
337433 Spectral index of the simulated power law
338- max_impact : float
434+ scatter_radius : float
339435 Maximal simulated impact in m
340436 viewcone: float
341437 Viewcone in degrees
@@ -348,11 +444,31 @@ def calc_proton_obstime(
348444 Default value is (29.2) of
349445 http://pdg.lbl.gov/2016/reviews/rpp2016-rev-cosmic-rays.pdf
350446 '''
351- area = np . pi * max_impact ** 2
352- solid_angle = 2 * np . pi * ( 1 - np . cos ( viewcone )) * u . sr
447+ if spectral_index >= - 1 :
448+ raise ValueError ( 'spectral_index must be < -1' )
353449
354- expected_integral_flux = power_law_integral (
355- flux_normalization , spectral_index , e_min , e_max , e_ref
450+ t_ref = 1 * u .hour
451+ phi_sim = calc_simulated_flux_normalization (
452+ obstime = t_ref ,
453+ n_events = n_events ,
454+ e_min = e_min ,
455+ e_max = e_max ,
456+ e_ref = e_ref ,
457+ simulated_index = spectral_index ,
458+ scatter_radius = scatter_radius ,
459+ viewcone = viewcone ,
356460 )
357461
358- return n_events / area / solid_angle / expected_integral_flux
462+ return (t_ref * phi_sim / flux_normalization ).to (u .hour )
463+
464+
465+ calc_weights_cosmic_rays = partial (
466+ calc_weights_powerlaw ,
467+ target_index = PDG_COSMIC_RAY_INDEX ,
468+ flux_normalization = PDG_COSMIC_RAY_FLUX ,
469+ e_ref = PDG_COSMIC_RAY_E_REF ,
470+ )
471+ calc_weights_cosmic_rays .__doc__ = '''
472+ Calculate event weights, so that simulated
473+ events are reweighted to the PDG cosmic rays spectrum
474+ '''
0 commit comments