@@ -30,8 +30,6 @@ class then fits King distribution parameters using the requested parameter binni
3030 cache_parameters : bool = True
3131 cache_name : str = "king_parameters_cache.npz"
3232
33- # Store an instance of the PDF class to use for evaluations. This will be
34- # either a KingPDF for standard point source searches
3533 king_pdf : KingPDF
3634
3735 # Source-level information
@@ -85,10 +83,8 @@ def __init__(
8583
8684 # Obtain the King distribution parameters for all bins. If we're caching parameters
8785 # and a cache file exists, load from the cache instead of fitting. Otherwise,
88- # run the fitter and potentially cache the results. Note that if we run the fitter,
89- # we explicitly set the angular cutoff to pi: this is to ensure that we allow the
90- # full histogram to be fit for each bin without artificially setting the PDF to 0
91- # for some bins.
86+ # run the fitter and potentially cache the results. When running the fitter,
87+ # angular_cutoff is set to pi so every bin's full angular error distribution is fit.
9288 fitted_parameters : Dict [str , npt .NDArray [np .floating ]] = {}
9389 if cache_parameters and (cache_name is not None ) and exists (cache_name ):
9490 fitted_parameters_npz = np .load (cache_name , allow_pickle = True )
@@ -134,13 +130,9 @@ def __init__(
134130 # Instantiate the PDF object.
135131 self .king_pdf = KingPDF (angular_cutoff = angular_cutoff )
136132
137- # Precompute the normalization constant for every (gamma, bin)
138- # combination on the small fitted grid once per process. set_events
139- # gathers per-event norm from this array via the same nearest-bin
140- # indices used for alpha/beta, instead of recomputing the same
141- # closed-form norm independently for every event that shares a bin
142- # (most events in a trial do, since the grid is much smaller than
143- # the event count).
133+ # Precompute the normalization constant for every (gamma, bin) combination
134+ # on the fitted grid once at init. set_events looks up per-event norms from
135+ # this array using the same nearest-bin indices as alpha/beta.
144136 self .norm_values = self .king_pdf .norm (self .alpha_values , self .beta_values )
145137 return
146138
@@ -257,28 +249,19 @@ def set_events(
257249 self .event_mask = all_dists < cutoff
258250 self .event_distances = all_dists [self .event_mask ]
259251
260- # Reuse the buffer across trials when the event count hasn't
261- # changed, instead of reallocating every call. Either way, the
262- # buffer is always fully zeroed here: the masked-out region is
263- # write-only-once (only evaluate_pdf writes, and only at
264- # [self.event_mask] positions), so this is the only place a stale
265- # value from a previous trial's different mask could otherwise leak
266- # through.
252+ # Reuse the buffer across trials when the event count is unchanged.
253+ # The buffer is always fully zeroed here so that events outside
254+ # event_mask are guaranteed to be zero on every call.
267255 if len (self ._result_buffer ) != len (events ):
268256 self ._result_buffer = np .zeros (len (events ))
269257 else :
270258 self ._result_buffer [:] = 0.0
271259
272260 all_alpha , all_beta , all_norm = self ._lookup_event_grid (events )
273261 for i , gamma in enumerate (self .spectral_indices ):
274- # alpha/beta are from the fitted grid (already validated at fit
275- # time) and event_distances is already <= angular_cutoff by
276- # construction above, so bypass KingPDF.pdf()'s validation/
277- # masking and go straight to the kernel using the precomputed
278- # per-bin norm. `i` is already the correct row (spectral_indices
279- # and the leading axis of alpha_values/beta_values/norm_values
280- # are index-aligned 1:1), so there's no need to go through
281- # get_alpha_beta_gamma's searchsorted + defensive copy here.
262+ # Evaluate the King PDF directly using the precomputed per-bin norm.
263+ # alpha/beta come from the fitted grid (validated at fit time) and
264+ # event_distances are already within angular_cutoff by construction.
282265 self .event_pvalue [gamma ] = self .king_pdf .pdf_from_norm (
283266 self .event_distances , all_alpha [i ], all_beta [i ], all_norm [i ]
284267 )
@@ -292,8 +275,7 @@ def _lookup_event_grid(self, events):
292275 nearest-bin index computation is only ever done once per call.
293276 """
294277
295- # Nearest-bin lookup. Field-first masking (events[key][mask]) avoids
296- # copying the full structured array before extracting each field.
278+ # Nearest-bin lookup. Extracts each field individually after masking.
297279 def index (centers , values ):
298280 i = np .searchsorted (centers , values ).clip (1 , len (centers ) - 1 )
299281 return np .where (values - centers [i - 1 ] < centers [i ] - values , i - 1 , i )
@@ -306,25 +288,19 @@ def index(centers, values):
306288 idx = (slice (None ), * event_indices )
307289 return self .alpha_values [idx ], self .beta_values [idx ], self .norm_values [idx ]
308290
309- def get_alpha_beta (self , events , copy = True ):
291+ def get_alpha_beta (self , events ):
310292 """
311293 Look up fitted alpha/beta parameters for each event via nearest-bin lookup.
312294
313- This is a lower-level accessor used internally by :meth:`set_events`;
314- most users will call :meth:`evaluate_pdf` instead. Useful for
315- inspecting the fitted King parameters assigned to specific events.
295+ Used internally by :meth:`set_events`. Useful for inspecting the fitted
296+ King parameters assigned to specific events.
316297
317298 Parameters
318299 ----------
319300 events : structured array
320301 Events to look up. Must contain the fields referenced by
321302 ``parametrization_bins``. Only events selected by the mask set in
322303 the most recent :meth:`set_events` call are returned.
323- copy : bool, optional
324- Currently unused; fancy-indexing into the stored alpha/beta grids
325- already returns new arrays regardless of this flag. Default is
326- True.
327-
328304 Returns
329305 -------
330306 alpha : ndarray, shape (n_gamma, n_masked_events)
@@ -369,22 +345,17 @@ def get_alpha_beta_gamma(self, gamma, events=None, alpha=None, beta=None):
369345 """
370346 if alpha is None :
371347 assert events is not None
372- alpha , beta = self .get_alpha_beta (events , copy = False )
348+ alpha , beta = self .get_alpha_beta (events )
373349 assert len (alpha ) == len (beta )
374350
375351 # If we have this gamma, just return it. Make sure to use copy()
376- # so the caller doesn't get a reference into our array. Note:
377- # searchsorted's default side="left" already returns the exact
378- # index of an exact match in a sorted array -- no "-1" needed here
379- # (that would be an off-by-one, wrapping to the previous row).
352+ # so the caller doesn't get a reference into our array.
353+ # searchsorted with side="left" returns the exact index of an exact match.
380354 if gamma in self .spectral_indices :
381355 gamma_idx = np .searchsorted (self .spectral_indices , gamma )
382356 return alpha [gamma_idx ].copy (), beta [gamma_idx ].copy ()
383357
384- # Otherwise, interpolate between the bracketing pair of spectral
385- # indices, clamping so the pair is always valid even when gamma is
386- # outside the stored range (extrapolation from the nearest pair).
387- # Mirrors evaluate_pdf's bracketing logic.
358+ # Clamp so the bracketing pair is always within the stored range.
388359 idx = np .clip (
389360 np .searchsorted (self .spectral_indices , gamma ) - 1 , 0 , len (self .spectral_indices ) - 2
390361 )
@@ -426,7 +397,7 @@ def evaluate_pdf(self, events: npt.NDArray[Any], gamma: float = 2) -> npt.NDArra
426397 If ``events`` does not match the events passed to the most recent
427398 call to :meth:`set_events`.
428399 """
429- # If we haven't already calculated the per-event alpha and beta parameters, do so now .
400+ # Require that set_events has been called for these events .
430401 if not self ._events_match (events ):
431402 raise RuntimeError (
432403 "The events provided to evaluate_pdf do not match the events that were used to calculate the per-event parameters."
@@ -439,10 +410,6 @@ def evaluate_pdf(self, events: npt.NDArray[Any], gamma: float = 2) -> npt.NDArra
439410 )
440411
441412 gamma_low , gamma_high = self .spectral_indices [idx ], self .spectral_indices [idx + 1 ]
442- # No need to re-zero the buffer here: event_mask is fixed for the
443- # whole trial (only set_events changes it), and set_events already
444- # zeroed the full buffer on entry, so the masked-out region is
445- # already correct and untouched by anything else.
446413 self ._result_buffer [self .event_mask ] = _interp1d (
447414 gamma ,
448415 gamma_low ,
0 commit comments