From 8c7b8d34d8bdd1835464960838571cd18050f9d3 Mon Sep 17 00:00:00 2001 From: Aditya Vijaykumar <vijaykumar.aditya@gmail.com> Date: Mon, 16 May 2022 12:46:17 +0530 Subject: [PATCH] changes to source.py --- AUTHORS.md | 1 + bilby/gw/source.py | 189 +++++++++++++++++++++++++++++++++++++++ test/gw/source_test.py | 194 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 384 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 98fae5bce..cdb687ce1 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -40,6 +40,7 @@ Karl Wette Katerina Chatziioannou Kaylee de Soto Khun Sang Phukon +Kruthi Krishna Kshipraa Athar Leslie Wade Liting Xiao diff --git a/bilby/gw/source.py b/bilby/gw/source.py index 4d7793b92..f32af4bf2 100644 --- a/bilby/gw/source.py +++ b/bilby/gw/source.py @@ -828,6 +828,195 @@ def _base_waveform_frequency_sequence( return dict(plus=h_plus.data.data, cross=h_cross.data.data) +def lal_binary_black_hole_relativebinning( + frequency_array, mass_1, mass_2, luminosity_distance, a_1, tilt_1, + phi_12, a_2, tilt_2, phi_jl, theta_jn, phase, fiducial, **kwargs): + + waveform_kwargs = dict( + waveform_approximant='IMRPhenomPv2', reference_frequency=50.0, + minimum_frequency=20.0, maximum_frequency=frequency_array[-1], + catch_waveform_errors=False, pn_spin_order=-1, pn_tidal_order=-1, + pn_phase_order=-1, pn_amplitude_order=0) + waveform_kwargs.update(kwargs) + + if fiducial == 1: + return _base_lal_cbc_fd_waveform( + frequency_array=frequency_array, mass_1=mass_1, mass_2=mass_2, + luminosity_distance=luminosity_distance, theta_jn=theta_jn, phase=phase, + a_1=a_1, a_2=a_2, tilt_1=tilt_1, tilt_2=tilt_2, phi_jl=phi_jl, + phi_12=phi_12, lambda_1=0.0, lambda_2=0.0, **waveform_kwargs) + + else: + return _base_relativebinning_waveform( + frequency_array=frequency_array, mass_1=mass_1, mass_2=mass_2, + luminosity_distance=luminosity_distance, theta_jn=theta_jn, phase=phase, + a_1=a_1, a_2=a_2, tilt_1=tilt_1, tilt_2=tilt_2, phi_jl=phi_jl, + phi_12=phi_12, lambda_1=0.0, lambda_2=0.0, **waveform_kwargs) + + +def lal_binary_neutron_star_relativebinning( + frequency_array, mass_1, mass_2, luminosity_distance, a_1, tilt_1, + phi_12, a_2, tilt_2, phi_jl, lambda_1, lambda_2, theta_jn, phase, + fiducial, **kwargs): + + waveform_kwargs = dict( + waveform_approximant='IMRPhenomPv2_NRTidal', reference_frequency=50.0, + minimum_frequency=20.0, maximum_frequency=frequency_array[-1], + catch_waveform_errors=False, pn_spin_order=-1, pn_tidal_order=-1, + pn_phase_order=-1, pn_amplitude_order=0) + waveform_kwargs.update(kwargs) + + if fiducial == 1: + + return _base_lal_cbc_fd_waveform( + frequency_array=frequency_array, mass_1=mass_1, mass_2=mass_2, + luminosity_distance=luminosity_distance, theta_jn=theta_jn, phase=phase, + a_1=a_1, a_2=a_2, tilt_1=tilt_1, tilt_2=tilt_2, phi_12=phi_12, + phi_jl=phi_jl, lambda_1=lambda_1, lambda_2=lambda_2, **waveform_kwargs) + + else: + return _base_relativebinning_waveform( + frequency_array=frequency_array, mass_1=mass_1, mass_2=mass_2, + luminosity_distance=luminosity_distance, theta_jn=theta_jn, phase=phase, + a_1=a_1, a_2=a_2, tilt_1=tilt_1, tilt_2=tilt_2, phi_jl=phi_jl, + phi_12=phi_12, lambda_1=lambda_1, lambda_2=lambda_2, **waveform_kwargs) + + +def _base_relativebinning_waveform( + frequency_array, mass_1, mass_2, luminosity_distance, theta_jn, phase, + a_1=0.0, a_2=0.0, tilt_1=0.0, tilt_2=0.0, phi_12=0.0, phi_jl=0.0, + lambda_1=0.0, lambda_2=0.0, **waveform_kwargs): + """ Generate a cbc waveform model using lalsimulation + + Parameters + ---------- + frequency_array: array_like + The frequencies at which we want to calculate the strain. Ignored + for the relative binning model. + mass_1: float + The mass of the heavier object in solar masses + mass_2: float + The mass of the lighter object in solar masses + luminosity_distance: float + The luminosity distance in megaparsec + a_1: float + Dimensionless primary spin magnitude + tilt_1: float + Primary tilt angle + phi_12: float + Azimuthal angle between the component spins + a_2: float + Dimensionless secondary spin magnitude + tilt_2: float + Secondary tilt angle + phi_jl: float + Azimuthal angle between the total and orbital angular momenta + theta_jn: float + Orbital inclination + phase: float + The phase at coalescence + lambda_1: float + Tidal deformability of the more massive object + lambda_2: float + Tidal deformability of the less massive object + kwargs: dict + Optional keyword arguments + + Waveform arguments + ------------------ + Non-sampled extra data used in the source model calculation + frequency_bin_edges: np.array + + Returns + ------- + dict: A dictionary with the plus and cross polarisation strain modes + """ + import lal + import lalsimulation as lalsim + + waveform_approximant = waveform_kwargs['waveform_approximant'] + reference_frequency = waveform_kwargs['reference_frequency'] + catch_waveform_errors = waveform_kwargs['catch_waveform_errors'] + pn_spin_order = waveform_kwargs['pn_spin_order'] + pn_tidal_order = waveform_kwargs['pn_tidal_order'] + pn_phase_order = waveform_kwargs['pn_phase_order'] + pn_amplitude_order = waveform_kwargs['pn_amplitude_order'] + waveform_dictionary = waveform_kwargs.get( + 'lal_waveform_dictionary', lal.CreateDict() + ) + + frequency_bin_edges = waveform_kwargs['frequency_bin_edges'] + + approximant = lalsim_GetApproximantFromString(waveform_approximant) + + luminosity_distance = luminosity_distance * 1e6 * utils.parsec + mass_1 = mass_1 * utils.solar_mass + mass_2 = mass_2 * utils.solar_mass + + iota, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z = bilby_to_lalsimulation_spins( + theta_jn=theta_jn, phi_jl=phi_jl, tilt_1=tilt_1, tilt_2=tilt_2, + phi_12=phi_12, a_1=a_1, a_2=a_2, mass_1=mass_1, mass_2=mass_2, + reference_frequency=reference_frequency, phase=phase) + + lalsim.SimInspiralWaveformParamsInsertPNSpinOrder( + waveform_dictionary, int(pn_spin_order)) + lalsim.SimInspiralWaveformParamsInsertPNTidalOrder( + waveform_dictionary, int(pn_tidal_order)) + lalsim.SimInspiralWaveformParamsInsertPNPhaseOrder( + waveform_dictionary, int(pn_phase_order)) + lalsim.SimInspiralWaveformParamsInsertPNAmplitudeOrder( + waveform_dictionary, int(pn_amplitude_order)) + lalsim_SimInspiralWaveformParamsInsertTidalLambda1( + waveform_dictionary, lambda_1) + lalsim_SimInspiralWaveformParamsInsertTidalLambda2( + waveform_dictionary, lambda_2) + + for key, value in waveform_kwargs.items(): + func = getattr(lalsim, "SimInspiralWaveformParamsInsert" + key, None) + if func is not None: + func(waveform_dictionary, value) + + if waveform_kwargs.get('numerical_relativity_file', None) is not None: + lalsim.SimInspiralWaveformParamsInsertNumRelData( + waveform_dictionary, waveform_kwargs['numerical_relativity_file']) + + if ('mode_array' in waveform_kwargs) and waveform_kwargs['mode_array'] is not None: + mode_array = waveform_kwargs['mode_array'] + mode_array_lal = lalsim.SimInspiralCreateModeArray() + for mode in mode_array: + lalsim.SimInspiralModeArrayActivateMode(mode_array_lal, mode[0], mode[1]) + lalsim.SimInspiralWaveformParamsInsertModeArray(waveform_dictionary, mode_array_lal) + + try: + h_binned_plus, h_binned_cross = lalsim_SimInspiralChooseFDWaveformSequence( + phase, mass_1, mass_2, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, + spin_2z, reference_frequency, luminosity_distance, iota, + waveform_dictionary, approximant, frequency_bin_edges) + except Exception as e: + if not catch_waveform_errors: + raise + else: + EDOM = (e.args[0] == 'Internal function call failed: Input domain error') + if EDOM: + failed_parameters = dict(mass_1=mass_1, mass_2=mass_2, + spin_1=(spin_1x, spin_2y, spin_1z), + spin_2=(spin_2x, spin_2y, spin_2z), + luminosity_distance=luminosity_distance, + iota=iota, phase=phase, + ) + logger.warning("Evaluating the waveform failed with error: {}\n".format(e) + + "The parameters were {}\n".format(failed_parameters) + + "Likelihood will be set to -inf.") + return None + else: + raise + + waveform_polarizations = dict( + plus=h_binned_plus.data.data, cross=h_binned_cross.data.data) + + return waveform_polarizations + + def sinegaussian(frequency_array, hrss, Q, frequency, **kwargs): r""" A frequency-domain sine-Gaussian burst source model. diff --git a/test/gw/source_test.py b/test/gw/source_test.py index 627278a33..f3fcc1201 100644 --- a/test/gw/source_test.py +++ b/test/gw/source_test.py @@ -423,5 +423,199 @@ class TestBNSfreqseq(unittest.TestCase): self.assertLess(diff / norm, 1e-5) +class TestRelbinBBH(unittest.TestCase): + def setUp(self): + self.parameters = dict( + mass_1=30.0, + mass_2=30.0, + luminosity_distance=400.0, + a_1=0.4, + tilt_1=0.2, + phi_12=1.0, + a_2=0.8, + tilt_2=2.7, + phi_jl=2.9, + theta_jn=0.3, + phase=0.0, + ) + self.waveform_kwargs_fiducial = dict( + waveform_approximant="IMRPhenomPv2", + reference_frequency=50.0, + minimum_frequency=20.0, + catch_waveform_errors=True, + fiducial=True, + ) + self.waveform_kwargs_binned = dict( + waveform_approximant="IMRPhenomPv2", + reference_frequency=50.0, + minimum_frequency=20.0, + catch_waveform_errors=True, + fiducial=False, + frequency_bin_edges=np.arange(20, 1500, 50) + ) + self.frequency_array = bilby.core.utils.create_frequency_series(2048, 4) + self.bad_parameters = copy(self.parameters) + self.bad_parameters["mass_1"] = -30.0 + + def tearDown(self): + del self.parameters + del self.waveform_kwargs_fiducial + del self.waveform_kwargs_binned + del self.frequency_array + del self.bad_parameters + + def test_relbin_fiducial_bbh_works_runs_valid_parameters(self): + self.parameters.update(self.waveform_kwargs_fiducial) + self.assertIsInstance( + bilby.gw.source.lal_binary_black_hole_relativebinning( + self.frequency_array, **self.parameters + ), + dict, + ) + + def test_relbin_binned_bbh_works_runs_valid_parameters(self): + self.parameters.update(self.waveform_kwargs_binned) + self.assertIsInstance( + bilby.gw.source.lal_binary_black_hole_relativebinning( + self.frequency_array, **self.parameters + ), + dict, + ) + + def test_waveform_error_catching_fiducial(self): + self.bad_parameters.update(self.waveform_kwargs_fiducial) + self.assertIsNone( + bilby.gw.source.lal_binary_black_hole_relativebinning( + self.frequency_array, **self.bad_parameters + ) + ) + + def test_waveform_error_catching_binned(self): + self.bad_parameters.update(self.waveform_kwargs_binned) + self.assertIsNone( + bilby.gw.source.lal_binary_black_hole_relativebinning( + self.frequency_array, **self.bad_parameters + ) + ) + + def test_waveform_error_raising_fiducial(self): + raise_error_parameters = copy(self.bad_parameters) + raise_error_parameters.update(self.waveform_kwargs_fiducial) + raise_error_parameters["catch_waveform_errors"] = False + with self.assertRaises(Exception): + bilby.gw.source.lal_binary_black_hole_relativebinning( + self.frequency_array, **raise_error_parameters + ) + + def test_waveform_error_raising_binned(self): + raise_error_parameters = copy(self.bad_parameters) + raise_error_parameters.update(self.waveform_kwargs_binned) + raise_error_parameters["catch_waveform_errors"] = False + with self.assertRaises(Exception): + bilby.gw.source.lal_binary_black_hole_relativebinning( + self.frequency_array, **raise_error_parameters + ) + + def test_relbin_bbh_fails_without_fiducial_option(self): + with self.assertRaises(KeyError): + bilby.gw.source.lal_binary_black_hole_relativebinning( + self.frequency_array, **self.parameters + ) + + def test_relbin_bbh_xpprecession_version(self): + self.parameters.update(self.waveform_kwargs_fiducial) + self.parameters["waveform_approximant"] = "IMRPhenomXP" + + # Test that we can modify the XP precession version + out_v223 = bilby.gw.source.lal_binary_black_hole( + self.frequency_array, PhenomXPrecVersion=223, **self.parameters + ) + out_v102 = bilby.gw.source.lal_binary_black_hole( + self.frequency_array, PhenomXPrecVersion=102, **self.parameters + ) + self.assertFalse(np.all(out_v223["plus"] == out_v102["plus"])) + + +class TestRelbinBNS(unittest.TestCase): + def setUp(self): + self.parameters = dict( + mass_1=1.4, + mass_2=1.4, + luminosity_distance=400.0, + a_1=0.4, + a_2=0.3, + tilt_1=0.2, + tilt_2=1.7, + phi_jl=0.2, + phi_12=0.9, + theta_jn=1.7, + phase=0.0, + lambda_1=100.0, + lambda_2=100.0, + ) + self.waveform_kwargs_fiducial = dict( + waveform_approximant="IMRPhenomPv2_NRTidal", + reference_frequency=50.0, + minimum_frequency=20.0, + fiducial=True, + ) + self.waveform_kwargs_binned = dict( + waveform_approximant="IMRPhenomPv2_NRTidal", + reference_frequency=50.0, + minimum_frequency=20.0, + fiducial=False, + frequency_bin_edges=np.arange(20, 1500, 50), + ) + self.frequency_array = bilby.core.utils.create_frequency_series(2048, 4) + + def tearDown(self): + del self.parameters + del self.waveform_kwargs_fiducial + del self.waveform_kwargs_binned + del self.frequency_array + + def test_relbin_fiducial_bns_runs_with_valid_parameters(self): + self.parameters.update(self.waveform_kwargs_fiducial) + self.assertIsInstance( + bilby.gw.source.lal_binary_neutron_star_relativebinning( + self.frequency_array, **self.parameters + ), + dict, + ) + + def test_relbin_binned_bns_runs_with_valid_parameters(self): + self.parameters.update(self.waveform_kwargs_binned) + self.assertIsInstance( + bilby.gw.source.lal_binary_neutron_star_relativebinning( + self.frequency_array, **self.parameters + ), + dict, + ) + + def test_relbin_bns_fails_without_fiducial_option(self): + with self.assertRaises(KeyError): + bilby.gw.source.lal_binary_neutron_star_relativebinning( + self.frequency_array, **self.parameters + ) + + def test_fiducial_fails_without_tidal_parameters(self): + self.parameters.pop("lambda_1") + self.parameters.pop("lambda_2") + self.parameters.update(self.waveform_kwargs_fiducial) + with self.assertRaises(TypeError): + bilby.gw.source.lal_binary_neutron_star_relativebinning( + self.frequency_array, **self.parameters + ) + + def test_binned_fails_without_tidal_parameters(self): + self.parameters.pop("lambda_1") + self.parameters.pop("lambda_2") + self.parameters.update(self.waveform_kwargs_binned) + with self.assertRaises(TypeError): + bilby.gw.source.lal_binary_neutron_star_relativebinning( + self.frequency_array, **self.parameters + ) + + if __name__ == "__main__": unittest.main() -- GitLab