Parameterization and Waveform Differences

GWCorrect v0.20.2

In this tutorial, we demonstrate using this package to load in and use parameterized sets of waveform differences as well as how to generate these sets ourselves. This notebook can be downloaded here.

The following cell is everything we need to import to run this tutorial. We also import the GWCorrect package, which will need to be installed first. See Installation.

[2]:
import os
import numpy as np
import bilby
import matplotlib.pyplot as plt
import sys
import scipy
import lal
import random
from pesummary.gw.file.strain import StrainData
from pesummary.io import read
import requests
import pandas
import GWCorrect.wfu as wfu

Using Parameterized Waveform Differences

We will first demonstrate how parameterized waveform differences are loaded in and used. Here, we load in BBH_parameterization_nsamples1000.npy, which contains 1000 samples of parameterized amplitude differences and phase differences from simulated binary black hole merger events.

[3]:
# downloading the file and saving to a folder
try:
    os.mkdir('tutorial_files')
except:
    pass
file = requests.get('https://github.com/RyanSR71/waveform_uncertainty/raw/refs/heads/main/files/BBH_parameterization_nsamples1000.npy', allow_redirects=True)
open("tutorial_files/BBH_parameterization_nsamples1000.npy", 'wb').write(file.content)

# loading the file
parameterization = np.load("tutorial_files/BBH_parameterization_nsamples1000.npy",allow_pickle=True)

We can use GWCorrect.wfu.parameterization.recovery_from_parameterization to turn the parameterized sets of waveform differences back into the waveform differences they represent. This function takes in one row of the parameterization array and constructs the waveform differences from the spline parameters in the file. The function returns the frequency array, amplitude difference array, and phase difference array. By default, the frequency array is given in standard frequency units (Hz). This can be changed by changing the dimensionless kwarg to True.

[4]:
# we can choose any index to recover up to the number of sample sets in the file; in this case, 1000
index = random.randint(0,1000)

# recovering a draw of waveform differences
frequency_grid, amplitude_difference, phase_difference = wfu.parameterization.recovery_from_parameterization(parameterization[index])

# plotting
fig,ax = plt.subplots(1,2,figsize=(15,6))

# plotting the waveform differences
ax[0].semilogx(frequency_grid,amplitude_difference,color='red')
ax[1].semilogx(frequency_grid,phase_difference,color='blue')

# plot settings
ax[0].grid(False)
ax[0].set_xlabel(r'$f$ [Hz]')
ax[0].set_ylabel(r'$\Delta\mathcal{A}$')
ax[0].tick_params(direction='in')
ax[0].set_xlim(frequency_grid[0],frequency_grid[-1])

ax[1].grid(False)
ax[1].set_xlabel(r'$f$ [Hz]')
ax[1].set_ylabel(r'$\Delta\phi$')
ax[1].tick_params(direction='in')
ax[1].set_xlim(frequency_grid[0],frequency_grid[-1])

plt.show()
../_images/notebooks_Parameterization_and_Waveform_Differences_9_0.png

From a parameterization file, we can use GWCorrect.wfu.parameterization.uncertainties_from_parameterization to find the means and standard deviations of each waveform difference, which will show us the expected variability between the waveform models. We represent the means as \(\overline{\Delta\mathcal{A}}_\mu\) and \(\overline{\Delta\phi}_\mu\), and the standard deviations as \(\delta\mathcal{A}_\mu\) and \(\delta\phi_\mu\).

[5]:
# finding the means and standard deviations
mean_amplitude_difference,amplitude_uncertainty,mean_phase_difference,phase_uncertainty = wfu.parameterization.uncertainties_from_parameterization(parameterization)

# plotting
fig,ax = plt.subplots(1,2,figsize=(15,6))

