{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "12112806",
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "86cd781f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "8a671a4f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from skyllh.core.config import Config\n",
    "cfg = Config()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "129e7c27",
   "metadata": {},
   "source": [
    "# PDFs"
   ]
  },
  {
   "cell_type": "raw",
   "id": "3b30fe0c",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "The most basic building block of a likelihood function is a probability density\n",
    "function (PDF). SkyLLH provides the :py:mod:`skyllh.core.pdf` module, which \n",
    "defines base classes for PDFs. The abstract base class of all PDFs is \n",
    ":py:class:`~skyllh.core.pdf.PDF`. It defines the abstract \n",
    ":py:meth:`~skyllh.core.pdf.PDF.get_pd` method. In the derived PDF class this \n",
    "method needs to return the probability density values for each event. \n",
    "In case of a signal PDF it will have to return those values also for all the \n",
    "sources."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "f7ca9ec5",
   "metadata": {},
   "source": [
    "## Time PDFs"
   ]
  },
  {
   "cell_type": "raw",
   "id": "30573d02",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "SkyLLH provides the very generic time PDF abstract base class \n",
    ":py:class:`~skyllh.core.pdf.TimePDF`, which takes a \n",
    ":py:class:`~skyllh.core.livetime.Livetime` instance and a \n",
    ":py:class:`~skyllh.core.flux_model.TimeFluxProfile` instance to calculate\n",
    "the probability density values of the events.\n",
    "\n",
    "For signal and background time PDFs the \n",
    ":py:class:`~skyllh.core.signalpdf.SignalTimePDF` and\n",
    ":py:class:`~skyllh.core.backgroundpdf.BackgroundTimePDF` classes exist,\n",
    "respectively."
   ]
  },
  {
   "cell_type": "raw",
   "id": "df388eb4",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "As an example we are creating a signal time PDF with a gaussian time profile:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "b6b6c7d8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from skyllh.core.livetime import Livetime\n",
    "from skyllh.core.flux_model import GaussianTimeFluxProfile\n",
    "from skyllh.core.signalpdf import SignalTimePDF\n",
    "\n",
    "livetime = Livetime(np.array([[0., 3.], [6., 10.]], dtype=np.float64))\n",
    "gaussian_tfp = GaussianTimeFluxProfile(\n",
    "    t0=7, \n",
    "    sigma_t=0.2, \n",
    "    cfg=cfg)\n",
    "pdf = SignalTimePDF(\n",
    "    pmm=None, \n",
    "    livetime=livetime, \n",
    "    time_flux_profile=gaussian_tfp,\n",
    "    cfg=cfg)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "raw",
   "id": "9aecf770",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "The gaussian time flux profile is restricted to the following time range:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1c6dc1f0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time range: [5.513231124460065, 8.486768875539935]\n"
     ]
    }
   ],
   "source": [
    "print(f'Time range: [{gaussian_tfp.t_start}, {gaussian_tfp.t_stop}]')"
   ]
  },
  {
   "attachments": {},
   "cell_type": "raw",
   "id": "7799cc8f",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "In order to evaluate the time PDF, we need to create a \n",
    ":py:class:`~skyllh.core.trialdata.TrialDataManager` instance and the \n",
    "structured array holding the local source parameter names and values.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "f24294dd",
   "metadata": {},
   "outputs": [],
   "source": [
    "from skyllh.core.parameters import ParameterModelMapper\n",
    "from skyllh.core.flux_model import NullFluxModel\n",
    "from skyllh.core.detsigyield import NullDetSigYieldBuilder\n",
    "from skyllh.core.source_hypo_grouping import (\n",
    "    SourceHypoGroupManager, \n",
    "    SourceHypoGroup,\n",
    ")\n",
    "from skyllh.core.source_model import SourceModel\n",
    "from skyllh.core.storage import DataFieldRecordArray\n",
    "from skyllh.core.trialdata import TrialDataManager\n",
    "\n",
    "sources = [SourceModel()]\n",
    "\n",
    "shg_mgr = SourceHypoGroupManager(\n",
    "    SourceHypoGroup(\n",
    "        sources=sources,\n",
    "        fluxmodel=NullFluxModel(cfg=cfg),\n",
    "        detsigyield_builders=NullDetSigYieldBuilder(cfg=cfg)))\n",
    "\n",
    "pmm = ParameterModelMapper(models=sources)\n",
    "src_params_recarray=pmm.create_src_params_recarray([])\n",
    "\n",
    "events = DataFieldRecordArray({'time': np.array([0., 1.1, 5.6, 8.1, 9.5])})\n",
    "\n",
    "tdm = TrialDataManager()\n",
    "tdm.initialize_trial(shg_mgr=shg_mgr, pmm=pmm, events=events)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "e98ee136",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "Via the :py:meth:`~skyllh.core.signalpdf.SignalTimePDF.get_pd` method we can now\n",
    "get the PDF values:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "24ec10e6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.00000000e+00 0.00000000e+00 0.00000000e+00 5.38488156e-07\n",
      " 0.00000000e+00]\n"
     ]
    }
   ],
   "source": [
    "(pd, grads) = pdf.get_pd(\n",
    "    tdm=tdm,\n",
    "    params_recarray=src_params_recarray)\n",
    "print(pd)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "b96048a8",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    "As can be seen, only the 4th event time (``8.1``) has a non-zero PDF value, \n",
    "because all other values are either outside the detector on-time or are \n",
    "not covered by the time flux profile."
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}