def test_asd_from_freq_series(self): freq_data = np.array([1, 2, 3]) df = 0.1 asd = gwutils.asd_from_freq_series(freq_data, df) self.assertTrue(np.all(asd == freq_data * 2 * df ** 0.5))
def plot_interferometer_waveform_posterior(res, interferometer, level=0.9, n_samples=None, start_time=None, end_time=None, outdir='.', signals_to_plot={}): """ Plot the posterior for the waveform in the frequency domain and whitened time domain. If the strain data is passed that will be plotted. If injection parameters can be found, the injection will be plotted. Parameters ========== interferometer: (str, bilby.gw.detector.interferometer.Interferometer) detector to use, if an Interferometer object is passed the data will be overlaid on the posterior level: float, optional symmetric confidence interval to show, default is 90% n_samples: int, optional number of samples to use to calculate the median/interval default is all start_time: float, optional the amount of time before merger to begin the time domain plot. the merger time is defined as the mean of the geocenter time posterior. Default is - 0.4 end_time: float, optional the amount of time before merger to end the time domain plot. the merger time is defined as the mean of the geocenter time posterior. Default is 0.2 Returns ======= fig: figure-handle, only is save=False Notes ----- To reduce the memory footprint we decimate the frequency domain waveforms to have ~4000 entries. This should be sufficient for decent resolution. """ DATA_COLOR = "#ff7f0e" WAVEFORM_COLOR = "#1f77b4" INJECTION_COLOR = "#000000" if not isinstance(interferometer, bilby.gw.detector.Interferometer): raise TypeError('interferometer type must be Interferometer') logger.info("Generating waveform figure for {}".format( interferometer.name)) if n_samples is None: samples = res.posterior else: samples = res.posterior.sample(n_samples, replace=False) if start_time is None: start_time = -0.4 start_time = np.mean(samples.geocent_time) + start_time if end_time is None: end_time = 0.2 end_time = np.mean(samples.geocent_time) + end_time time_idxs = ((interferometer.time_array >= start_time) & (interferometer.time_array <= end_time)) frequency_idxs = np.where(interferometer.frequency_mask)[0] logger.debug("Frequency mask contains {} values".format( len(frequency_idxs))) frequency_idxs = frequency_idxs[::max(1, len(frequency_idxs) // 4000)] logger.debug("Downsampling frequency mask to {} values".format( len(frequency_idxs))) plot_times = interferometer.time_array[time_idxs] plot_times -= interferometer.strain_data.start_time start_time -= interferometer.strain_data.start_time end_time -= interferometer.strain_data.start_time plot_frequencies = interferometer.frequency_array[frequency_idxs] waveform_arguments = res.waveform_arguments waveform_arguments['waveform_approximant'] = "IMRPhenomPv2" waveform_generator = res.waveform_generator_class( duration=res.duration, sampling_frequency=res.sampling_frequency, start_time=res.start_time, frequency_domain_source_model=res.frequency_domain_source_model, parameter_conversion=res.parameter_conversion, waveform_arguments=waveform_arguments) old_font_size = rcParams["font.size"] rcParams["font.size"] = 20 fig, axs = plt.subplots(2, 1, gridspec_kw=dict(height_ratios=[1.5, 1]), figsize=(16, 12.5)) axs[0].loglog(plot_frequencies, asd_from_freq_series( interferometer.frequency_domain_strain[frequency_idxs], 1 / interferometer.strain_data.duration), color=DATA_COLOR, label='Data', alpha=0.3) axs[0].loglog( plot_frequencies, interferometer.amplitude_spectral_density_array[frequency_idxs], color=DATA_COLOR, label='ASD') axs[1].plot( plot_times, infft(interferometer.whitened_frequency_domain_strain * np.sqrt(2. / interferometer.sampling_frequency), sampling_frequency=interferometer.strain_data.sampling_frequency) [time_idxs], color=DATA_COLOR, alpha=0.3) logger.debug('Plotted interferometer data.') fd_waveforms = list() td_waveforms = list() for _, params in tqdm(samples.iterrows(), desc="Processing Samples", total=len(samples)): try: params = dict(params) wf_pols = waveform_generator.frequency_domain_strain(params) fd_waveform = interferometer.get_detector_response(wf_pols, params) fd_waveforms.append(fd_waveform[frequency_idxs]) td_waveform = infft( fd_waveform * np.sqrt(2. / interferometer.sampling_frequency) / interferometer.amplitude_spectral_density_array, res.sampling_frequency)[time_idxs] except Exception as e: logger.debug(f"ERROR: {e}\nparams: {params}") pass td_waveforms.append(td_waveform) fd_waveforms = asd_from_freq_series( fd_waveforms, 1 / interferometer.strain_data.duration) td_waveforms = np.array(td_waveforms) delta = (1 + level) / 2 upper_percentile = delta * 100 lower_percentile = (1 - delta) * 100 logger.debug('Plotting posterior between the {} and {} percentiles'.format( lower_percentile, upper_percentile)) lower_limit = np.mean(fd_waveforms, axis=0)[0] / 1e3 axs[0].loglog(plot_frequencies, np.mean(fd_waveforms, axis=0), color=WAVEFORM_COLOR, label='Mean reconstructed') axs[0].fill_between(plot_frequencies, np.percentile(fd_waveforms, lower_percentile, axis=0), np.percentile(fd_waveforms, upper_percentile, axis=0), color=WAVEFORM_COLOR, label='{}\% credible interval'.format( int(upper_percentile - lower_percentile)), alpha=0.3) axs[1].plot(plot_times, np.mean(td_waveforms, axis=0), color=WAVEFORM_COLOR) axs[1].fill_between(plot_times, np.percentile(td_waveforms, lower_percentile, axis=0), np.percentile(td_waveforms, upper_percentile, axis=0), color=WAVEFORM_COLOR, alpha=0.3) if len(signals_to_plot) > 0: for d in signals_to_plot: params = d['params'] label = d['label'] col = d['color'] try: hf_inj = waveform_generator.frequency_domain_strain(params) hf_inj_det = interferometer.get_detector_response( hf_inj, params) ht_inj_det = infft( hf_inj_det * np.sqrt(2. / interferometer.sampling_frequency) / interferometer.amplitude_spectral_density_array, res.sampling_frequency)[time_idxs] axs[0].loglog(plot_frequencies, asd_from_freq_series( hf_inj_det[frequency_idxs], 1 / interferometer.strain_data.duration), label=label, linestyle=':', color=col) axs[1].plot(plot_times, ht_inj_det, linestyle=':', color=col) logger.debug('Plotted injection.') except IndexError as e: logger.info( 'Failed to plot injection with message {}.'.format(e)) f_domain_x_label = "$f [\\mathrm{Hz}]$" f_domain_y_label = "$\\mathrm{ASD} \\left[\\mathrm{Hz}^{-1/2}\\right]$" t_domain_x_label = "$t - {} [s]$".format( interferometer.strain_data.start_time) t_domain_y_label = "Whitened Strain" axs[0].set_xlim(interferometer.minimum_frequency, interferometer.maximum_frequency) axs[1].set_xlim(start_time, end_time) axs[0].set_ylim(lower_limit) axs[0].set_xlabel(f_domain_x_label) axs[0].set_ylabel(f_domain_y_label) axs[1].set_xlabel(t_domain_x_label) axs[1].set_ylabel(t_domain_y_label) axs[0].legend(loc='lower left', ncol=2) filename = f"{outdir}/{res.label}_{interferometer.name}_waveform.png" plt.tight_layout() fig.savefig(fname=filename, dpi=600) plt.close() logger.info("Waveform figure saved to {}".format(filename)) rcParams["font.size"] = old_font_size