# plotting the means and standard deviations (uncertainties)
ax[0].semilogx(frequency_grid,mean_amplitude_difference,color='k',linewidth=2,zorder=2,label=r'$\overline{\Delta\mathcal{A}_{\mu}}\pm\delta\mathcal{A}_{\mu}$')
ax[0].fill_between(frequency_grid,mean_amplitude_difference-amplitude_uncertainty,mean_amplitude_difference+amplitude_uncertainty,color='k',alpha=0.5,zorder=2)
ax[1].semilogx(frequency_grid,mean_phase_difference,color='k',linewidth=2,zorder=2,label=r'$\overline{\Delta\phi_{\mu}}\pm\delta\phi_{\mu}$')
ax[1].fill_between(frequency_grid,mean_phase_difference-phase_uncertainty,mean_phase_difference+phase_uncertainty,color='k',alpha=0.5,zorder=2)

# plotting all of the draws of waveform difference
for i in range(len(parameterization)):
    frequency_grid, amplitude_difference, phase_difference = wfu.parameterization.recovery_from_parameterization(parameterization[i])
    ax[0].semilogx(frequency_grid,amplitude_difference,color='tab:red',linewidth=0.75,alpha=0.35,zorder=1)
    ax[1].semilogx(frequency_grid,phase_difference,color='tab:blue',linewidth=0.75,alpha=0.35,zorder=1)

# plot settings
ax[0].legend(fancybox=True,loc='upper left')
ax[0].grid(False)
ax[0].set_xlim(frequency_grid[0],frequency_grid[-1])
ax[0].set_xlabel(r'$f\ [\mathrm{Hz}]$')
ax[0].set_ylabel(r'$\Delta\mathcal{A}$')
ax[0].tick_params(direction='in')

ax[1].legend(fancybox=True,loc='upper left')
ax[1].grid(False)
ax[1].set_xlim(frequency_grid[0],frequency_grid[-1])
ax[1].set_xlabel(r'$f\ [\mathrm{Hz}]$')
ax[1].set_ylabel(r'$\Delta\phi$')
ax[1].tick_params(direction='in')

plt.show()
../_images/notebooks_Parameterization_and_Waveform_Differences_11_0.png

We can also perform this same operation in dimensionless frequency, \(\xi\). To do so, we simply set dimensionless=True in both the GWCorrect.wfu.parameterization.recovery_from_parameterization and GWCorrect.wfu.parameterization.uncertainties_from_parameterization functions. In doing this, we essentially remove the total mass contributions from the waveform differences, and we are left with smaller overall distributions. This is useful for defining more constrained priors.

[6]:
# finding the means and standard deviations
mean_amplitude_difference,amplitude_uncertainty,mean_phase_difference,phase_uncertainty = wfu.parameterization.uncertainties_from_parameterization(parameterization,dimensionless=True)

# plotting
fig,ax = plt.subplots(1,2,figsize=(15,6))

# plotting the means and standard deviations (uncertainties)
frequency_grid = np.geomspace(0.001,1,1000)
ax[0].semilogx(frequency_grid,mean_amplitude_difference,color='k',linewidth=2,zorder=2,label=r'$\overline{\Delta\mathcal{A}_{\mu}}\pm\delta\mathcal{A}_{\mu}$')
ax[0].fill_between(frequency_grid,mean_amplitude_difference-amplitude_uncertainty,mean_amplitude_difference+amplitude_uncertainty,color='k',alpha=0.5,zorder=2)
ax[1].semilogx(frequency_grid,mean_phase_difference,color='k',linewidth=2,zorder=2,label=r'$\overline{\Delta\phi_{\mu}}\pm\delta\phi_{\mu}$')
ax[1].fill_between(frequency_grid,mean_phase_difference-phase_uncertainty,mean_phase_difference+phase_uncertainty,color='k',alpha=0.5,zorder=2)

# plotting all of the draws of waveform difference
for i in range(len(parameterization)):
    frequency_grid, amplitude_difference, phase_difference = wfu.parameterization.recovery_from_parameterization(parameterization[i],dimensionless=True)
    ax[0].semilogx(frequency_grid,amplitude_difference,color='tab:red',linewidth=0.75,alpha=0.35,zorder=1)
    ax[1].semilogx(frequency_grid,phase_difference,color='tab:blue',linewidth=0.75,alpha=0.35,zorder=1)

