diff --git a/bilby/gw/utils.py b/bilby/gw/utils.py index 62317c858ed52a61b9d4432990827bc593236b05..5e304b4ecbbd71ead876598bf7231f92c2c2d86a 100644 --- a/bilby/gw/utils.py +++ b/bilby/gw/utils.py @@ -130,6 +130,7 @@ def get_polarization_tensor(ra, dec, time, psi, mode): elif mode.lower() == 'breathing': return np.einsum('i,j->ij', m, m) + np.einsum('i,j->ij', n, n) + # Calculating omega here to avoid calculation when model in [plus, cross, breathing] omega = np.cross(m, n) if mode.lower() == 'longitudinal': return np.sqrt(2) * np.einsum('i,j->ij', omega, omega) @@ -138,8 +139,7 @@ def get_polarization_tensor(ra, dec, time, psi, mode): elif mode.lower() == 'y': return np.einsum('i,j->ij', n, omega) + np.einsum('i,j->ij', omega, n) else: - logger.warning("{} not a polarization mode!".format(mode)) - return None + raise ValueError("{} not a polarization mode!".format(mode)) def get_vertex_position_geocentric(latitude, longitude, elevation): @@ -380,7 +380,7 @@ def get_open_strain_data( return strain -def read_frame_file(file_name, start_time, end_time, channel=None, buffer_time=1, **kwargs): +def read_frame_file(file_name, start_time, end_time, channel=None, buffer_time=0, **kwargs): """ A function which accesses the open strain data This uses `gwpy` to download the open data and then saves a cached copy for @@ -416,23 +416,22 @@ def read_frame_file(file_name, start_time, end_time, channel=None, buffer_time=1 except RuntimeError: logger.warning('Channel {} not found. Trying preset channel names'.format(channel)) - while not loaded: - ligo_channel_types = ['GDS-CALIB_STRAIN', 'DCS-CALIB_STRAIN_C01', 'DCS-CALIB_STRAIN_C02', - 'DCH-CLEAN_STRAIN_C02'] - virgo_channel_types = ['Hrec_hoft_V1O2Repro2A_16384Hz', 'FAKE_h_16384Hz_4R'] - channel_types = dict(H1=ligo_channel_types, L1=ligo_channel_types, V1=virgo_channel_types) - for detector in channel_types.keys(): - for channel_type in channel_types[detector]: - if loaded: - break - channel = '{}:{}'.format(detector, channel_type) - try: - strain = TimeSeries.read(source=file_name, channel=channel, start=start_time, end=end_time, - **kwargs) - loaded = True - logger.info('Successfully read strain data for channel {}.'.format(channel)) - except RuntimeError: - pass + ligo_channel_types = ['GDS-CALIB_STRAIN', 'DCS-CALIB_STRAIN_C01', 'DCS-CALIB_STRAIN_C02', + 'DCH-CLEAN_STRAIN_C02'] + virgo_channel_types = ['Hrec_hoft_V1O2Repro2A_16384Hz', 'FAKE_h_16384Hz_4R'] + channel_types = dict(H1=ligo_channel_types, L1=ligo_channel_types, V1=virgo_channel_types) + for detector in channel_types.keys(): + for channel_type in channel_types[detector]: + if loaded: + break + channel = '{}:{}'.format(detector, channel_type) + try: + strain = TimeSeries.read(source=file_name, channel=channel, start=start_time, end=end_time, + **kwargs) + loaded = True + logger.info('Successfully read strain data for channel {}.'.format(channel)) + except RuntimeError: + pass if loaded: return strain diff --git a/test/detector_test.py b/test/detector_test.py index edaa139fc74c12f694254986771decf16512ceee..07d107a074b9f534f1ab4bb45d747585519f4f7d 100644 --- a/test/detector_test.py +++ b/test/detector_test.py @@ -898,6 +898,13 @@ class TestInterferometerList(unittest.TestCase): with self.assertRaises(ValueError): self.ifo_list.inject_signal(injection_polarizations=None, waveform_generator=None) + def test_meta_data(self): + ifos_list = [self.ifo1, self.ifo2] + ifos = bilby.gw.detector.InterferometerList(ifos_list) + self.assertTrue(isinstance(ifos.meta_data, dict)) + meta_data = {ifo.name: ifo.meta_data for ifo in ifos_list} + self.assertEqual(ifos.meta_data, meta_data) + @patch.object(bilby.gw.waveform_generator.WaveformGenerator, 'frequency_domain_strain') def test_inject_signal_pol_none_calls_frequency_domain_strain(self, m): waveform_generator = bilby.gw.waveform_generator.WaveformGenerator( diff --git a/test/gw_utils_test.py b/test/gw_utils_test.py new file mode 100644 index 0000000000000000000000000000000000000000..bce6f97de0978fff982b1ee65d59e0559a8cfeab --- /dev/null +++ b/test/gw_utils_test.py @@ -0,0 +1,188 @@ +from __future__ import absolute_import, division + +import unittest +import os +from shutil import rmtree + +import numpy as np +import gwpy +import lal +import lalsimulation as lalsim + +import bilby +from bilby.gw import utils as gwutils + + +class TestGWUtils(unittest.TestCase): + + def setUp(self): + self.outdir = 'outdir' + bilby.core.utils.check_directory_exists_and_if_not_mkdir(self.outdir) + + def tearDown(self): + try: + rmtree(self.outdir) + except FileNotFoundError: + pass + + 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 test_psd_from_freq_series(self): + freq_data = np.array([1, 2, 3]) + df = 0.1 + psd = gwutils.psd_from_freq_series(freq_data, df) + self.assertTrue(np.all(psd == (freq_data * 2 * df ** 0.5)**2)) + + def test_time_delay_from_geocenter(self): + det1 = np.array([0.1, 0.2, 0.3]) + det2 = np.array([0.1, 0.2, 0.5]) + ra = 0.5 + dec = 0.2 + time = 10 + self.assertEqual( + gwutils.time_delay_geocentric(det1, det1, ra, dec, time), 0) + self.assertEqual( + gwutils.time_delay_geocentric(det1, det2, ra, dec, time), + 1.3253791114055397e-10) + + def test_get_polarization_tensor(self): + ra = 1 + dec = 2.0 + time = 10 + psi = 0.1 + for mode in ['plus', 'cross', 'breathing', 'longitudinal', 'x', 'y']: + p = gwutils.get_polarization_tensor(ra, dec, time, psi, mode) + self.assertEqual(p.shape, (3, 3)) + with self.assertRaises(ValueError): + gwutils.get_polarization_tensor(ra, dec, time, psi, 'not-a-mode') + + def test_inner_product(self): + aa = np.array([1, 2, 3]) + bb = np.array([5, 6, 7]) + frequency = np.array([0.2, 0.4, 0.6]) + PSD = bilby.gw.detector.PowerSpectralDensity.from_aligo() + ip = gwutils.inner_product(aa, bb, frequency, PSD) + self.assertEqual(ip, 0) + + def test_noise_weighted_inner_product(self): + aa = np.array([1e-23, 2e-23, 3e-23]) + bb = np.array([5e-23, 6e-23, 7e-23]) + frequency = np.array([100, 101, 102]) + PSD = bilby.gw.detector.PowerSpectralDensity.from_aligo() + psd = PSD.power_spectral_density_interpolated(frequency) + duration = 4 + nwip = gwutils.noise_weighted_inner_product(aa, bb, psd, duration) + self.assertEqual(nwip, 239.87768033598326) + + self.assertEqual( + gwutils.optimal_snr_squared(aa, psd, duration), + gwutils.noise_weighted_inner_product(aa, aa, psd, duration)) + + def test_matched_filter_snr(self): + signal = np.array([1e-23, 2e-23, 3e-23]) + frequency_domain_strain = np.array([5e-23, 6e-23, 7e-23]) + frequency = np.array([100, 101, 102]) + PSD = bilby.gw.detector.PowerSpectralDensity.from_aligo() + psd = PSD.power_spectral_density_interpolated(frequency) + duration = 4 + + mfsnr = gwutils.matched_filter_snr( + signal, frequency_domain_strain, psd, duration) + self.assertEqual(mfsnr, 25.510869054168282) + + def test_get_event_time(self): + events = ['GW150914', 'GW151012', 'GW151226', 'GW170104', 'GW170608', + 'GW170729', 'GW170809', 'GW170814', 'GW170817', 'GW170818', + 'GW170823'] + for event in events: + self.assertTrue(isinstance(gwutils.get_event_time(event), float)) + + self.assertTrue(gwutils.get_event_time('GW010290') is None) + + def test_read_frame_file(self): + start_time = 0 + end_time = 10 + channel = 'H1:GDS-CALIB_STRAIN' + N = 100 + times = np.linspace(start_time, end_time, N) + data = np.random.normal(0, 1, N) + ts = gwpy.timeseries.TimeSeries(data=data, times=times, t0=0) + ts.channel = gwpy.detector.Channel(channel) + ts.name = channel + filename = os.path.join(self.outdir, 'test.gwf') + ts.write(filename, format='gwf') + + # Check reading without time limits + strain = gwutils.read_frame_file( + filename, start_time=None, end_time=None, channel=channel) + self.assertEqual(strain.channel.name, channel) + self.assertTrue(np.all(strain.value==data)) + + # Check reading with time limits + start_cut = 2 + end_cut = 8 + strain = gwutils.read_frame_file( + filename, start_time=start_cut, end_time=end_cut, channel=channel) + idxs = (times > start_cut) & (times < end_cut) + # Dropping the last element - for some reason gwpy drops the last element when reading in data + self.assertTrue(np.all(strain.value==data[idxs][:-1])) + + # Check reading with unknown channels + strain = gwutils.read_frame_file( + filename, start_time=None, end_time=None) + self.assertTrue(np.all(strain.value==data)) + + # Check reading with incorrect channel + strain = gwutils.read_frame_file( + filename, start_time=None, end_time=None, channel='WRONG') + self.assertTrue(np.all(strain.value==data)) + + ts = gwpy.timeseries.TimeSeries(data=data, times=times, t0=0) + ts.name = 'NOT-A-KNOWN-CHANNEL' + ts.write(filename, format='gwf') + strain = gwutils.read_frame_file( + filename, start_time=None, end_time=None) + self.assertEqual(strain, None) + + def test_convert_args_list_to_float(self): + self.assertEqual( + gwutils.convert_args_list_to_float(1, '2', 3.0), [1.0, 2.0, 3.0]) + with self.assertRaises(ValueError): + gwutils.convert_args_list_to_float(1, '2', 'ten') + + def test_lalsim_SimInspiralTransformPrecessingNewInitialConditions(self): + a = gwutils.lalsim_SimInspiralTransformPrecessingNewInitialConditions( + 0.1, 0, 0.6, 0.5, 0.6, 0.1, 0.8, 30.6, 23.2, 50, 0) + self.assertTrue(len(a) == 7) + + def test_get_approximant(self): + with self.assertRaises(ValueError): + gwutils.lalsim_GetApproximantFromString(10) + self.assertEqual(gwutils.lalsim_GetApproximantFromString("IMRPhenomPV2"), 69) + + def test_lalsim_SimInspiralChooseFDWaveform(self): + a = gwutils.lalsim_SimInspiralChooseFDWaveform( + 35.2, 20.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 1000, 2, 2.3, + 45., 0.1, 10, 0.01, 10, 1000, 20, None, 69) + self.assertEqual(len(a), 2) + self.assertEqual(type(a[0]), lal.COMPLEX16FrequencySeries) + self.assertEqual(type(a[1]), lal.COMPLEX16FrequencySeries) + + with self.assertRaises(ValueError): + a = gwutils.lalsim_SimInspiralChooseFDWaveform( + 35.2, 20.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 1000, 2, 2.3, + 45., 0.1, 10, 0.01, 10, 1000, 20, None, 'IMRPhenomPV2') + + def test_lalsim_SimIMRPhenomPCalculateModelParametersFromSourceFrame(self): + version = lalsim.IMRPhenomPv2_V + a = gwutils.lalsim_SimIMRPhenomPCalculateModelParametersFromSourceFrame( + 25.6, 12.2, 50, 0.2, 0, 0, 0, 0, 0, 0, 0, version) + self.assertEqual(len(a), 7) + + +if __name__ == '__main__': + unittest.main()