1- from typing import Any , Dict , List , Optional , Tuple , Union , cast
1+ from typing import Any , Dict , List , Optional , Tuple , Union
22import numpy .typing as npt
33
44from os .path import exists
55import logging
66import numpy as np
77import healpy as hp
8- from scipy .interpolate import interpn
98
109from .pdf import InterpolatedKingPDF , TemplateSmearedKingPDF
1110from .fitting import KingPSFFitter
@@ -117,6 +116,15 @@ def __init__(
117116 self .parametrization_bins .items ()
118117 except AttributeError :
119118 self .parametrization_bins = self .parametrization_bins .item ()
119+
120+ # Extract the bin centers and keys for each event. The stored bins are
121+ # edges, but interpn requires coordinates matching the values shape.
122+ self .keys , self .bin_centers = [], []
123+ for key , edges in self .parametrization_bins .items ():
124+ self .keys .append (key )
125+ self .bin_centers .append ((edges [:- 1 ] + edges [1 :]) / 2 )
126+
127+ # And grab the fitted alpha/beta arrays
120128 self .alpha_values = fitted_parameters ["alpha" ]
121129 self .beta_values = fitted_parameters ["beta" ]
122130
@@ -135,7 +143,7 @@ def __init__(
135143 def events_match (self , events : npt .NDArray [Any ]):
136144 if self .events is None :
137145 return False
138- return np .array_equal (self .events ["ra" ], events ["ra" ]) & np .array_equal (
146+ return np .array_equal (self .events ["ra" ], events ["ra" ]) and np .array_equal (
139147 self .events ["dec" ], events ["dec" ]
140148 )
141149
@@ -175,37 +183,16 @@ def set_events(
175183 "that these arrays have the same length when passing into set_events."
176184 )
177185
178- # Begin by finding the per-event alpha and beta values via interpolation.
179- # Extract the bin centers and keys for each event. The stored bins are
180- # edges, but interpn requires coordinates matching the values shape.
181- keys , bins , event_param_values = [], [], []
182- for key , edges in self .parametrization_bins .items ():
183- keys .append (key )
184- bins .append ((edges [:- 1 ] + edges [1 :]) / 2 )
185- event_param_values .append (events [key ])
186-
187- # Get the event parameter values for each parameter
188- event_param_values = np .array (event_param_values ).T
189-
190186 # Interpolate to get the alpha and beta values for each spectral index for
191187 # each event in the given sample.
188+ def index (centers , values ):
189+ i = np .searchsorted (centers , values ).clip (1 , len (centers ) - 1 )
190+ return np .where (values - centers [i - 1 ] < centers [i ] - values , i - 1 , i )
191+
192+ event_indices = [index (self .bin_centers [i ], events [key ]) for i , key in enumerate (self .keys )]
192193 for i , gamma in enumerate (self .spectral_indices ):
193- self .event_alpha [gamma ] = interpn (
194- bins ,
195- self .alpha_values [i ],
196- event_param_values ,
197- bounds_error = False ,
198- fill_value = None ,
199- method = "nearest" ,
200- )
201- self .event_beta [gamma ] = interpn (
202- bins ,
203- self .beta_values [i ],
204- event_param_values ,
205- bounds_error = False ,
206- fill_value = None ,
207- method = "nearest" ,
208- )
194+ self .event_alpha [gamma ] = self .alpha_values [i ][* event_indices ]
195+ self .event_beta [gamma ] = self .beta_values [i ][* event_indices ]
209196
210197 # Start calculating the pvalues.
211198 # TODO: By assuming keys "ra" and "dec" exist and are usable here, we're
@@ -259,19 +246,17 @@ def evaluate_pdf(self, events: npt.NDArray[Any], gamma: float = 2) -> npt.NDArra
259246 " Please ensure that you call set_events with the same events that you later pass into evaluate_pdf."
260247 )
261248
262- if gamma in self .spectral_indices :
263- # If the requested gamma is one of the fitted spectral indices, we can directly use those parameters.
264- return cast (npt .NDArray [np .floating ], self .event_pvalue [gamma ])
265- else :
266- # Otherwise we have to interpolate the gamma values.
267- idx = np .clip (
268- np .searchsorted (self .spectral_indices , gamma ) - 1 , 0 , len (self .spectral_indices ) - 2
269- )
270- gamma_low , gamma_high = self .spectral_indices [idx ], self .spectral_indices [idx + 1 ]
271- return _interp1d (
272- gamma ,
273- gamma_low ,
274- gamma_high ,
275- self .event_pvalue [gamma_low ],
276- self .event_pvalue [gamma_high ],
277- )
249+ # Interpolate over gamma to get the final result for each event
250+ idx = np .clip (
251+ np .searchsorted (self .spectral_indices , gamma ) - 1 , 0 , len (self .spectral_indices ) - 2
252+ )
253+
254+ gamma_low , gamma_high = self .spectral_indices [idx ], self .spectral_indices [idx + 1 ]
255+ result = _interp1d (
256+ gamma ,
257+ gamma_low ,
258+ gamma_high ,
259+ self .event_pvalue [gamma_low ],
260+ self .event_pvalue [gamma_high ],
261+ )
262+ return result
0 commit comments