# plot settings
ax[0].legend(fancybox=True,loc='upper left')
ax[0].grid(False)
ax[0].set_xlim(frequency_grid[0],frequency_grid[-1])
ax[0].set_xlabel(r'$\xi$')
ax[0].set_ylabel(r'$\Delta\mathcal{A}$')
ax[0].tick_params(direction='in')

ax[1].legend(fancybox=True,loc='upper left')
ax[1].grid(False)
ax[1].set_xlim(frequency_grid[0],frequency_grid[-1])
ax[1].set_xlabel(r'$\xi$')
ax[1].set_ylabel(r'$\Delta\phi$')
ax[1].tick_params(direction='in')

plt.show()
../_images/notebooks_Parameterization_and_Waveform_Differences_13_0.png

Generating Waveform Model Differences

In the following sections, we look at generating waveform differences and then generating a parameterization file.

We first construct a prior of source parameters over which we want to generate waveform differences. Here, we choose a prior for binary black hole analysis.

[7]:
prior = bilby.core.prior.PriorDict()

prior['chirp_mass'] = bilby.gw.prior.UniformInComponentsChirpMass(name='chirp_mass',latex_label=r'$\mathcal{M}_c$',minimum=25,maximum=100,unit=r'$\mathrm{M}_{\odot}$')
prior['mass_ratio'] = bilby.gw.prior.UniformInComponentsMassRatio(name='mass_ratio',latex_label=r'$q$',minimum=0.125,maximum=1)
prior['chi_1'] = bilby.core.prior.Uniform(name='chi_1',latex_label=r'$\chi_1$',minimum=-1,maximum=1)
prior['chi_2'] = bilby.core.prior.Uniform(name='chi_2',latex_label=r'$\chi_2$',minimum=-1,maximum=1)
prior['geocent_time'] = bilby.core.prior.Uniform(name='geocent_time',latex_label=r'$t_{c}$',minimum=1126259462.3,maximum=1126259462.5,unit='s')
prior['luminosity_distance'] = bilby.gw.prior.UniformSourceFrame(name='luminosity_distance',latex_label=r'$D_L$',minimum=100,maximum=10000,unit='Mpc')
prior['phase'] = bilby.core.prior.Uniform(name='phase',latex_label=r'$\phi_\mathrm{ref}$',minimum=0,maximum=2*np.pi,boundary='periodic')
prior['theta_jn'] = bilby.core.prior.Sine(name='theta_jn',latex_label=r'$\theta_{JN}$')

Here we set up our waveform generators with our injection passed as an argument. Because we are looking to generate model differences, we choose two different waveform approximants, IMRPhenomD and SEOBNRv4.

[8]:
waveform_arguments_1 = dict(waveform_approximant='IMRPhenomD', reference_frequency=50,
                            catch_waveform_errors=True, minimum_frequency=20.0, maximum_frequency=1024.0)

hf1 = bilby.gw.WaveformGenerator(parameter_conversion=bilby.gw.conversion.convert_to_lal_binary_neutron_star_parameters,
                    waveform_arguments=waveform_arguments_1,
                    frequency_domain_source_model=bilby.gw.source.lal_binary_neutron_star,
                    sampling_frequency=4096,
                    duration=4,
                )

waveform_arguments_2 = dict(waveform_approximant='SEOBNRv4', reference_frequency=50,
                            catch_waveform_errors=True, minimum_frequency=20.0, maximum_frequency=1024.0)

hf2 = bilby.gw.WaveformGenerator(parameter_conversion=bilby.gw.conversion.convert_to_lal_binary_neutron_star_parameters,
                    waveform_arguments=waveform_arguments_2,
                    frequency_domain_source_model=bilby.gw.source.lal_binary_neutron_star,
                    sampling_frequency=4096,
                    duration=4,
                )
