Skip to content

Commit ab84a40

Browse files
authored
Add standard deviation to the effective area function
Added the calculation of the standard deviation of the effective area by weighting with squared weights. The default behavior of the function is unchanged, the return type is a single histograms with effective area binned in energy and cos(zenith). If the new argument return_stddev is set to True, a tuple of effective area and its uncertainty is returned.
1 parent bedd1c5 commit ab84a40

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

src/simweights/_weighter.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import inspect
88
import warnings
9-
from typing import TYPE_CHECKING, Any, Callable, Iterable
9+
from typing import TYPE_CHECKING, Any, Callable, Iterable, Tuple
1010

1111
import numpy as np
1212
from scipy.integrate import quad # pylint: disable=import-error
@@ -142,20 +142,24 @@ def effective_area(
142142
cos_zenith_bins: ArrayLike,
143143
mask: ArrayLike | None = None,
144144
flux: Any = 1, # default is 1 GeV^-1 cm^-2 sr^-1 flux
145-
) -> NDArray[np.float64]:
146-
r"""Calculate The effective area for the given energy and zenith bins.
145+
return_stddev: bool = False,
146+
) -> NDArray[np.float64] | Tuple[NDArray[np.float64], NDArray[np.float64]]:
147+
r"""Calculate the effective area for the given energy and zenith bins.
147148
148-
This is accomplished by histogramming the generation surface the simulation sample
149+
This is accomplished by histogramming the generation surface of the simulation sample
149150
in energy and zenith bins and dividing by the size of the energy and solid angle of each bin.
150-
If mask is passed as a parameter, only events which are included in the mask are used.
151-
Effective areas are given units of :math:`\mathrm{m}^2`
151+
If a mask is passed as a parameter, only events which are included in the mask are used.
152+
Effective areas are given in units of :math:`\mathrm{m}^2`
152153
153154
.. Note ::
154155
155156
If the sample contains more than one type of primary particle, then the result will be
156157
averaged over the number of particles. This is usually what you want. However, it can
157158
cause strange behavior if there is a small number of one type. In this case, the mask
158-
should be used to select the particle types individually.
159+
should be used to select the particle types individually. Alternatively, a flux model
160+
can be specified to apply a weighting to the individual primary particle types. If
161+
return_stddev is set to True, a tuple of effective area histograms and their standard
162+
deviation are returned.
159163
160164
161165
Args:
@@ -169,11 +173,16 @@ def effective_area(
169173
flux: Any
170174
A model describing the flux of the primaries to weight against. For
171175
possible types, see get_weights()
176+
return_stddev: bool
177+
boolean to specify if only effective area (default) or a tuple of
178+
effective area and its standard deviation is returned
172179
173180
Returns:
174-
array_like
181+
array_like | tuple(array_like, array_like)
175182
An NxM array of effective areas. Where N is the number of energy bins and M
176183
is the number of cos(zenith) bins.
184+
If return_stddev, a tuple of two NxM arrays (effective area and its
185+
standard deviation)
177186
178187
"""
179188
cm2_to_m2 = 1e-4
@@ -200,6 +209,13 @@ def effective_area(
200209
bins=[cos_zenith_bins, energy_bins],
201210
)
202211

212+
hist_val_variance, _, _ = np.histogram2d(
213+
cos_zen[maska],
214+
energy[maska],
215+
weights=(weights[maska])**2,
216+
bins=[cos_zenith_bins, energy_bins],
217+
)
218+
203219
assert np.array_equal(enbin, energy_bins)
204220
assert np.array_equal(czbin, cos_zenith_bins)
205221
pdgids = np.unique(self.get_weight_column("pdgid")[maska])
@@ -217,7 +233,11 @@ def effective_area(
217233
mesg = f"flux of type {type(flux)} is supplied but only scalar flux or cosmic ray flux models are supported so far"
218234
raise TypeError(mesg)
219235
e_int, z_int = np.meshgrid(flux_integrals, np.ediff1d(czbin))
220-
return np.asarray(cm2_to_m2 * hist_val / (e_int * 2 * np.pi * z_int), dtype=np.float64)
236+
if return_stddev:
237+
output = np.asarray(cm2_to_m2 * hist_val / (e_int * 2 * np.pi * z_int), dtype=np.float64), np.asarray(cm2_to_m2 * np.sqrt(hist_val_variance) / (e_int * 2 * np.pi * z_int), dtype=np.float64)
238+
else:
239+
output = np.asarray(cm2_to_m2 * hist_val / (e_int * 2 * np.pi * z_int), dtype=np.float64)
240+
return output
221241

222242
def __add__(self: Weighter, other: Weighter | int) -> Weighter:
223243
if other == 0:

0 commit comments

Comments
 (0)