From 08336df0b76049a9b2fb08f67245e868426b457d Mon Sep 17 00:00:00 2001 From: Colm Talbot <colm.talbot@ligo.org> Date: Fri, 28 Oct 2022 12:26:31 -0700 Subject: [PATCH] remove old relbin file --- bilby/gw/likelihood/relbin.py | 626 ---------------------------------- 1 file changed, 626 deletions(-) delete mode 100644 bilby/gw/likelihood/relbin.py diff --git a/bilby/gw/likelihood/relbin.py b/bilby/gw/likelihood/relbin.py deleted file mode 100644 index 1936d2fb1..000000000 --- a/bilby/gw/likelihood/relbin.py +++ /dev/null @@ -1,626 +0,0 @@ -import numpy as np -from .base import GravitationalWaveTransient -from ...core.utils import logger, create_time_series -from ...core.prior.base import Constraint -from ...core.prior import Interped, DeltaFunction -from ..utils import noise_weighted_inner_product, ln_i0 -from scipy.optimize import differential_evolution -import copy - - -class RelativeBinningGravitationalWaveTransient(GravitationalWaveTransient): - """A gravitational-wave transient likelihood object which uses the relative - binning procedure to calculate a fast likelihood. See IAS paper: - - - Parameters - ---------- - interferometers: list, bilby.gw.detector.InterferometerList - A list of `bilby.detector.Interferometer` instances - contains the - detector data and power spectral densities - waveform_generator: `bilby.waveform_generator.WaveformGenerator` - An object which computes the frequency-domain strain of the signal, - given some set of parameters - fiducial_parameters: dict, optional - A starting guess for initial parameters of the event for finding the - maximum likelihood (fiducial) waveform. - parameter_bounds: dict, optional - Dictionary of bounds (lists) for the initial parameters when finding - the initial maximum likelihood (fiducial) waveform. - distance_marginalization: bool, optional - If true, marginalize over distance in the likelihood. - This uses a look up table calculated at run time. - The distance prior is set to be a delta function at the minimum - distance allowed in the prior being marginalised over. - time_marginalization: bool, optional - If true, marginalize over time in the likelihood. - This uses a FFT to calculate the likelihood over a regularly spaced - grid. - In order to cover the whole space the prior is set to be uniform over - the spacing of the array of times. - If using time marginalisation and jitter_time is True a "jitter" - parameter is added to the prior which modifies the position of the - grid of times. - phase_marginalization: bool, optional - If true, marginalize over phase in the likelihood. - This is done analytically using a Bessel function. - The phase prior is set to be a delta function at phase=0. - priors: dict, optional - If given, used in the distance and phase marginalization. - distance_marginalization_lookup_table: (dict, str), optional - If a dict, dictionary containing the lookup_table, distance_array, - (distance) prior_array, and reference_distance used to construct - the table. - If a string the name of a file containing these quantities. - The lookup table is stored after construction in either the - provided string or a default location: - '.distance_marginalization_lookup_dmin{}_dmax{}_n{}.npz' - jitter_time: bool, optional - Whether to introduce a `time_jitter` parameter. This avoids either - missing the likelihood peak, or introducing biases in the - reconstructed time posterior due to an insufficient sampling frequency. - Default is False, however using this parameter is strongly encouraged. - reference_frame: (str, bilby.gw.detector.InterferometerList, list), optional - Definition of the reference frame for the sky location. - - "sky": sample in RA/dec, this is the default - - e.g., "H1L1", ["H1", "L1"], InterferometerList(["H1", "L1"]): - sample in azimuth and zenith, `azimuth` and `zenith` defined in the - frame where the z-axis is aligned the the vector connecting H1 - and L1. - time_reference: str, optional - Name of the reference for the sampled time parameter. - - "geocent"/"geocenter": sample in the time at the Earth's center, - this is the default - - e.g., "H1": sample in the time of arrival at H1 - chi: float, optional - Tunable parameter which limits the perturbation of alpha when setting - up the bin range. See https://arxiv.org/abs/1806.08792. - epsilon: float, optional - Tunable parameter which limits the differential phase change in each - bin when setting up the bin range. See https://arxiv.org/abs/1806.08792. - - Returns - ------- - Likelihood: `bilby.core.likelihood.Likelihood` - A likelihood object, able to compute the likelihood of the data given - some model parameters. - """ - - def __init__(self, interferometers, - waveform_generator, - fiducial_parameters={}, parameter_bounds=None, - maximization_kwargs=dict(), - update_fiducial_parameters=False, - distance_marginalization=False, - time_marginalization=False, - phase_marginalization=False, - priors=None, - distance_marginalization_lookup_table=None, - jitter_time=True, - reference_frame="sky", - time_reference="geocenter", - chi=1, - epsilon=0.5): - - super(RelativeBinningGravitationalWaveTransient, self).__init__( - interferometers=interferometers, - waveform_generator=waveform_generator, - distance_marginalization=distance_marginalization, - phase_marginalization=phase_marginalization, - time_marginalization=time_marginalization, - priors=priors, - distance_marginalization_lookup_table=distance_marginalization_lookup_table, - jitter_time=jitter_time, - reference_frame=reference_frame, - time_reference=time_reference) - - self.fiducial_parameters = fiducial_parameters - self.chi = chi - self.epsilon = epsilon - self.gamma = np.array([-5 / 3, -2 / 3, 1, 5 / 3, 7 / 3]) - self.fiducial_waveform_obtained = False - self.check_if_bins_are_setup = False - self.fiducial_polarizations = None - self.per_detector_fiducial_waveforms = {} - self.bin_freqs = dict() - self.bin_inds = dict() - self.set_fiducial_waveforms(self.fiducial_parameters) - logger.info("Initial fiducial waveforms set up") - self.setup_bins() - self.compute_summary_data() - logger.info("Summary Data Obtained") - - if update_fiducial_parameters: - # write a check to make sure prior is not None - logger.info("Using scipy optimization to find maximum likelihood parameters.") - self.parameters_to_be_updated = [key for key in self.priors if not isinstance( - self.priors[key], (DeltaFunction, Constraint))] - logger.info("Parameters over which likelihood is maximized: {}".format(self.parameters_to_be_updated)) - if parameter_bounds is None: - logger.info("No parameter bounds were given. Using priors instead.") - self.parameter_bounds = self.get_bounds_from_priors(self.priors) - else: - self.parameter_bounds = self.get_parameter_list_from_dictionary(parameter_bounds) - self.fiducial_parameters = self.find_maximum_likelihood_parameters( - self.parameter_bounds, maximization_kwargs=maximization_kwargs) - - def __repr__(self): - return self.__class__.__name__ + '(interferometers={},\n\twaveform_generator={},\n\fiducial_parameters={},' \ - .format(self.interferometers, self.waveform_generator, self.fiducial_parameters) - - def setup_bins(self): - frequency_array = self.waveform_generator.frequency_array - gamma = self.gamma - for interferometer in self.interferometers: - frequency_array_useful = frequency_array[np.intersect1d( - np.where(frequency_array >= interferometer.minimum_frequency), - np.where(frequency_array <= interferometer.maximum_frequency))] - - d_alpha = self.chi * 2 * np.pi / np.abs( - (interferometer.minimum_frequency ** gamma) * np.heaviside( - -gamma, 1) - (interferometer.maximum_frequency ** gamma) * np.heaviside( - gamma, 1)) - d_phi = np.sum(np.array([np.sign(gamma[i]) * d_alpha[i] * ( - frequency_array_useful ** gamma[i]) for i in range(len(gamma))]), axis=0) - d_phi_from_start = d_phi - d_phi[0] - self.number_of_bins = int(d_phi_from_start[-1] // self.epsilon) - self.bin_freqs[interferometer.name] = np.zeros(self.number_of_bins + 1) - self.bin_inds[interferometer.name] = np.zeros(self.number_of_bins + 1, dtype=np.int) - - for i in range(self.number_of_bins + 1): - bin_index = np.where(d_phi_from_start >= ((i / self.number_of_bins) * d_phi_from_start[-1]))[0][0] - bin_freq = frequency_array_useful[bin_index] - self.bin_freqs[interferometer.name][i] = bin_freq - self.bin_inds[interferometer.name][i] = np.where(frequency_array >= bin_freq)[0][0] - - logger.info("Set up {} bins for {} between {} Hz and {} Hz".format( - self.number_of_bins, interferometer.name, interferometer.minimum_frequency, - interferometer.maximum_frequency)) - self.waveform_generator.waveform_arguments["frequency_bin_edges"] = self.bin_freqs[interferometer.name] - return - - def set_fiducial_waveforms(self, parameters): - parameters["fiducial"] = 1 - self.fiducial_polarizations = self.waveform_generator.frequency_domain_strain( - parameters) - - maximum_nonzero_index = np.where(self.fiducial_polarizations["plus"] != 0j)[0][-1] - logger.info("Maximum Nonzero Index is {}".format(maximum_nonzero_index)) - maximum_nonzero_frequency = self.waveform_generator.frequency_array[maximum_nonzero_index] - logger.info("Maximum Nonzero Frequency is {}".format(maximum_nonzero_frequency)) - - if self.fiducial_polarizations is None: - return np.nan_to_num(-np.inf) - - for interferometer in self.interferometers: - logger.info("Maximum Frequency is {}".format(interferometer.maximum_frequency)) - if interferometer.maximum_frequency > maximum_nonzero_frequency: - interferometer.maximum_frequency = maximum_nonzero_frequency - - self.per_detector_fiducial_waveforms[interferometer.name] = ( - interferometer.get_detector_response( - self.fiducial_polarizations, parameters)) - parameters["fiducial"] = 0 - return - - def log_likelihood(self): - return self.log_likelihood_ratio() + self.noise_log_likelihood() - - def log_likelihood_ratio(self): - self.parameters.update(self.get_sky_frame_parameters()) - - d_inner_h = 0. - optimal_snr_squared = 0. - complex_matched_filter_snr = 0. - waveform_ratio = self.compute_waveform_ratio(self.parameters) - - if self.time_marginalization: - if self.jitter_time: - self.parameters['geocent_time'] += self.parameters['time_jitter'] - d_inner_h_tc_array = np.zeros( - self.interferometers.frequency_array[0:-1].shape, - dtype=np.complex128) - - for interferometer in self.interferometers: - per_detector_snr = self.calculate_snrs_relative_binning( - waveform_ratio[interferometer.name], interferometer) - d_inner_h += per_detector_snr.d_inner_h - optimal_snr_squared += np.real(per_detector_snr.optimal_snr_squared) - complex_matched_filter_snr += per_detector_snr.complex_matched_filter_snr - - if self.time_marginalization: - d_inner_h_tc_array += per_detector_snr.d_inner_h_squared_tc_array - - if self.time_marginalization: - log_l = self.time_marginalized_likelihood( - d_inner_h_tc_array=d_inner_h_tc_array, - h_inner_h=optimal_snr_squared) - if self.jitter_time: - self.parameters['geocent_time'] -= self.parameters['time_jitter'] - - elif self.distance_marginalization: - log_l = self.distance_marginalized_likelihood( - d_inner_h=d_inner_h, h_inner_h=optimal_snr_squared) - - elif self.phase_marginalization: - log_l = self.phase_marginalized_likelihood( - d_inner_h=d_inner_h, h_inner_h=optimal_snr_squared) - - else: - log_l = np.real(d_inner_h) - optimal_snr_squared / 2 - - return float(log_l.real) - - def find_maximum_likelihood_parameters(self, parameter_bounds, - iterations=1, maximization_kwargs=dict()): - - for i in range(iterations): - logger.info("Optimizing fiducial parameters. Iteration : {}".format(i + 1)) - output = differential_evolution(self.lnlike_scipy_maximize, - bounds=parameter_bounds, **maximization_kwargs) - updated_parameters_list = output['x'] - updated_parameters = self.get_parameter_dictionary_from_list(updated_parameters_list) - self.set_fiducial_waveforms(updated_parameters) - self.compute_summary_data() - - logger.info("Fiducial waveforms updated") - logger.info("Summary Data updated") - return updated_parameters - - def lnlike_scipy_maximize(self, parameter_list): - self.parameters = self.get_parameter_dictionary_from_list(parameter_list) - return -self.log_likelihood_ratio() - - def get_parameter_dictionary_from_list(self, parameter_list): - parameter_dictionary = dict(zip(self.parameters_to_be_updated, parameter_list)) - excluded_parameter_keys = set(self.fiducial_parameters) - set(self.parameters_to_be_updated) - for key in excluded_parameter_keys: - parameter_dictionary[key] = self.fiducial_parameters[key] - return parameter_dictionary - - def get_parameter_list_from_dictionary(self, parameter_dict): - return [parameter_dict[k] for k in self.parameters_to_be_updated] - - def get_bounds_from_priors(self, priors): - bounds = [] - for key in self.parameters_to_be_updated: - bounds.append([priors[key].minimum, priors[key].maximum]) - return bounds - - def compute_summary_data(self): - summary_data = dict() - - for interferometer in self.interferometers: - mask = interferometer.frequency_mask - masked_frequency_array = interferometer.frequency_array[mask] - masked_bin_inds = [] - for edge in self.bin_freqs[interferometer.name]: - index = np.where(masked_frequency_array == edge)[0][0] - masked_bin_inds.append(index) - masked_strain = interferometer.frequency_domain_strain[mask] - masked_h0 = self.per_detector_fiducial_waveforms[interferometer.name][mask] - masked_psd = interferometer.power_spectral_density_array[mask] - a0, b0, a1, b1 = np.zeros((4, self.number_of_bins), dtype=np.complex) - - for i in range(self.number_of_bins): - - central_frequency_i = 0.5 * \ - (masked_frequency_array[masked_bin_inds[i]] + masked_frequency_array[masked_bin_inds[i + 1]]) - masked_strain_i = masked_strain[masked_bin_inds[i]:masked_bin_inds[i + 1]] - masked_h0_i = masked_h0[masked_bin_inds[i]:masked_bin_inds[i + 1]] - masked_psd_i = masked_psd[masked_bin_inds[i]:masked_bin_inds[i + 1]] - masked_frequency_i = masked_frequency_array[masked_bin_inds[i]:masked_bin_inds[i + 1]] - - a0[i] = noise_weighted_inner_product( - masked_h0_i, - masked_strain_i, - masked_psd_i, - self.waveform_generator.duration) - - b0[i] = noise_weighted_inner_product( - masked_h0_i, - masked_h0_i, - masked_psd_i, - self.waveform_generator.duration) - - a1[i] = noise_weighted_inner_product( - masked_h0_i, - masked_strain_i * (masked_frequency_i - central_frequency_i), - masked_psd_i, - self.waveform_generator.duration) - - b1[i] = noise_weighted_inner_product( - masked_h0_i, - masked_h0_i * (masked_frequency_i - central_frequency_i), - masked_psd_i, - self.waveform_generator.duration) - - summary_data[interferometer.name] = dict(a0=a0, a1=a1, b0=b0, b1=b1) - - self.summary_data = summary_data - - def compute_waveform_ratio(self, parameters): - waveform_ratio = dict() - self.waveform_generator.parameters = parameters - new_polarizations = self.waveform_generator.frequency_domain_strain(parameters) - for interferometer in self.interferometers: - h = interferometer.get_detector_response_relative_binning( - new_polarizations, parameters, self.bin_freqs[interferometer.name]) - h0 = self.per_detector_fiducial_waveforms[interferometer.name][self.bin_inds[interferometer.name]] - waveform_ratio_per_detector = h / h0 - - r0 = (waveform_ratio_per_detector[1:] + waveform_ratio_per_detector[:-1]) / 2 - r1 = (waveform_ratio_per_detector[1:] - waveform_ratio_per_detector[:-1]) / ( - self.bin_freqs[interferometer.name][1:] - self.bin_freqs[interferometer.name][:-1]) - - waveform_ratio[interferometer.name] = [r0, r1] - - return waveform_ratio - - def calculate_snrs_relative_binning(self, waveform_ratio_per_detector, interferometer): - summary_data_per_interferometer = self.summary_data[interferometer.name] - a0 = summary_data_per_interferometer["a0"] - a1 = summary_data_per_interferometer["a1"] - b0 = summary_data_per_interferometer["b0"] - b1 = summary_data_per_interferometer["b1"] - - r0, r1 = waveform_ratio_per_detector - - d_inner_h = np.sum(a0 * np.conjugate(r0) + a1 * np.conjugate(r1)) - h_inner_h = np.sum(b0 * np.abs(r0) ** 2 + 2 * b1 * np.real( - r0 * np.conjugate(r1))) - optimal_snr_squared = h_inner_h - complex_matched_filter_snr = d_inner_h / (optimal_snr_squared ** 0.5) - - if self.time_marginalization: - f = interferometer.frequency_array - duplicated_r0, duplicated_r1, duplicated_fm = np.zeros((3, f.shape[0]), dtype=np.complex) - - for i in range(self.number_of_bins): - ind = self.bin_inds[interferometer.name] - fm = 0.5 * (self.bin_freqs[interferometer.name][1:] + self.bin_freqs[interferometer.name][:-1]) - duplicated_fm[ind[i]:ind[i + 1]] = fm[i] - duplicated_r0[ind[i]:ind[i + 1]] = r0[i] - duplicated_r1[ind[i]:ind[i + 1]] = r1[i] - - duplicated_r = duplicated_r0 + duplicated_r1 * (f - duplicated_fm) - - d_inner_h_squared_tc_array = 4 / self.waveform_generator.duration * np.fft.fft( - self.per_detector_fiducial_waveforms[interferometer.name][0:-1] * - interferometer.frequency_domain_strain.conjugate()[0:-1] * - duplicated_r[0:-1] / interferometer.power_spectral_density_array[0:-1]) - - else: - d_inner_h_squared_tc_array = None - - return self._CalculatedSNRs( - d_inner_h=d_inner_h, optimal_snr_squared=optimal_snr_squared, - complex_matched_filter_snr=complex_matched_filter_snr, - d_inner_h_array=None, optimal_snr_squared_array=None, - d_inner_h_squared_tc_array=d_inner_h_squared_tc_array) - - def generate_posterior_sample_from_marginalized_likelihood(self): - """ - Reconstruct the distance posterior from a run which used a likelihood - which explicitly marginalised over time/distance/phase. - - See Eq. (C29-C32) of https://arxiv.org/abs/1809.02293 - - Return - ------ - sample: dict - Returns the parameters with new samples. - - Notes - ----- - This involves a deepcopy of the signal to avoid issues with waveform - caching, as the signal is overwritten in place. - """ - if any([self.phase_marginalization, self.distance_marginalization, - self.time_marginalization]): - waveform_ratio = copy.deepcopy( - self.compute_waveform_ratio(self.parameters)) - else: - return self.parameters - if self.time_marginalization: - new_time = self.generate_time_sample_from_marginalized_likelihood( - waveform_ratio=waveform_ratio) - self.parameters['geocent_time'] = new_time - if self.distance_marginalization: - new_distance = self.generate_distance_sample_from_marginalized_likelihood( - waveform_ratio=waveform_ratio) - self.parameters['luminosity_distance'] = new_distance - if self.phase_marginalization: - new_phase = self.generate_phase_sample_from_marginalized_likelihood( - waveform_ratio=waveform_ratio) - self.parameters['phase'] = new_phase - return self.parameters.copy() - - def generate_time_sample_from_marginalized_likelihood( - self, waveform_ratio=None): - """ - Generate a single sample from the posterior distribution for coalescence - time when using a likelihood which explicitly marginalises over time. - - In order to resolve the posterior we artificially upsample to 16kHz. - - See Eq. (C29-C32) of https://arxiv.org/abs/1809.02293 - - Parameters - ---------- - waveform_ratio: dict, optional - contains waveform ratios for all interferometers. - - Returns - ------- - new_time: float - Sample from the time posterior. - """ - self.parameters.update(self.get_sky_frame_parameters()) - if self.jitter_time: - self.parameters['geocent_time'] += self.parameters['time_jitter'] - if waveform_ratio is None: - waveform_ratio = \ - self.compute_waveform_ratio(self.parameters) - - times = create_time_series( - sampling_frequency=16384, - starting_time=self.parameters['geocent_time'] - self.waveform_generator.start_time, - duration=self.waveform_generator.duration) - times = times % self.waveform_generator.duration - times += self.waveform_generator.start_time - - prior = self.priors["geocent_time"] - in_prior = (times >= prior.minimum) & (times < prior.maximum) - times = times[in_prior] - - n_time_steps = int(self.waveform_generator.duration * 16384) - d_inner_h = np.zeros(len(times), dtype=np.complex) - psd = np.ones(n_time_steps) - signal_long = np.zeros(n_time_steps, dtype=np.complex) - data = np.zeros(n_time_steps, dtype=np.complex) - h_inner_h = np.zeros(1) - for ifo in self.interferometers: - f = ifo.frequency_array - ifo_length = len(f) - mask = ifo.frequency_mask - r0, r1 = waveform_ratio[ifo.name] - duplicated_r0, duplicated_r1, duplicated_fm = np.zeros((3, ifo_length), dtype=np.complex) - for i in range(self.number_of_bins): - ind = self.bin_inds[ifo.name] - fm = 0.5 * (self.bin_freqs[ifo.name][1:] + self.bin_freqs[ifo.name][:-1]) - duplicated_fm[ind[i]:ind[i + 1]] = fm[i] - duplicated_r0[ind[i]:ind[i + 1]] = r0[i] - duplicated_r1[ind[i]:ind[i + 1]] = r1[i] - duplicated_r = duplicated_r0 + duplicated_r1 * (f - duplicated_fm) - signal = duplicated_r * self.per_detector_fiducial_waveforms[ifo.name] - signal_long[:ifo_length] = signal - data[:ifo_length] = np.conj(ifo.frequency_domain_strain) - psd[:ifo_length][mask] = ifo.power_spectral_density_array[mask] - d_inner_h += np.fft.fft(signal_long * data / psd)[in_prior] - h_inner_h += ifo.optimal_snr_squared(signal=signal).real - - if self.distance_marginalization: - time_log_like = self.distance_marginalized_likelihood( - d_inner_h, h_inner_h) - elif self.phase_marginalization: - time_log_like = (ln_i0(abs(d_inner_h)) - - h_inner_h.real / 2) - else: - time_log_like = (d_inner_h.real - h_inner_h.real / 2) - - time_prior_array = self.priors['geocent_time'].prob(times) - time_post = ( - np.exp(time_log_like - max(time_log_like)) * time_prior_array) - - keep = (time_post > max(time_post) / 1000) - if sum(keep) < 3: - keep[1:-1] = keep[1:-1] | keep[2:] | keep[:-2] - time_post = time_post[keep] - times = times[keep] - - new_time = Interped(times, time_post).sample() - return new_time - - def generate_distance_sample_from_marginalized_likelihood( - self, waveform_ratio=None): - """ - Generate a single sample from the posterior distribution for luminosity - distance when using a likelihood which explicitly marginalises over - distance. - - See Eq. (C29-C32) of https://arxiv.org/abs/1809.02293 - - Parameters - ---------- - signal_polarizations: dict, optional - Polarizations modes of the template. - Note: These are rescaled in place after the distance sample is - generated to allow further parameter reconstruction to occur. - - Returns - ------- - new_distance: float - Sample from the distance posterior. - """ - self.parameters.update(self.get_sky_frame_parameters()) - if waveform_ratio is None: - waveform_ratio = \ - self.compute_waveform_ratio(self.parameters) - d_inner_h, h_inner_h = self._calculate_inner_products(waveform_ratio) - - d_inner_h_dist = ( - d_inner_h * self.parameters['luminosity_distance'] / - self._distance_array) - - h_inner_h_dist = ( - h_inner_h * self.parameters['luminosity_distance']**2 / - self._distance_array**2) - - if self.phase_marginalization: - distance_log_like = ( - ln_i0(abs(d_inner_h_dist)) - - h_inner_h_dist.real / 2) - else: - distance_log_like = (d_inner_h_dist.real - h_inner_h_dist.real / 2) - - distance_post = (np.exp(distance_log_like - max(distance_log_like)) * - self.distance_prior_array) - - new_distance = Interped( - self._distance_array, distance_post).sample() - - self._rescale_signal(waveform_ratio, new_distance) - return new_distance - - def _rescale_signal(self, waveform_ratio, new_distance): - for ifo in self.interferometers: - for i in range(2): - waveform_ratio[ifo.name][i] *= self._ref_dist / new_distance - - def _calculate_inner_products(self, waveform_ratio): - d_inner_h = 0 - h_inner_h = 0 - for interferometer in self.interferometers: - waveform_ratio_per_detector = waveform_ratio[interferometer.name] - per_detector_snr = self.calculate_snrs_relative_binning( - waveform_ratio_per_detector, interferometer) - - d_inner_h += per_detector_snr.d_inner_h - h_inner_h += per_detector_snr.optimal_snr_squared - return d_inner_h, h_inner_h - - def generate_phase_sample_from_marginalized_likelihood( - self, waveform_ratio=None): - """ - Generate a single sample from the posterior distribution for phase when - using a likelihood which explicitly marginalises over phase. - - See Eq. (C29-C32) of https://arxiv.org/abs/1809.02293 - - Parameters - ---------- - signal_polarizations: dict, optional - Polarizations modes of the template. - - Returns - ------- - new_phase: float - Sample from the phase posterior. - - Notes - ----- - This is only valid when assumes that mu(phi) propto exp(-2i phi). - """ - self.parameters.update(self.get_sky_frame_parameters()) - if waveform_ratio is None: - waveform_ratio = \ - self.compute_waveform_ratio(self.parameters) - d_inner_h, h_inner_h = self._calculate_inner_products(waveform_ratio) - - phases = np.linspace(0, 2 * np.pi, 101) - phasor = np.exp(-2j * phases) - phase_log_post = d_inner_h * phasor - h_inner_h / 2 - phase_post = np.exp(phase_log_post.real - max(phase_log_post.real)) - new_phase = Interped(phases, phase_post).sample() - return new_phase -- GitLab