20:02 bilby INFO    : Waveform generator initiated with
  frequency_domain_source_model: bilby.gw.source.lal_binary_neutron_star
  time_domain_source_model: None
  parameter_conversion: bilby.gw.conversion.convert_to_lal_binary_neutron_star_parameters
20:02 bilby INFO    : Waveform generator initiated with
  frequency_domain_source_model: bilby.gw.source.lal_binary_neutron_star
  time_domain_source_model: None
  parameter_conversion: bilby.gw.conversion.convert_to_lal_binary_neutron_star_parameters

With the waveform generators, we can calculate the waveform model differences, \(\Delta\mathcal{A}_{\mu}\) and \(\Delta\phi_{\mu}\). If we pass the waveform generators into the GWCorrect.wfu.parameterization.fd_model_difference function, it will return model amplitude difference, \(\Delta\mathcal{A}_{\mu}\), and model phase difference, \(\Delta{\phi}_{\mu}\).

If injection parameters are not present in the waveform generators, add them to the fd_model_difference function as a kwarg.

[9]:
# calculating the waveform model differences

injection=prior.sample()

frequency_grid,amplitude_difference,phase_difference = wfu.parameterization.fd_model_difference(hf1,hf2,injection=injection)

# plotting
fig,ax = plt.subplots(1,2,figsize=(15,6))

# plotting the waveform differences
ax[0].semilogx(frequency_grid,amplitude_difference,color='red')
ax[1].semilogx(frequency_grid,phase_difference,color='blue')

# plot settings
ax[0].set_xlim(hf1.waveform_arguments['minimum_frequency'],hf1.waveform_arguments['maximum_frequency'])
ax[0].set_xlabel(r'$\mathit{f}$ [Hz]')
ax[0].set_ylabel(r'$\Delta\mathcal{A}$')
ax[0].tick_params(direction='in')
ax[0].grid(False)

ax[1].set_xlim(hf1.waveform_arguments['minimum_frequency'],hf1.waveform_arguments['maximum_frequency'])
ax[1].set_xlabel(r'$\mathit{f}$ [Hz]')
ax[1].set_ylabel(r'$\Delta\phi$')
ax[1].tick_params(direction='in')
ax[1].grid(False)

plt.show()
../_images/notebooks_Parameterization_and_Waveform_Differences_22_0.png

Generating a Parameterization File

GWCorrect.wfu.parameterization.parameterization takes the previous steps and iterates them many times, but fits a cubic spline function to the waveform differences and saves the spline parameters and the injection parameters in a numpy array. To run the function, we pass two waveform generators, a prior, and the number of draws we want.

Here we define some waveform generators, each with different waveform approximants:

[10]:
waveform_arguments_1 = dict(waveform_approximant='IMRPhenomD', reference_frequency=20.0,
                            catch_waveform_errors=True, minimum_frequency=20.0, maximum_frequency=1024.0)

IMR_waveform = bilby.gw.WaveformGenerator(parameter_conversion=bilby.gw.conversion.convert_to_lal_binary_neutron_star_parameters,
                    waveform_arguments=waveform_arguments_1,
                    frequency_domain_source_model=bilby.gw.source.lal_binary_neutron_star,
                    sampling_frequency=4096,
                    duration=4,
                )

waveform_arguments_2 = dict(waveform_approximant='SEOBNRv4', reference_frequency=20.0,
                            catch_waveform_errors=True, minimum_frequency=20.0, maximum_frequency=1024.0)

EOB_waveform = bilby.gw.WaveformGenerator(parameter_conversion=bilby.gw.conversion.convert_to_lal_binary_neutron_star_parameters,
                    waveform_arguments=waveform_arguments_2,
                    frequency_domain_source_model=bilby.gw.source.lal_binary_neutron_star,
                    sampling_frequency=4096,
                    duration=4,
                )

