diff --git a/dingo/gw/waveform_generator/waveform_generator.py b/dingo/gw/waveform_generator/waveform_generator.py index b9efaba24..5e84683e2 100644 --- a/dingo/gw/waveform_generator/waveform_generator.py +++ b/dingo/gw/waveform_generator/waveform_generator.py @@ -630,8 +630,9 @@ def generate_hplus_hcross_m( # Step 3: Separate negative and positive frequency parts of the modes, # and add contributions according to their transformation behavior under # phase shifts. + pol_m = wfg_utils.get_polarizations_from_fd_modes_m( - hlm_fd, iota, parameters["phase"] + hlm_fd, iota, parameters["phase"], self.approximant_str ) else: @@ -658,9 +659,13 @@ def generate_FD_modes_LO(self, parameters): values. iota: float """ - # TD approximants that are implemented in J frame. Currently tested for: - # 101: IMRPhenomXPHM - if self.approximant in [101]: + # FD Waveform approximants that are implemented in either the L0 or J frame. Currently tested for: + # IMRPhenomXPHM - Modes returned in J-Frame + # IMRPhenomXHM - Modes returned in L0-Frame + + + tested_approximants = ["IMRPhenomXPHM","IMRPhenomXHM"] + if LS.GetStringFromApproximant(self.approximant) in tested_approximants: parameters_lal_fd_modes = self._convert_parameters( {**parameters, "f_ref": self.f_ref}, lal_target_function="SimInspiralChooseFDModes", @@ -670,17 +675,18 @@ def generate_FD_modes_LO(self, parameters): # unpack linked list, convert lal objects to arrays hlm_fd = wfg_utils.linked_list_modes_to_dict_modes(hlm_fd) hlm_fd = {k: v.data.data for k, v in hlm_fd.items()} - # For the waveform models considered here (e.g., IMRPhenomXPHM), the modes - # are returned in the J frame (where the observer is at inclination=theta_JN, - # azimuth=0). In this frame, the dependence on the reference phase enters - # via the modes themselves. We need to convert to the L0 frame so that the - # dependence on phase enters via the spherical harmonics. - hlm_fd = frame_utils.convert_J_to_L0_frame( - hlm_fd, - parameters, - self, - spin_conversion_phase=self.spin_conversion_phase, - ) + + # For waveform models where the modes are returned in the J frame (where the observer is + # at an inclination=theta_JN, azimuth=0), the dependence on the reference phase enters + # via the modes themselves. We need to convert to the L0 frame so that the + # dependence on phase enters via the spherical harmonics. + if LS.GetStringFromApproximant(self.approximant) == "IMRPhenomXPHM": + hlm_fd = frame_utils.convert_J_to_L0_frame( + hlm_fd, + parameters, + self, + spin_conversion_phase=self.spin_conversion_phase, + ) return hlm_fd, iota else: raise NotImplementedError( @@ -713,7 +719,8 @@ def generate_TD_modes_L0(self, parameters): """ # TD approximants that are implemented in L0 frame. Currently tested for: # 52: SEOBNRv4PHM - if self.approximant in [52]: + tested_approximants = ["SEOBNRv4PHM"] + if LS.GetStringFromApproximant(self.approximant) in tested_approximants: parameters_lal_td_modes, iota = self._convert_parameters( {**parameters, "f_ref": self.f_ref}, lal_target_function="SimInspiralChooseTDModes", diff --git a/dingo/gw/waveform_generator/wfg_utils.py b/dingo/gw/waveform_generator/wfg_utils.py index c8206e1cf..7d4dbf6fd 100644 --- a/dingo/gw/waveform_generator/wfg_utils.py +++ b/dingo/gw/waveform_generator/wfg_utils.py @@ -141,7 +141,7 @@ def td_modes_to_fd_modes(hlm_td, domain): return hlm_fd -def get_polarizations_from_fd_modes_m(hlm_fd, iota, phase): +def get_polarizations_from_fd_modes_m(hlm_fd, iota, phase, approximant_str = None): pol_m = {} polarizations = ["h_plus", "h_cross"] @@ -152,7 +152,13 @@ def get_polarizations_from_fd_modes_m(hlm_fd, iota, phase): # In the L0 frame, we compute the polarizations from the modes using the # spherical harmonics below. - ylm = lal.SpinWeightedSphericalHarmonic(iota, np.pi / 2 - phase, -2, l, m) + #Some aligned spin models use phase internally to generate hlm so np.pi/2 - phase may give wrong result. + # It is important to understand what convention is used for a given waveform model before adding it. + + if approximant_str == "IMRPhenomXHM": + ylm = lal.SpinWeightedSphericalHarmonic(iota, np.pi / 2, -2, l, m) + else: + ylm = lal.SpinWeightedSphericalHarmonic(iota, np.pi / 2 - phase, -2, l, m) ylmstar = ylm.conjugate() # Modes (l,m) are defined on domain -f_max,...,-f_min,...0,...,f_min,...,f_max. diff --git a/tests/gw/waveform_generator/test_wfg_m.py b/tests/gw/waveform_generator/test_wfg_m.py index c57e703b7..4f10ee7b0 100644 --- a/tests/gw/waveform_generator/test_wfg_m.py +++ b/tests/gw/waveform_generator/test_wfg_m.py @@ -37,7 +37,7 @@ def uniform_fd_domain(): return domain -@pytest.fixture(params=["IMRPhenomXPHM", "SEOBNRv4PHM", "SEOBNRv5PHM", "SEOBNRv5HM"]) +@pytest.fixture(params=["IMRPhenomXPHM", "IMRPhenomXHM", "SEOBNRv4PHM", "SEOBNRv5PHM", "SEOBNRv5HM"]) def approximant(request): return request.param @@ -135,9 +135,9 @@ def tolerances(approximant): # Uncomment to test only one approximant. try: import pyseobnr - approximant_list = ["IMRPhenomXPHM", "SEOBNRv4PHM", "SEOBNRv5PHM", "SEOBNRv5HM"] + approximant_list = ["IMRPhenomXPHM", "IMRPhenomXHM", "SEOBNRv4PHM", "SEOBNRv5PHM", "SEOBNRv5HM"] except ImportError: - approximant_list = ["IMRPhenomXPHM", "SEOBNRv4PHM"] + approximant_list = ["IMRPhenomXPHM", "IMRPhenomXHM", "SEOBNRv4PHM"] @pytest.mark.parametrize("approximant", approximant_list) def test_generate_hplus_hcross_m(intrinsic_prior, wfg, num_evaluations, tolerances): mismatches = []