Skip to content

nullpol.analysis.likelihood

nullpol.analysis.likelihood

Likelihood package.

nullpol.analysis.likelihood.Chi2TimeFrequencyLikelihood

Bases: TimeFrequencyLikelihood

A time-frequency likelihood class that computes the likelihood of the total null energy.

Parameters:

Name Type Description Default
interferometers list

List of interferometers.

required
wavelet_frequency_resolution float

The frequency resolution of the wavelet transform.

required
wavelet_nx int

The number of points in the wavelet transform.

required
polarization_modes list

List of polarization modes.

required
polarization_basis list

List of polarization basis.

None
time_frequency_filter str

The time-frequency filter.

None
Source code in src/nullpol/analysis/likelihood/chi2_tf_likelihood.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class Chi2TimeFrequencyLikelihood(TimeFrequencyLikelihood):
    """A time-frequency likelihood class that computes the likelihood of the total null energy.

    Args:
        interferometers (list): List of interferometers.
        wavelet_frequency_resolution (float): The frequency resolution of the wavelet transform.
        wavelet_nx (int): The number of points in the wavelet transform.
        polarization_modes (list): List of polarization modes.
        polarization_basis (list): List of polarization basis.
        time_frequency_filter (str): The time-frequency filter.
    """

    def __init__(
        self,
        interferometers,
        wavelet_frequency_resolution,
        wavelet_nx,
        polarization_modes,
        *args,
        polarization_basis=None,
        time_frequency_filter=None,
        **kwargs,
    ):
        """Initialize the instance."""
        super().__init__(
            *args,
            interferometers=interferometers,
            wavelet_frequency_resolution=wavelet_frequency_resolution,
            wavelet_nx=wavelet_nx,
            polarization_modes=polarization_modes,
            polarization_basis=polarization_basis,
            time_frequency_filter=time_frequency_filter,
            **kwargs,
        )

    @property
    def DoF(self):
        """Degree of freedom.

        Returns:
            int: Degree of freedom.
        """
        polarization_basis_sum = np.sum(self.antenna_pattern_processor.polarization_basis)

        if self.data_context.time_frequency_filter is None:
            raise ValueError("Time frequency filter is not available")

        time_frequency_filter_sum = np.sum(self.data_context.time_frequency_filter)
        return (len(self.interferometers) - polarization_basis_sum) * time_frequency_filter_sum

    def log_likelihood(self):
        """Compute the log likelihood using the projection approach."""
        # Compute null energy using the parameters
        null_energy = self.null_stream_calculator.compute_null_energy(self.parameters)

        return scipy.stats.chi2.logpdf(null_energy, df=self.DoF)

    def _calculate_noise_log_likelihood(self):
        """Calculate the noise log likelihood.

        Returns:
            float: noise log likelihood.
        """
        if self.data_context.whitened_frequency_domain_strain_array is None:
            raise ValueError("Whitened frequency domain strain array is not available")
        if self.data_context.time_frequency_filter is None:
            raise ValueError("Time frequency filter is not available")

        wavelet_domain_strain_array = np.array(
            [
                transform_wavelet_freq(
                    data=self.data_context.whitened_frequency_domain_strain_array[i],
                    sampling_frequency=self.data_context.sampling_frequency,
                    frequency_resolution=self.data_context.wavelet_frequency_resolution,
                    nx=self.data_context.wavelet_nx,
                )
                for i in range(len(self.interferometers))
            ]
        )
        E = np.sum(np.abs(wavelet_domain_strain_array * self.data_context.time_frequency_filter) ** 2)
        log_likelihood = scipy.stats.chi2.logpdf(
            E, df=len(self.interferometers) * np.sum(self.data_context.time_frequency_filter)
        )
        return log_likelihood

nullpol.analysis.likelihood.Chi2TimeFrequencyLikelihood.data_context property

Access to the data context through null_stream_calculator.

Returns:

Name Type Description
TimeFrequencyDataContext

The data context instance.