Because we want to use this file to construct a waveform uncertainty prior later, we will need to define a new prior. When perform parameter estimation, we need to constrict the total mass to ensure that our waveform uncertainty correction stays inside the frequency band. To be as accurate as possible, we want this restriction to be reflected in the prior.

[11]:
# we pass the total mass conversion function into the PriorDict() function. this will allow bilby to convert between the given mass parameters and total mass
prior = bilby.core.prior.PriorDict(conversion_function=wfu.prior.total_mass_conversion)

# here we put in the total mass constraint prior, making sure to use the upper and lower frequencies that we set in the waveform generators
prior['total_mass'] = wfu.prior.TotalMassConstraint(name='total_mass',latex_label=r'$M$',minimum_frequency=20,maximum_frequency=1024,unit=r'$\mathrm{M}_{\odot}$')

prior['chirp_mass'] = bilby.gw.prior.UniformInComponentsChirpMass(name='chirp_mass',latex_label=r'$\mathcal{M}_c$',minimum=25,maximum=100,unit=r'$\mathrm{M}_{\odot}$')
prior['mass_ratio'] = bilby.gw.prior.UniformInComponentsMassRatio(name='mass_ratio',latex_label=r'$q$',minimum=0.125,maximum=1)
prior['chi_1'] = bilby.gw.prior.AlignedSpin(name='chi_1',latex_label=r'$\chi_1$')
prior['chi_2'] = bilby.gw.prior.AlignedSpin(name='chi_2',latex_label=r'$\chi_2$')
prior['geocent_time'] = bilby.gw.prior.Uniform(name='geocent_time',latex_label=r'$t_{c}$',minimum=1126259462.3,maximum=1126259462.5,unit='s')
prior['luminosity_distance'] = bilby.gw.prior.UniformSourceFrame(name='luminosity_distance',latex_label=r'$D_L$',minimum=100,maximum=10000,unit='Mpc')
prior['phase'] = bilby.core.prior.Uniform(name='phase',latex_label=r'$\phi_\mathrm{ref}$',minimum=0,maximum=2*np.pi,boundary='periodic')
prior['theta_jn'] = bilby.core.prior.Sine(name='theta_jn',latex_label=r'$\theta_{JN}$')

Now we can generate the parameterization file, passing in both waveform generators and the prior. We choose our sample size to be 25 for this demonstration.

[12]:
parameterization=wfu.parameterization.parameterization(IMR_waveform,EOB_waveform,prior,25)
Generating Waveform Differences: 100%|██████████| 25/25 [00:51<00:00,  2.08s/it]

This can then be saved as a .npy file using numpy.save.

[13]:
try:
    os.mkdir('tutorial_files')
except:
    pass

np.save('tutorial_files/parameterization_example.npy',parameterization)

We can use pandas dataframes to see the structure of the parameterization table:

