Source code for pespace.inference.likelihood_ti

"""Taichi backend of the Whittle likelihood kernel.

This module contains the taichi kernel for the Whittle likelihood
computation, used by
:class:`~pespace.inference.interface_bilby.LikelihoodBilbyInterfaceTaichi`.

Important: this module must *not* use ``from __future__ import annotations``
(PEP 563). Taichi parses kernel annotations at decoration time and requires
the actual annotation objects (e.g., ``ti.template()``); with PEP 563 all
annotations become strings and the kernel definition fails with a
``TaichiSyntaxError``.
"""

import taichi as ti


[docs] @ti.kernel def compute_whittle_likelihood_ti( channels: ti.template(), observed_data: ti.template(), response_data: ti.template(), psd: ti.template(), df: float, ) -> float: """Compute the Whittle likelihood. Parameters ---------- channels : ti.template() Specifying the TDI channels to iterate over. Used with ``ti.static()`` for compile-time loop unrolling. observed_data : ti.template() ``taichi.field`` containing the observed frequency-domain data for each channel. Expected to be a field of ``ti.types.vector(2, float)`` indexed by frequency bin and channel. response_data : ti.template() ``taichi.field`` containing detector responses for each channel, having the same structure as ``observed_data``. psd : ti.template() ``taichi.field`` containing the noise power spectral density for each channel. Expected to be a real-valued field indexed by frequency bin and channel. df : float Spacing between frequency bins in Hz. Returns ------- float The log-likelihood value computed using the Whittle approximation. Notes ----- - Uses Array-of-Structures (AoS) layout for ``StructField``, with the channel loop placed inside the frequency loop for optimal memory accessing - Atomic operations are used to accumulate the log-likelihood to ensure thread safety in parallel execution """ log_l = 0.0 for i in observed_data: inner_product = 0.0 for chan in ti.static(channels): # AoS is used for StructField, placing the loop of channels inside. inner_product += ( observed_data[i][chan] - response_data[i][chan] ).norm_sqr() / psd[i][chan] ti.atomic_add(log_l, inner_product) log_l *= -2 * df return log_l