nullpol.analysis.likelihood.Chi2TimeFrequencyLikelihood.antenna_pattern_processor property

Access to the antenna pattern processor through null_stream_calculator.

Returns:

Name Type Description
AntennaPatternProcessor

The antenna pattern processor instance.

nullpol.analysis.likelihood.Chi2TimeFrequencyLikelihood.interferometers property

A list of interferometers.

Returns:

Type Description

bilby.gw.detector.InterferometerList: A list of interferometers.

nullpol.analysis.likelihood.Chi2TimeFrequencyLikelihood.DoF property

Degree of freedom.

Returns:

Name Type Description
int

Degree of freedom.

nullpol.analysis.likelihood.Chi2TimeFrequencyLikelihood.noise_log_likelihood()

Compute the noise log likelihood.

Returns:

Name Type Description
float

The noise log likelihood.

Source code in src/nullpol/analysis/likelihood/time_frequency_likelihood.py
107
108
109
110
111
112
113
114
115
def noise_log_likelihood(self):
    """Compute the noise log likelihood.

    Returns:
        float: The noise log likelihood.
    """
    if self._noise_log_likelihood_value is None:
        self._noise_log_likelihood_value = self._calculate_noise_log_likelihood()
    return self._noise_log_likelihood_value

nullpol.analysis.likelihood.Chi2TimeFrequencyLikelihood.log_likelihood()

Compute the log likelihood using the projection approach.

Source code in src/nullpol/analysis/likelihood/chi2_tf_likelihood.py
63
64
65
66
67
68
def log_likelihood(self):
    """Compute the log likelihood using the projection approach."""
    # Compute null energy using the parameters
    null_energy = self.null_stream_calculator.compute_null_energy(self.parameters)

    return scipy.stats.chi2.logpdf(null_energy, df=self.DoF)

nullpol.analysis.likelihood.TimeFrequencyLikelihood

Bases: Likelihood

A time-frequency likelihood class with modular architecture.

This class uses composition to separate concerns: - Data management and antenna pattern operations are handled by NullStreamCalculator - Null stream computations are handled by NullStreamCalculator

For low-level data access, use: likelihood.null_stream_calculator.data_context.property_name For antenna pattern operations, use: likelihood.null_stream_calculator.antenna_pattern_processor.method_name For null stream computations, use: likelihood.null_stream_calculator.method_name For high-level likelihood operations, use the methods on this class directly.

Parameters:

Name Type Description Default
interferometers list

List of interferometers.

required
wavelet_frequency_resolution float

The frequency resolution of the wavelet transform.

required
wavelet_nx int

The number of points in the wavelet transform.

required
polarization_modes list

List of polarization modes.

required
polarization_basis list

List of polarization basis.

None
time_frequency_filter str

The time-frequency filter.