[14]:
pandas.DataFrame(parameterization)
[14]:
0 1 2 3 4
0 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.011344734627451114, -0.00516763664473352, 0... [-0.11387150553302217, -0.11109348298542376, -... {'chirp_mass': 46.41777273488074, 'mass_ratio'...
1 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.010403677514487453, -0.01594057099319146, ... [0.06537430489148921, 0.04911807101151133, 0.0... {'chirp_mass': 51.85010559182378, 'mass_ratio'...
2 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.01450122685292099, 0.002994016100458463, -... [0.12291880829948099, 0.12712177369798194, 0.1... {'chirp_mass': 41.06424048302982, 'mass_ratio'...
3 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.0397728258968022, 0.01690793363377785, 0.0... [0.1462430177956725, 0.15019131793423313, 0.17... {'chirp_mass': 35.73517830359083, 'mass_ratio'...
4 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.002874038414641733, 0.0025211111344098924,... [-0.005329277280922362, -0.0044138510753040094... {'chirp_mass': 68.31448457749205, 'mass_ratio'...
5 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.02460783566832636, -0.002495861950812417, -... [0.16067865439767504, 0.16688532235235387, 0.1... {'chirp_mass': 47.03839556657787, 'mass_ratio'...
6 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.011254553165691017, -0.006325611437562162,... [0.09887000812124558, 0.09119274310205117, 0.0... {'chirp_mass': 62.075846322448164, 'mass_ratio...
7 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.002783626124574834, 0.016202600952211377, -... [0.11342416167096525, 0.14490166132054982, 0.1... {'chirp_mass': 28.704328178100457, 'mass_ratio...
8 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.011093874723562935, -0.007218645426659842,... [0.12323367922058215, 0.11112772429518192, 0.1... {'chirp_mass': 66.43887593482461, 'mass_ratio'...
9 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.0009004489617877587, 0.024498046738648194,... [0.12096047240263746, 0.15319377907685983, 0.1... {'chirp_mass': 41.906715323538926, 'mass_ratio...
10 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.013528120357516937, -0.011595301409160208,... [0.06224469112694386, 0.055375735106461654, 0.... {'chirp_mass': 73.80995516273092, 'mass_ratio'...
11 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.005426338681634224, 0.0036538013645470713,... [0.031309531963197745, 0.03842093224060539, 0.... {'chirp_mass': 62.7437830154027, 'mass_ratio':...
12 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.01404105186132687, 0.004442994995799143, -... [0.1694492986072662, 0.15060142289815914, 0.16... {'chirp_mass': 39.0740563377856, 'mass_ratio':...
13 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.007549941130094107, 0.012800711905960105, 0... [-0.04429019940192225, -0.03510695221890314, -... {'chirp_mass': 67.50196004340364, 'mass_ratio'...
14 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.00915807767588206, -0.00685063267811814, -... [0.10068688991870989, 0.09300161125955353, 0.0... {'chirp_mass': 74.66271628352878, 'mass_ratio'...
15 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.02222161820384172, 0.0015570071553248077, -... [0.08628033830422277, 0.11322707964063294, 0.0... {'chirp_mass': 28.74314829877408, 'mass_ratio'...
16 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.008906090143098733, -0.005647761888350145,... [-0.1542962174242175, -0.15952713340025992, -0... {'chirp_mass': 56.332979485239306, 'mass_ratio...
17 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.004493465342684355, -0.003607752257268948,... [0.05911354158165388, 0.05718327665687184, 0.0... {'chirp_mass': 46.30792832802009, 'mass_ratio'...
18 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.001498268468311137, -0.006343440703046488, ... [0.10224993647534109, 0.11401530167038354, 0.0... {'chirp_mass': 43.74863669259766, 'mass_ratio'...
19 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.0072221250150101834, 0.0053732359570424215... [0.12214098391729156, 0.12529488031462854, 0.1... {'chirp_mass': 48.6387291872817, 'mass_ratio':...
20 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.013667922279653633, -0.015321339058875005, ... [0.1743107920467697, 0.15722008918546893, 0.13... {'chirp_mass': 42.093878923530404, 'mass_ratio...
21 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.024253480236051894, 0.009991929297262558, -... [0.10450116186606806, 0.1291131680774198, 0.11... {'chirp_mass': 48.92562603929362, 'mass_ratio'...
22 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [-0.003858694568517951, 0.0071040461974336555,... [-0.04053418405736142, -0.030041981700463793, ... {'chirp_mass': 38.79145334694394, 'mass_ratio'...
23 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.00825362253451467, -0.0025275099871425732, ... [-0.19784081702727785, -0.19116451934315792, -... {'chirp_mass': 59.72901526943032, 'mass_ratio'...
24 [20.0, 20.25, 20.5, 20.75, 21.0, 21.25, 21.5, ... [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.... [0.0013997180699645284, -0.004860364056346933,... [0.10729686886581313, 0.09228168557252814, 0.0... {'chirp_mass': 38.5834670104539, 'mass_ratio':...