Interfaces and protocols ======================== The cosipy library has been refactored to make the components required to compute a likelihood modular and interchangeable. These components include the data (binned or event-by-event), the instrument response function (IRF), the convolution of the response with a source model, background models, and the likelihood calculation itself. The goal is to allow users and developers to experiment with new versions of any component—without needing to modify the library core. Implementations of these components do not need to live within cosipy; they only need to comply with the relevant interface definition. This design also preserves flexibility as analysis ideas evolve over the course of the mission, and it makes it easier to switch between different approaches (for example, binned versus unbinned analyses). This modularity is achieved by defining protocols for the interfaces between components. In practice, these are class-level contracts that specify a well-defined set of methods, including their expected inputs and outputs, that other parts of the code can rely on. The protocols describe what must be provided, but they do not prescribe how computations are performed; that is left to the specific implementation. Below we provide an overview of the available interfaces (used interchangeably with “protocols”) and how to use them. We start from the top-most level (the likelihood) and describe all other components needed to compute it. The best place to see practical examples in action is the `Crab spectral fit tutorials `_ (binned and unbinned). Note, however, that not every part of cosipy fully uses these protocols yet; some areas still refer to specific implementations rather than a generic interface. Here's a practical cheat sheet if you want to add/try a new: * Instrument response function (IRF): - Interface: ``InstrumentResponseFunctionInterface`` - Example: ``UnpolarizedDC3InterpolatedFarFieldInstrumentResponseFunction`` * IRF-source convolution: - Interface: ``ThreeMLSourceResponseInterface`` - Examples: ``UnbinnedThreeMLPointSourceResponseTrapz``, ``BinnedThreeMLPointSourceResponse`` * Background model: - Interface: ``BackgroundInterface`` - Example: ``FreeNormBinnedBackground``, ``FreeNormBackgroundInterpolatedDensityTimeTagEmCDS`` * Event selection: - Interface: ``EventSelectorInterface`` - Example: ``TimeSelector`` Likelihood functions -------------------- The ``LikelihoodInterface`` main method is ``get_log_like()``, which a promise for all implementation for result a log-likelihood. The interface, by itself, doesn't define how this will be achieved. AS a concreate example, ``PoissonLikelihood`` needs the observed counts and the expected number of counts, and internally uses the Poisson likelihood function to return the likelihood value. Expectation interfaces ---------------------- Likelihood functions such as ``PoissonLikelihood`` require the expected number of events --on average-- under a model that includes both signal and background contributions. This requirement is codified by the ``ExpectationInterface``. Two variants are provided: ``BinnedExpectationInterface``, which returns the expected number of counts in each bin of a binned dataset, and ``ExpectationDensityInterface``, which provides (1) the total expected number of counts and (2) the expectation density, i.e., the expected counts per unit phase space. The expectation density can be understood as the limit of the expected counts in a bin divided by the bin size as the bin size approaches zero. This form is used by the ``UnbinnedLikelihood``. Expected counts may originate from signal sources or backgrounds. For signal modeling, the hypothetical source is represented by the ``Source`` class from `astromodels `_. This is captured by the ``ThreeMLSourceResponseInterface``, which defines the method ``set_source(source: Source)`` for passing source properties (e.g., position, spectrum, polarization). On its own, ``ThreeMLSourceResponseInterface`` only specifies how a source is provided; it is combined with an ``ExpectationInterface`` to define an class that can accept a ``Source`` and produce expected counts. An example is ``BinnedThreeMLSourceResponseInterface`` (with a corresponding unbinned counterpart). Finally, ThreeMLModelFoldingInterface generalizes this concept to compute expectations for a collection of sources. As you can see, protocols such as ``BinnedThreeMLSourceResponseInterface`` are intentionally abstract. This goal of this design is to constrain implementations as little as possible while still providing a reliable contract for the rest of the code. In practice, an implementation of ``BinnedThreeMLSourceResponseInterface`` will typically compute the expected number of counts by convolving ---i.e. integrate over the relevant dimensions such as time, energy, and direction--- an instrument response function (IRF) with a source model (e.g., spectrum, light curve, and/or morphology). However, the IRF itself is defined by a separate protocol (see below). For backgrounds, we define ``BackgroundInterface``. It is intentionally generic and only requires the ability to pass parameter values via ``set_parameters()``. These parameters are completely user-defined: the interface does not assign them any specific meaning. A common concrete example is a single background normalization, but more complex cases are also supported —for example, multiple background components with independent normalizations, or non-linear parameters such as an exponential index, or even the input to a complex simulation. In a fit, these typically act as nuisance parameters. As with the signal-side expectation, ``BackgroundInterface`` is combined with an ``ExpectationInterface`` to define a complete contract for the required inputs and outputs (i.e., an object that can accept background parameters and return the corresponding expected counts). Instrument Response Functions ----------------------------- The (far-field) instrument response function (IRF) is responsible for providing: (1) the effective area as a function of photon energy and incoming direction (in spacecraft coordinates), and (2) the probability of obtaining a given set of measurements when a photon is detected. These outputs are defined by ``FarFieldInstrumentResponseFunctionInterface`` via the methods ``effective_area_cm()`` and ``event_probability()``, respectively. For binned analyses, ``BinnedInstrumentResponseInterface`` provides ``differential_effective_area``, i.e., the product of ``effective_area_cm`` and ``event_probability`` integrated over each bin of a binned dataset. The interfaces definitions also allow for a near-field IRF, although it has not been developed yet. For a Compton telescope such as COSI, typical measurements include the reconstructed energy, the Compton scattering angle, and the scattering direction. The definition of the measurement space is intentionally not part of the IRF interfaces; instead, it is delegated to the ``EventDataInterface`` (see below). Each IRF implementation must declare which ``EventDataInterface`` subclass it can handle, including any derived subclasses. The IRF also needs to know how it will receive the photon properties being queried (e.g., true energy, direction, and polarization). This is handled by the ``PhotonInterface`` (see below). Data Interfaces --------------- The data interfaces are used as a medium to specify measurements and counts independently of their origin or file format. There are two types: binned data and event (unbinned) data. The ``BinnedData`` interface is currently a thin wrapper around ``histpy``’s ``Histogram``, which contains both the axes for measured quantities and the observed counts (the histogram contents). There are multiple ``EventDataInterface`` derivatives, each specifying a measured value through a property. For example, ``EventDataWithEnergyInterface`` provides the property ``energy_keV``, and ``EventDataWithScatteringAngleInterface`` provides ``scattering_angle_rad``. These properties return iterables, with one entry per event. Their names are descriptive and include the unit. For convenience, properties such as ``energy`` (returning an ``astropy`` ``Quantity``) are also provided, but they are typically slower and should be avoided in performance-critical code. ``EventDataInterface`` types can be combined by creating classes that inherit from multiple interfaces, e.g. ``ComptonDataSpaceInSCFrameEventDataInterface``. In addition, all ``EventDataInterface`` implementations can return an iterable of ``EventInterface`` objects. ``EventInterface`` is similar to ``EventDataInterface``, except that it holds the values for a single event. Photon Interfaces ----------------- ``PhotonInterface`` and ``PhotonListInterface`` work in the same way as ``EventInterface`` and ``EventDataInterface``, respectively. However, their scope is more limited, since a photon’s direction, energy, and polarization are sufficient to fully specify its state. In the future, this may be extended to include the photon origin location to support near-field analyses. Event selection --------------- The ``EventSelectionInterface`` defines a ``select()`` method, which takes either an ``EventDataInterface`` or an ``EventInterface`` object and returns True or False to indicate whether it should be selected. Implementations should specify which ``EventInterface`` type they support; all subclasses of that type are automatically supported. For example, ``TimeSelector`` supports ``TimetagEventInterface`` and therefore also any derived interface such as ``TimeTagEmCDSEventInSCFrameInterface``.