None
Source code in src/nullpol/analysis/likelihood/time_frequency_likelihood.py
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
class TimeFrequencyLikelihood(Likelihood):
    """A time-frequency likelihood class with modular architecture.

    This class uses composition to separate concerns:
    - Data management and antenna pattern operations are handled by NullStreamCalculator
    - Null stream computations are handled by NullStreamCalculator

    For low-level data access, use: likelihood.null_stream_calculator.data_context.property_name
    For antenna pattern operations, use: likelihood.null_stream_calculator.antenna_pattern_processor.method_name
    For null stream computations, use: likelihood.null_stream_calculator.method_name
    For high-level likelihood operations, use the methods on this class directly.

    Args:
        interferometers (list): List of interferometers.
        wavelet_frequency_resolution (float): The frequency resolution of the wavelet transform.
        wavelet_nx (int): The number of points in the wavelet transform.
        polarization_modes (list): List of polarization modes.
        polarization_basis (list): List of polarization basis.
        time_frequency_filter (str): The time-frequency filter.
    """

    def __init__(
        self,
        interferometers,
        wavelet_frequency_resolution,
        wavelet_nx,
        polarization_modes,
        *args,  # pylint: disable=unused-argument
        polarization_basis=None,
        time_frequency_filter=None,
        **kwargs,  # pylint: disable=unused-argument
    ):
        """Initialize the instance."""
        super().__init__({})

        # Initialize null stream calculator with all components
        self.null_stream_calculator = NullStreamCalculator(
            interferometers=interferometers,
            wavelet_frequency_resolution=wavelet_frequency_resolution,
            wavelet_nx=wavelet_nx,
            polarization_modes=polarization_modes,
            polarization_basis=polarization_basis,
            time_frequency_filter=time_frequency_filter,
        )

        # Initialize the normalization constant
        self._noise_log_likelihood_value = None

        # Marginalization
        self._marginalized_parameters = []

    @property
    def data_context(self):
        """Access to the data context through null_stream_calculator.

        Returns:
            TimeFrequencyDataContext: The data context instance.
        """
        return self.null_stream_calculator.data_context

    @property
    def antenna_pattern_processor(self):
        """Access to the antenna pattern processor through null_stream_calculator.

        Returns:
            AntennaPatternProcessor: The antenna pattern processor instance.
        """
        return self.null_stream_calculator.antenna_pattern_processor

    @property
    def interferometers(self):
        """A list of interferometers.

        Returns:
            bilby.gw.detector.InterferometerList: A list of interferometers.
        """
        return self.null_stream_calculator.data_context.interferometers

    def log_likelihood(self):
        """Log likelihood.

        Raises:
            NotImplementedError: This should be implemented in a subclass.
        """
        raise NotImplementedError("The log_likelihood method must be implemented in a subclass.")

    def _calculate_noise_log_likelihood(self):
        """Calculate noise log likelihood.

        This should be implemented in a subclass.

        Raises:
            NotImplementedError: This should be implemented in a subclass.
        """
        raise NotImplementedError("The _calculate_noise_log_likelihood method must be implemented in a subclass.")

    def noise_log_likelihood(self):
        """Compute the noise log likelihood.

        Returns:
            float: The noise log likelihood.
        """
        if self._noise_log_likelihood_value is None:
            self._noise_log_likelihood_value = self._calculate_noise_log_likelihood()
        return self._noise_log_likelihood_value

nullpol.analysis.likelihood.TimeFrequencyLikelihood.data_context property

Access to the data context through null_stream_calculator.

Returns:

Name Type Description
TimeFrequencyDataContext

The data context instance.

nullpol.analysis.likelihood.TimeFrequencyLikelihood.antenna_pattern_processor property

Access to the antenna pattern processor through null_stream_calculator.

Returns:

Name Type Description
AntennaPatternProcessor

The antenna pattern processor instance.

nullpol.analysis.likelihood.TimeFrequencyLikelihood.interferometers property

A list of interferometers.

Returns:

Type Description

bilby.gw.detector.InterferometerList: A list of interferometers.

nullpol.analysis.likelihood.TimeFrequencyLikelihood.log_likelihood()

Log likelihood.

Raises:

Type Description
NotImplementedError

This should be implemented in a subclass.

Source code in src/nullpol/analysis/likelihood/time_frequency_likelihood.py
89
90
91
92
93
94
95
def log_likelihood(self):
    """Log likelihood.

    Raises:
        NotImplementedError: This should be implemented in a subclass.
    """
    raise NotImplementedError("The log_likelihood method must be implemented in a subclass.")

nullpol.analysis.likelihood.TimeFrequencyLikelihood.noise_log_likelihood()

Compute the noise log likelihood.

Returns:

Name Type Description
float

The noise log likelihood.

Source code in src/nullpol/analysis/likelihood/time_frequency_likelihood.py
107
108
109
110
111
112
113
114
115
def noise_log_likelihood(self):
    """Compute the noise log likelihood.

    Returns:
        float: The noise log likelihood.
    """
    if self._noise_log_likelihood_value is None:
        self._noise_log_likelihood_value = self._calculate_noise_log_likelihood()
    return self._noise_log_likelihood_value