def test_write_text_data(self): """ Test that data can be correctly written (and re-read) from a text file. """ times = np.linspace(1000000000.0, 1000086340.0, 1440) data = np.random.normal(0.0, 1e-25, size=(1440, 2)) het = HeterodynedData(data, times=times) for suffix in ["txt", "txt.gz"]: datafile = "testdata.{}".format(suffix) het.write(datafile) # read in data hetnew = HeterodynedData.read(datafile) assert np.array_equal(het.data, hetnew.data) assert np.array_equal(het.times, hetnew.times) # check things that the read-in data should not contain assert hetnew.detector is None assert hetnew.par is None os.remove(datafile) # clean up file
def test_wrong_inputs(self): """ Test that exceptions are raised for incorrect inputs to the TargetedPulsarLikelihood. """ with pytest.raises(TypeError): TargetedPulsarLikelihood(None, None) # create HeterodynedData object (no par file) het = HeterodynedData(self.data, times=self.times, detector=self.detector) priors = dict() priors["h0"] = Uniform(0.0, 1.0e-23, "h0") # error with no par file with pytest.raises(ValueError): TargetedPulsarLikelihood(het, PriorDict(priors)) het = HeterodynedData(self.data, times=self.times, detector=self.detector, par=self.parfile) mhet = MultiHeterodynedData(het) # multihet object for testing with pytest.raises(TypeError): TargetedPulsarLikelihood(het, None) with pytest.raises(TypeError): TargetedPulsarLikelihood(mhet, None)
def test_parse_detector(self): """ Test parsing a detector name and a lal.Detector """ from lal import Detector from lalpulsar import GetSiteInfo det = "BK" # "bad" detector times = np.linspace(1000000000.0, 1000086340.0, 1440) data = np.random.normal( 0.0, 1e-25, size=1440) + 1j * np.random.normal(0.0, 1e-25, size=1440) with pytest.raises(ValueError): HeterodynedData(data, times=times, detector=det) det = "H1" # good detector laldet = GetSiteInfo("H1") het = HeterodynedData(data, times=times, detector=det) assert het.detector == det assert isinstance(het.laldetector, Detector) assert het.laldetector.frDetector.prefix == laldet.frDetector.prefix assert np.all((het.laldetector.response == laldet.response).flatten()) # try passing the lal.Detector itself del het het = HeterodynedData(data, times=times, detector=laldet) assert het.detector == det assert isinstance(het.laldetector, Detector) assert het.laldetector.frDetector.prefix == laldet.frDetector.prefix assert np.all((het.laldetector.response == laldet.response).flatten())
def test_write_csv_data_std(self): """ Test that data can be correctly written (and re-read) from a CSV file with the standard deviations also output. """ times = np.linspace(1000000000.0, 1000086340.0, 1440) data = np.random.normal(0.0, 1e-25, size=(1440, 2)) stds = 1e-25 * np.ones_like(times) data = np.column_stack((data, stds)) het = HeterodynedData(data, times=times) datafile = "testdata.csv" het.write(datafile) # read in data hetnew = HeterodynedData.read(datafile) assert np.array_equal(het.data, hetnew.data) assert np.array_equal(het.times, hetnew.times) assert np.array_equal(het.stds, hetnew.stds) # check things that the read-in data should not contain assert hetnew.detector is None assert hetnew.par is None os.remove(datafile) # clean up file
def test_write_hdf_data(self): """ Test that data can be correctly written (and re-read) from a HDF5 file. """ times = np.linspace(1000000000.0, 1000086340.0, 1440) data = np.random.normal(0.0, 1e-25, size=(1440, 2)) det = "H1" parcontent = """\ PSRJ J0123+3456 RAJ 01:23:45.6789 DECJ 34:56:54.321 F0 567.89 F1 -1.2e-12 PEPOCH 56789 H0 9.87e-26 COSIOTA 0.3 PSI 1.1 PHI0 2.4 """ parfile = "J0123+3456.par" # add content to the par file with open(parfile, "w") as fp: fp.write(parcontent) het = HeterodynedData(data, times=times, detector=det, par=parfile) for suffix in ["hdf5", "hdf", "h5"]: datafile = "testdata.{}".format(suffix) het.write(datafile, overwrite=True) # read in data hetnew = HeterodynedData.read(datafile) assert np.array_equal(het.data, hetnew.data) assert np.array_equal(het.times, hetnew.times) # check that detector and par file are read in correctly assert hetnew.detector == det for key in het.par.as_dict(): if isinstance(hetnew.par[key], str): assert hetnew.par[key] == het.par[key] else: assert np.allclose(hetnew.par[key], het.par[key]) # check version information is stored assert het.cwinpy_version == hetnew.cwinpy_version assert het.cwinpy_version == cwinpy.__version__ os.remove(datafile) # clean up file os.remove(parfile)
def test_plot(self): """ Test plotting function (and at the same time test fake noise generation) """ # create an injection parameter file parcontent = """\ PSRJ J0000+0000 RAJ 00:00:00.0 DECJ 00:00:00.0 F0 123.45 F1 1.2e-11 PEPOCH 56789.0 H0 1.5e-22 """ parfile = "test.par" with open(parfile, "w") as fp: fp.write(parcontent) # one point per 10 mins times = np.linspace(1000000000.0, 1000085800.0, 144) with pytest.raises(AttributeError): # if no parameter file is given, then generating fake data for a # particular detector should fail het = HeterodynedData(times=times, fakeasd="H1") # set the asd explicitly het = HeterodynedData(times=times, fakeasd=1e-24, detector="H1", par=parfile, inject=True) mhd = MultiHeterodynedData(het) # not allowed argument with pytest.raises(ValueError): fig = mhd.plot(which="blah") # test different plot types for which in ["abs", "REAL", "im", "Both"]: fig = mhd.plot(which=which) assert isinstance(fig[0], Figure) del fig # remove the par file os.remove(parfile)
def setup_class(cls): """ Create directory for simulations. """ # set the base directory cls.basedir = os.path.join( os.path.split(os.path.realpath(__file__))[0], "simulation") os.makedirs(cls.basedir, exist_ok=True) # create pulsar parameter files for testing cls.pardir = os.path.join( os.path.split(os.path.realpath(__file__))[0], "test_pardir") os.makedirs(cls.pardir, exist_ok=True) cls.names = ["J0000+0000", "J0100+0000"] cls.ras = [0.0, (1 / 24) * 2 * np.pi] cls.decs = [0.0, 0.0] cls.dists = [1.0, None] cls.pardict = {} for name, ra, dec, dist in zip(cls.names, cls.ras, cls.decs, cls.dists): par = PulsarParameters() par["PSRJ"] = name par["F"] = [100.0] # set frequency to 100 Hz par["RAJ"] = ra par["DECJ"] = dec if dist is not None: par["DIST"] = (dist * u.kpc).to("m").value with open(os.path.join(cls.pardir, "{}.par".format(name)), "w") as fp: fp.write(str(par)) cls.pardict[name] = os.path.join(cls.pardir, "{}.par".format(name)) # create heterodyned data for testing cls.hetdir = os.path.join( os.path.split(os.path.realpath(__file__))[0], "test_hetdir") os.makedirs(cls.hetdir, exist_ok=True) cls.hetfiles = {} for det, name in zip(["H1", "L1"], ["J0000+0000", "J0100+0000"]): het = HeterodynedData( times=np.linspace(1000000000.0, 1000086340.0, 1440), fakeasd=det, par=os.path.join(cls.pardir, "{}.par".format(name)), ) cls.hetfiles[det] = os.path.join(cls.hetdir, "{}.hdf".format(name)) het.write(cls.hetfiles[det], overwrite=True)
def test_includephase_likelihood(self): """ Test the likelihood when include phase is set to True. """ het = HeterodynedData(self.data, times=self.times, detector=self.detector, par=self.parfile) priors = dict() priors["h0"] = Uniform(0.0, 1.0e-23, "h0") # run with includephase as False like1 = TargetedPulsarLikelihood(het, PriorDict(priors), likelihood="studentst") like1.parameters = {"h0": 1e-24} logl1 = like1.log_likelihood() # set includephase to True like2 = TargetedPulsarLikelihood(het, PriorDict(priors), likelihood="studentst") like2.parameters = {"h0": 1e-24} like2.include_phase = True logl2 = like2.log_likelihood() print(f"{logl1:.15f} {logl2:.15f}") assert np.allclose([logl1], [logl2], atol=1e-10, rtol=0.0)
def test_read_text_data(self): """ Test that a valid input file is read in correctly. """ # create a data file to output hetdata = """\ # times real imaginary 1000000000.0 -2.3e-25 4.3e-26 1000000060.0 3.2e-26 1.2e-25 1000000120.0 -1.7e-25 -2.8e-25 1000000180.0 -7.6e-26 -8.9e-26 """ datafile = "testdata.txt" with open("testdata.txt", "w") as fp: fp.write(hetdata) het = HeterodynedData(datafile) assert len(het) == 4 assert (het.data.real[0] == -2.3e-25) and (het.data.real[-1] == -7.6e-26) assert (het.data.imag[0] == 4.3e-26) and (het.data.imag[-1] == -8.9e-26) assert (het.times[0].value == 1000000000.0) and (het.times[-1].value == 1000000180.0) assert het.dt.value == 60.0 assert het.sample_rate.value == 1.0 / 60.0 assert het.cwinpy_heterodyne_pipeline_config is None assert het.heterodyne_arguments is None os.remove(datafile) # clean up file
def test_numba_likelihood(self): """ Test likelihood using numba against the standard likelihood. """ het = HeterodynedData(self.data, times=self.times, detector=self.detector, par=self.parfile) priors = dict() priors["h0"] = Uniform(0.0, 1.0e-23, "h0") for likelihood in ["gaussian", "studentst"]: like1 = TargetedPulsarLikelihood(het, PriorDict(priors), likelihood=likelihood) like1.parameters = {"h0": 1e-24} like2 = TargetedPulsarLikelihood(het, PriorDict(priors), likelihood=likelihood, numba=True) like2.parameters = {"h0": 1e-24} assert like1.log_likelihood() == like2.log_likelihood()
def test_read_csv_data_std(self): """ Test that a valid file with standard deviations is read in correctly. """ # create a data file to output hetdata = """\ # times real imaginary std 1000000000.0, -2.3e-25, 4.3e-26, 1.1e-26 1000000060.0, 3.2e-26, 1.2e-25, 2.1e-26 1000000120.0, -1.7e-25, -2.8e-25, 1.5e-26 1000000180.0, -7.6e-26, -8.9e-26, 1.3e-26 """ datafile = "testdata.csv" with open("testdata.csv", "w") as fp: fp.write(hetdata) het = HeterodynedData(datafile) assert len(het) == 4 assert (het.data.real[0] == -2.3e-25) and (het.data.real[-1] == -7.6e-26) assert (het.data.imag[0] == 4.3e-26) and (het.data.imag[-1] == -8.9e-26) assert (het.stds[0] == 1.1e-26) and (het.stds[-1] == 1.3e-26) assert (het.vars[0] == (1.1e-26)**2) and (het.vars[-1] == (1.3e-26)**2) assert (het.times[0].value == 1000000000.0) and (het.times[-1].value == 1000000180.0) assert het.dt.value == 60.0 assert het.sample_rate.value == 1.0 / 60.0 os.remove(datafile) # clean up file
def test_broken_data(self): """ Test reading of data fails during to a "broken" input file """ # create a "broken" input file (not the spurious "H") brokendata = """\ # times real imaginary 1000000000.0 -2.3e-25 4.3e-26 1000000060.0 H.2e-26 1.2e-25 1000000120.0 -1.7e-25 -2.8e-25 1000000180.0 -7.6e-26 -8.9e-26 """ brokenfile = "brokendata.txt" with open(brokenfile, "w") as fp: fp.write(brokendata) with pytest.raises(IOError): HeterodynedData(brokenfile) # run through MultiHeterodynedData with pytest.raises(IOError): MultiHeterodynedData(brokenfile) with pytest.raises(IOError): MultiHeterodynedData({"H1": brokenfile}) os.remove(brokenfile) # clean up file
def test_remove_duplicate_data(self): """ Test that duplicate data time stamps are removed. """ # create a data file to output hetdata = """\ # times real imaginary std 1000000000.0 -2.3e-25 4.3e-26 1.1e-26 1000000060.0 3.2e-26 1.2e-25 2.1e-26 1000000060.0 3.2e-26 1.2e-25 2.1e-26 1000000060.0 3.2e-26 1.2e-25 2.1e-26 1000000120.0 -1.7e-25 -2.8e-25 1.5e-26 1000000180.0 -7.6e-26 -8.9e-26 1.3e-26 1000000180.0 -7.6e-26 -8.9e-26 1.3e-26 """ datafile = "testdata.txt" with open("testdata.txt", "w") as fp: fp.write(hetdata) het = HeterodynedData(datafile) assert len(het) == 4 assert (het.data.real[0] == -2.3e-25) and (het.data.real[-1] == -7.6e-26) assert (het.data.imag[0] == 4.3e-26) and (het.data.imag[-1] == -8.9e-26) assert (het.stds[0] == 1.1e-26) and (het.stds[-1] == 1.3e-26) assert (het.vars[0] == (1.1e-26)**2) and (het.vars[-1] == (1.3e-26)**2) assert (het.times[0].value == 1000000000.0) and (het.times[-1].value == 1000000180.0) assert het.dt.value == 60.0 assert het.sample_rate.value == 1.0 / 60.0 os.remove(datafile) # clean up file
def test_running_median(self): """ Test the running median calculation. """ # set data times = np.linspace(1000000000.0, 1000001740, 31) data = np.random.normal( 0.0, 1e-25, size=31) + 1j * np.random.normal(0.0, 1e-25, size=31) window = 1 # window is too short with pytest.raises(ValueError): het = HeterodynedData(data, times=times, window=window) window = 1.5 # window is not an integer with pytest.raises(TypeError): het = HeterodynedData(data, times=times, window=window) window = 31 het = HeterodynedData(data, times=times, window=window) assert len(het.running_median) == len(het) # running median applies "mirror" to points at either end assert het.running_median.real[0] == np.median( np.concatenate((data.real[:len(data) // 2 + 1], data.real[len(data) // 2:0:-1]))) assert het.running_median.imag[0] == np.median( np.concatenate((data.imag[:len(data) // 2 + 1], data.imag[len(data) // 2:0:-1]))) assert het.running_median.real[len(data) // 2] == np.median(data.real) assert het.running_median.imag[len(data) // 2] == np.median(data.imag) assert het.running_median.real[-1] == np.median( np.concatenate(( data.real[len(data) // 2:], data.real[len(data) // 2:-1], ))) assert het.running_median.imag[-1] == np.median( np.concatenate(( data.imag[len(data) // 2:], data.imag[len(data) // 2:-1], ))) assert len(het.subtract_running_median()) == len(het) assert het.subtract_running_median()[0] == (data[0] - (np.median( np.concatenate(( data.real[:len(data) // 2 + 1], data.real[len(data) // 2:0:-1], ))) + 1j * np.median( np.concatenate(( data.imag[:len(data) // 2 + 1], data.imag[len(data) // 2:0:-1], )))))
def test_no_data(self): """ Test exception occurs if passing no data and no time stamps. """ # test exception if no data or times are passed with pytest.raises(ValueError): HeterodynedData()
def test_bad_ephemeris_files(self): """ Test passing bad solar system ephemeris files values. """ times = np.linspace(1000000000.0, 1000086340.0, 1440) data = np.random.normal(0.0, 1e-25, size=(1440, 2)) with pytest.raises(IOError): HeterodynedData(data, times=times, earthephemeris="kagskdgd") with pytest.raises(IOError): HeterodynedData(data, times=times, sunephemeris="kagskdgd") with pytest.raises(TypeError): HeterodynedData(data, times=times, earthephemeris=1.2) with pytest.raises(TypeError): HeterodynedData(data, times=times, sunephemeris=13)
def test_array_no_times(self): """ Test that failure occurs if no time steps are passed. """ data = np.random.normal( 0.0, 1e-25, size=1440) + 1j * np.random.normal(0.0, 1e-25, size=1440) with pytest.raises(ValueError): HeterodynedData(data)
def test_outlier_removal(self): """ Test the outlier removal algorithm. """ # set data times = np.linspace(1000000000.0, 1000001740, 30) data = np.random.normal( 0.0, 1.0, size=30) + 1j * np.random.normal(0.0, 1.0, size=30) # add outliers (one in the real part and one in the imaginary) data[10] = 20.0 + data.imag[10] * 1j data[20] = data.real[20] - 20.0 * 1j het = HeterodynedData(data, times=times) # try finding the outlier (and testing exceptions) thresh = "a" with pytest.raises(TypeError): _ = het.find_outliers(thresh=thresh) thresh = -1.0 with pytest.raises(ValueError): _ = het.find_outliers(thresh=thresh) idxs = het.find_outliers() assert len(np.where(idxs == True)[0]) >= 2 # noqa: E712 assert (10 in np.where(idxs == True)[0]) and ( 20 in np.where(idxs == True)[0]) # noqa: E712 # test removing the outlier automatically newhet = HeterodynedData(data, times=times, remove_outliers=True) assert len(newhet) == (len(data) - len(np.where(idxs == True)[0]) ) # noqa: E712
def test_array_data_broken_lengths(self): """ Test that failure occurs if the number of time stamps is different from the number of data points. """ times = np.linspace(1000000000.0, 1000086340.0, 1439) data = np.random.normal( 0.0, 1e-25, size=1440) + 1j * np.random.normal(0.0, 1e-25, size=1440) with pytest.raises(ValueError): HeterodynedData(data, times=times)
def test_zero_data(self): """ Test that data containing zeros is produced if only time stamps are provided. """ # create "zero" data by only passing a set of times times = np.linspace(1000000000.0, 1000086340.0, 1440) het = HeterodynedData(times=times) assert len(het) == len(times) assert np.all(het.data == 0.0)
def test_array_data(self): """ Test passing the data as arrays containing times and data. """ times = np.linspace(1000000000.0, 1000086340.0, 1440) data = np.random.normal(0.0, 1e-25, size=(1440, 2)) het = HeterodynedData(data, times=times) assert np.all(het.times.value == times) assert np.all(het.data.real == data[:, 0]) assert np.all(het.data.imag == data[:, 1]) assert het.dt.value == (times[1] - times[0])
def test_wrong_likelihood(self): """ Test with a bad likelihood name. """ het = HeterodynedData(self.data, times=self.times, detector=self.detector, par=self.parfile) priors = dict() priors["h0"] = Uniform(0.0, 1.0e-23, "h0") with pytest.raises(ValueError): _ = TargetedPulsarLikelihood(het, PriorDict(priors), likelihood="blah")
def test_priors(self): """ Test the parsed priors. """ # bad priors (unexpected parameter names) priors = dict() priors["a"] = Uniform(0.0, 1.0, "blah") priors["b"] = 2.0 het = HeterodynedData(self.data, times=self.times, detector=self.detector, par=self.parfile) with pytest.raises(ValueError): _ = TargetedPulsarLikelihood(het, PriorDict(priors))
def test_nonuniform_data(self): """ Test that non-uniform data times stamps are correctly retained. """ # create four datasets times = np.linspace(1000000000.0, 1000086340.0, 1440) # remove some times to create non-uniform sampling times = np.delete(times, [20, 897, 1200]) data = np.random.normal(0.0, 1e-25, size=(len(times), 2)) detector = "H1" het = HeterodynedData(data=data, times=times, detector=detector) assert np.all(times == het.times.value) assert het.dt.value == np.min(np.diff(times))
def test_likelihood_null_likelihood(self): """ Test likelihood and null likelihood. """ het = HeterodynedData(self.data, times=self.times, detector=self.detector, par=self.parfile) priors = dict() priors["h0"] = Uniform(0.0, 1.0e-23, "h0") for likelihood in ["gaussian", "studentst"]: like = TargetedPulsarLikelihood(het, PriorDict(priors), likelihood=likelihood) like.parameters = {"h0": 0.0} assert like.log_likelihood() == like.noise_log_likelihood()
def test_running_median(self): """ Test the running median calculation. """ # set data times = np.linspace(1000000000.0, 1000001740, 30) data = np.random.normal( 0.0, 1e-25, size=30) + 1j * np.random.normal(0.0, 1e-25, size=30) window = 1 # window is too short with pytest.raises(ValueError): het = HeterodynedData(data, times=times, window=window) window = 1.5 # window is not an integer with pytest.raises(TypeError): het = HeterodynedData(data, times=times, window=window) window = 30 het = HeterodynedData(data, times=times, window=window) assert len(het.running_median) == len(het) assert het.running_median.real[0] == np.median( data.real[:(window // 2) + 1]) assert het.running_median.imag[0] == np.median( data.imag[:(window // 2) + 1]) assert het.running_median.real[len(data) // 2 - 1] == np.median( data.real) assert het.running_median.imag[len(data) // 2 - 1] == np.median( data.imag) assert het.running_median.real[-1] == np.median( data.real[-(window // 2):]) assert het.running_median.imag[-1] == np.median( data.imag[-(window // 2):]) assert len(het.subtract_running_median()) == len(het) assert het.subtract_running_median()[0] == ( data[0] - (np.median(data.real[:(window // 2) + 1]) + 1j * np.median(data.imag[:(window // 2) + 1])))
def test_too_many_columns(self): """ Test for failure if there are too many columns in the data file. """ # create a "broken" input file (not the spurious "H") brokendata = """\ # times real imaginary std extra 1000000000.0 -2.3e-25 4.3e-26 1e-26 1 1000000060.0 3.2e-26 1.2e-25 1e-26 2 1000000120.0 -1.7e-25 -2.8e-25 1e-26 3 1000000180.0 -7.6e-26 -8.9e-26 1e-26 4 """ brokenfile = "brokendata.txt" with open(brokenfile, "w") as fp: fp.write(brokendata) with pytest.raises(IOError): HeterodynedData(brokenfile) os.remove(brokenfile) # clean up file
def test_too_few_columns(self): """ Test for failure if there are too few columns in the data file. """ # create a "broken" input file (not the spurious "H") brokendata = """\ # times real 1000000000.0 -2.3e-25 1000000060.0 3.2e-26 1000000120.0 -1.7e-25 1000000180.0 -7.6e-26 """ brokenfile = "brokendata.txt" with open(brokenfile, "w") as fp: fp.write(brokendata) with pytest.raises(IOError): HeterodynedData(brokenfile) os.remove(brokenfile) # clean up file
if not os.path.isdir(outdir): os.makedirs(outdir) # add content to the par file parfile = os.path.join(outdir, "{}.par".format(label)) with open(parfile, "w") as fp: fp.write(parcontent) # create some fake heterodyned data detector = "H1" # the detector to use asd = 1e-24 # noise amplitude spectral density times = np.linspace(1000000000.0, 1000086340.0, 1440) # times het = HeterodynedData( times=times, par=parfile, injpar=parfile, inject=True, fakeasd=asd, detector=detector, ) # output the data hetfile = os.path.join(outdir, "{}_data.txt".format(label)) het.write(hetfile) # create priors phi0range = [0.0, np.pi] psirange = [0.0, np.pi / 2.0] cosiotarange = [-1.0, 1.0] h0range = [0.0, 1e-23] # set prior for lalapps_pulsar_parameter_estimation_nested
# add content to the par file parfile = os.path.join(outdir, "{}.par".format(label)) with open(parfile, "w") as fp: fp.write(parcontent) # create some fake heterodyned data detector = "H1" # the detector to use asds = [1e-24, 2e-24] # noise amplitude spectral densities times = np.linspace(1000000000.0, 1000086340.0, 1440) # times harmonics = [1, 2] hetfiles = [] for harmonic, asd in zip(harmonics, asds): het = HeterodynedData( times=times, par=parfile, fakeasd=asd, detector=detector, freqfactor=harmonic ) # output the data hetfile = os.path.join( outdir, "{}_{}_{}_data.txt".format(label, detector, harmonic) ) het.write(hetfile) hetfiles.append(hetfile) # create priors phi21range = [0.0, 2.0 * np.pi] phi22range = [0.0, 2.0 * np.pi] psirange = [0.0, np.pi / 2.0] cosiotarange = [-1.0, 1.0] c21range = [0.0, 1e-23]