[1]:
%load_ext autoreload
%autoreload 2
[2]:
import numpy as np
[3]:
from skyllh.core.config import Config
cfg = Config()

PDFs

The most basic building block of a likelihood function is a probability density function (PDF). SkyLLH provides the skyllh.core.pdf module, which defines base classes for PDFs. The abstract base class of all PDFs is PDF. It defines the abstract get_pd() method. In the derived PDF class this method needs to return the probability density values for each event. In case of a signal PDF it will have to return those values also for all the sources.

Time PDFs

SkyLLH provides the very generic time PDF abstract base class TimePDF, which takes a Livetime instance and a TimeFluxProfile instance to calculate the probability density values of the events.

For signal and background time PDFs the SignalTimePDF and BackgroundTimePDF classes exist, respectively.

As an example we are creating a signal time PDF with a gaussian time profile:

[4]:
from skyllh.core.livetime import Livetime
from skyllh.core.flux_model import GaussianTimeFluxProfile
from skyllh.core.signalpdf import SignalTimePDF

livetime = Livetime(np.array([[0., 3.], [6., 10.]], dtype=np.float64))
gaussian_tfp = GaussianTimeFluxProfile(
    t0=7,
    sigma_t=0.2,
    cfg=cfg)
pdf = SignalTimePDF(
    pmm=None,
    livetime=livetime,
    time_flux_profile=gaussian_tfp,
    cfg=cfg)

The gaussian time flux profile is restricted to the following time range:

[5]:
print(f'Time range: [{gaussian_tfp.t_start}, {gaussian_tfp.t_stop}]')
Time range: [5.513231124460065, 8.486768875539935]

In order to evaluate the time PDF, we need to create a TrialDataManager instance and the structured array holding the local source parameter names and values.

[6]:
from skyllh.core.parameters import ParameterModelMapper
from skyllh.core.flux_model import NullFluxModel
from skyllh.core.detsigyield import NullDetSigYieldBuilder
from skyllh.core.source_hypo_grouping import (
    SourceHypoGroupManager,
    SourceHypoGroup,
)
from skyllh.core.source_model import SourceModel
from skyllh.core.storage import DataFieldRecordArray
from skyllh.core.trialdata import TrialDataManager

sources = [SourceModel()]

shg_mgr = SourceHypoGroupManager(
    SourceHypoGroup(
        sources=sources,
        fluxmodel=NullFluxModel(cfg=cfg),
        detsigyield_builders=NullDetSigYieldBuilder(cfg=cfg)))

pmm = ParameterModelMapper(models=sources)
src_params_recarray=pmm.create_src_params_recarray([])

events = DataFieldRecordArray({'time': np.array([0., 1.1, 5.6, 8.1, 9.5])})

tdm = TrialDataManager()
tdm.initialize_trial(shg_mgr=shg_mgr, pmm=pmm, events=events)

Via the get_pd() method we can now get the PDF values:

[7]:
(pd, grads) = pdf.get_pd(
    tdm=tdm,
    params_recarray=src_params_recarray)
print(pd)
[0.00000000e+00 0.00000000e+00 0.00000000e+00 5.38488156e-07
 0.00000000e+00]

As can be seen, only the 4th event time (8.1) has a non-zero PDF value, because all other values are either outside the detector on-time or are not covered by the time flux profile.