def test_properties2(capfd): """Test if the describe function produces an output. The output is 1870 characters at the moment, but we might add more properties.""" tpf = KeplerTargetPixelFile(filename_tpf_all_zeros) tpf.show_properties() out, err = capfd.readouterr() assert len(out) > 1000
def test_accessor_k2_campaign(): # scaled down version of tess sector test, as they share the same codepath lc0 = KeplerLightCurve( time=np.arange(1, 5), flux=np.arange(1, 5), flux_err=np.arange(1, 5), targetid=50000, ) lc0.meta["CAMPAIGN"] = 2 lc1 = KeplerLightCurve( time=np.arange(10, 15), flux=np.arange(10, 15), flux_err=np.arange(10, 15), targetid=120334, ) lc1.meta["CAMPAIGN"] = 1 lcc = LightCurveCollection([lc0, lc1]) assert (lcc.campaign == [2, 1]).all() # ensure it works for TPFs too. tpf0 = KeplerTargetPixelFile(filename_tpf_all_zeros) tpf0.hdu[0].header["CAMPAIGN"] = 2 tpf1 = KeplerTargetPixelFile(filename_tpf_one_center) tpf1.hdu[0].header["CAMPAIGN"] = 1 tpfc = TargetPixelFileCollection([tpf0, tpf1]) assert (tpfc.campaign == [2, 1]).all()
def test_bitmasking(quality_bitmask, answer): """Test whether the bitmasking behaves like it should""" tpf = KeplerTargetPixelFile(filename_tpf_one_center, quality_bitmask=quality_bitmask) with warnings.catch_warnings(): # Ignore "LightCurve contains NaN times" warnings triggered by liberal masks warnings.simplefilter("ignore", LightkurveWarning) lc = tpf.to_lightcurve() assert len(lc.flux) == answer
def test_tpfcollection_plot(): tpf = KeplerTargetPixelFile(filename_tpf_all_zeros) tpf2 = KeplerTargetPixelFile(filename_tpf_one_center) # Does plotting work with 3 TPFs? coll = TargetPixelFileCollection([tpf, tpf2, tpf2]) coll.plot() # Does plotting work with one TPF? coll = TargetPixelFileCollection([tpf]) coll.plot() plt.close("all")
def test_wcs_tabby(method): """Test the centroids from Tabby's star against simbad values""" tpf = KeplerTargetPixelFile(TABBY_TPF) tpf.wcs ra, dec = tpf.get_coordinates(0) col, row = tpf.estimate_centroids(method=method) col = col.value - tpf.column row = row.value - tpf.row y, x = int(np.round(col[0])), int(np.round(row[1])) # Compare with RA and Dec from Simbad assert np.isclose(ra[x, y], 301.5643971, 1e-4) assert np.isclose(dec[x, y], 44.4568869, 1e-4)
def test_sine_sff(): """Can we recover a synthetic sine curve using SFF and LombScargle?""" # Retrieve the custom, known signal properties tpf = KeplerTargetPixelFile(filename_synthetic_sine) true_period = np.float(tpf.hdu[3].header["PERIOD"]) true_amplitude = np.float(tpf.hdu[3].header["SINE_AMP"]) # Run the SFF algorithm lc = tpf.to_lightcurve() corrector = SFFCorrector(lc) cor_lc = corrector.correct( tpf.pos_corr2, tpf.pos_corr1, niters=4, windows=1, bins=7, restore_trend=True, timescale=0.5, ) # Verify that we get the period within ~20% pg = cor_lc.to_periodogram( method="lombscargle", minimum_period=1, maximum_period=10, oversample_factor=10 ) ret_period = pg.period_at_max_power.value threshold = 0.2 assert (ret_period > true_period * (1 - threshold)) & ( ret_period < true_period * (1 + threshold) ) # Verify that we get the amplitude to within 10% n_cad = len(tpf.time) design_matrix = np.vstack( [ np.ones(n_cad), np.sin(2.0 * np.pi * cor_lc.time.value / ret_period), np.cos(2.0 * np.pi * cor_lc.time.value / ret_period), ] ).T ATA = np.dot(design_matrix.T, design_matrix / cor_lc.flux_err[:, None] ** 2) least_squares_coeffs = np.linalg.solve( ATA, np.dot(design_matrix.T, cor_lc.flux / cor_lc.flux_err ** 2) ) const, sin_weight, cos_weight = least_squares_coeffs fractional_amplitude = (sin_weight ** 2 + cos_weight ** 2) ** (0.5) / const assert (fractional_amplitude > true_amplitude / 1.1) & ( fractional_amplitude < true_amplitude * 1.1 )
def test_get_model_prf(): tpf_fn = get_pkg_data_filename("../../tests/data/test-tpf-star.fits") tpf = KeplerTargetPixelFile(tpf_fn) prf = KeplerPRF(channel=tpf.channel, shape=tpf.shape[1:], column=tpf.column, row=tpf.row) prf_from_tpf = tpf.get_prf_model() assert type(prf) == type(prf_from_tpf) assert prf.channel == prf_from_tpf.channel assert prf.shape == prf_from_tpf.shape assert prf.column == prf_from_tpf.column assert prf.row == prf_from_tpf.row
def plot(self, *args, **kwargs): """ Plot a target pixel file at a given frame (index) or cadence number. Parameters ---------- ax : matplotlib.axes._subplots.AxesSubplot A matplotlib axes object to plot into. If no axes is provided, a new one will be generated. frame : int Frame number. The default is 0, i.e. the first frame. cadenceno : int, optional Alternatively, a cadence number can be provided. This argument has priority over frame number. bkg : bool If True, background will be added to the pixel values. aperture_mask : ndarray Highlight pixels selected by aperture_mask. show_colorbar : bool Whether or not to show the colorbar mask_color : str Color to show the aperture mask style : str matplotlib.pyplot.style.context, default is 'fast' kwargs : dict Keywords arguments passed to `lightkurve.utils.plot_image`. Returns ------- ax : matplotlib.axes._subplots.AxesSubplot The matplotlib axes object. """ ax = KeplerTargetPixelFile.plot(self, *args, **kwargs) ax.set_title('TIC: {}'.format(self.tic_id)) return ax
def test_centroids(): """Test the estimate centroid method.""" for fn in ( filename_synthetic_sine, filename_synthetic_transit, filename_synthetic_flat, ): tpf = KeplerTargetPixelFile(fn) xraw, yraw = tpf.estimate_centroids() xnorm = xraw - np.median(xraw) ynorm = yraw - np.median(yraw) xposc = tpf.pos_corr2 - np.median(tpf.pos_corr2) yposc = tpf.pos_corr1 - np.median(tpf.pos_corr1) rmax = np.max(np.sqrt((xnorm.value - xposc) ** 2 + (ynorm.value - yposc) ** 2)) # The centroids should agree to within a hundredth of a pixel. assert rmax < 0.01
def test_interact_sky(): """Test the Jupyter notebook interact() widget.""" for tpf in [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tess), ]: tpf.interact_sky()
def test_tpf_plot(): """Sanity check to verify that tpf plotting works""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tpf_one_center), ] for tpf in tpfs: tpf.plot() tpf.plot(aperture_mask=tpf.pipeline_mask) tpf.plot(aperture_mask="all") tpf.plot(frame=3) with pytest.raises(ValueError): tpf.plot(frame=999999) tpf.plot(cadenceno=125250) with pytest.raises(ValueError): tpf.plot(cadenceno=999) tpf.plot(bkg=True) tpf.plot(scale="sqrt") tpf.plot(scale="log") with pytest.raises(ValueError): tpf.plot(scale="blabla") tpf.plot(column="FLUX") tpf.plot(column="FLUX_ERR") tpf.plot(column="FLUX_BKG") tpf.plot(column="FLUX_BKG_ERR") tpf.plot(column="RAW_CNTS") tpf.plot(column="COSMIC_RAYS") with pytest.raises(ValueError): tpf.plot(column="not a column") plt.close("all")
def test_repr(): """Do __str__ and __repr__ work?""" for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: str(tpf) repr(tpf)
def test_load_bad_file(): """Test if a light curve can be opened without exception.""" with pytest.raises(ValueError) as exc: KeplerTargetPixelFile(TABBY_Q8) assert "is this a target pixel file?" in exc.value.args[0] with pytest.raises(ValueError) as exc: TessTargetPixelFile(TABBY_Q8) assert "is this a target pixel file?" in exc.value.args[0]
def test_transform_and_ylim_funcs(): """Test the transform_func and ylim_func""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [KeplerTargetPixelFile(filename_tpf_tabby_lite), TessTargetPixelFile(example_tpf)] for tpf in tpfs: tpf.interact(transform_func=lambda lc: lc.normalize()) tpf.interact(transform_func=lambda lc: lc.flatten().normalize()) tpf.interact(transform_func=lambda lc: lc, ylim_func=lambda lc: (0, 2)) tpf.interact(ylim_func=lambda lc: (0, lc.flux.max()))
def test_wcs(): """Test the wcs property.""" for tpf in [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tess), ]: w = tpf.wcs ra, dec = tpf.get_coordinates() assert ra.shape == tpf.shape assert dec.shape == tpf.shape assert type(w).__name__ == "WCS"
def test_bkg_lightcurve(): for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: lc = tpf.get_bkg_lightcurve() lc = tpf.get_bkg_lightcurve(aperture_mask=None) lc = tpf.get_bkg_lightcurve(aperture_mask="all") assert lc.time.scale == "tdb" assert lc.flux.shape == lc.flux_err.shape assert len(lc.time) == len(lc.flux)
def test_tpf_shapes(): """Are the data array shapes of the TargetPixelFile object consistent?""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tpf_all_zeros), ] for tpf in tpfs: assert tpf.quality_mask.shape == tpf.hdu[1].data["TIME"].shape assert tpf.flux.shape == tpf.flux_err.shape
def test_transit_sff(): """Can we recover a synthetic exoplanet signal using SFF and BLS?""" # Retrieve the custom, known signal properties tpf = KeplerTargetPixelFile(filename_synthetic_transit) true_period = np.float(tpf.hdu[3].header["PERIOD"]) true_rprs = np.float(tpf.hdu[3].header["RPRS"]) true_transit_lc = tpf.hdu[3].data["NOISELESS_INPUT"] max_depth = 1 - np.min(true_transit_lc) # Run the SFF algorithm lc = tpf.to_lightcurve().normalize() corrector = SFFCorrector(lc) cor_lc = corrector.correct( tpf.pos_corr2, tpf.pos_corr1, niters=4, windows=1, bins=7, restore_trend=False, timescale=0.5, ) # Verify that we get the transit period within 5% pg = cor_lc.to_periodogram( method="bls", minimum_period=1, maximum_period=9, frequency_factor=0.05, duration=np.arange(0.1, 0.6, 0.1), ) ret_period = pg.period_at_max_power.value threshold = 0.05 assert (ret_period > true_period * (1 - threshold)) & ( ret_period < true_period * (1 + threshold) ) # Verify that we get the transit depth in expected bounds assert (pg.depth_at_max_power >= true_rprs ** 2) & ( pg.depth_at_max_power < max_depth )
def test_detrending_residuals(): """Test the detrending residual distributions""" # Retrieve the custom, known signal properties tpf = KeplerTargetPixelFile(filename_synthetic_flat) # Run the SFF algorithm lc = tpf.to_lightcurve() corrector = SFFCorrector(lc) cor_lc = corrector.correct( tpf.pos_corr2, tpf.pos_corr1, niters=10, windows=5, bins=7, restore_trend=True ) # Verify that we get a significant reduction in RMS cdpp_improvement = lc.estimate_cdpp() / cor_lc.estimate_cdpp() assert cdpp_improvement > 10.0 # The residuals should be Gaussian-"ish" # Table 4.1 of Ivezic, Connolly, Vanerplas, Gray 2014 anderson_threshold = 1.57 resid_n_sigmas = (cor_lc.flux - np.mean(cor_lc.flux)) / cor_lc.flux_err A_value, _, _ = stats.anderson(resid_n_sigmas) assert A_value ** 2 < anderson_threshold n_sigma = np.std(resid_n_sigmas) assert n_sigma < 2.0 corrector = tpf.to_corrector("pld") cor_lc = corrector.correct(restore_trend=False) cdpp_improvement = lc.estimate_cdpp() / cor_lc.estimate_cdpp() assert cdpp_improvement > 10.0 resid_n_sigmas = (cor_lc.flux - np.mean(cor_lc.flux)) / cor_lc.flux_err A_value, crit, sig = stats.anderson(resid_n_sigmas) assert A_value ** 2 < anderson_threshold n_sigma = np.std(resid_n_sigmas) assert n_sigma < 2.0
def test_aperture_photometry(): for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: tpf.extract_aperture_photometry() for mask in [None, "all", "default", "threshold", "background"]: tpf.extract_aperture_photometry(aperture_mask=mask) if np.any(tpf.pipeline_mask): tpf.extract_aperture_photometry(aperture_mask="pipeline") else: with pytest.raises(ValueError): tpf.extract_aperture_photometry(aperture_mask="pipeline")
def test_get_models(): """Can we obtain PRF and TPF models?""" tpf = KeplerTargetPixelFile(filename_tpf_all_zeros, quality_bitmask=None) with warnings.catch_warnings(): # Ignore "RuntimeWarning: All-NaN slice encountered" warnings.simplefilter("ignore", RuntimeWarning) tpf.get_model() tpf.get_prf_model()
def test_tpf_to_fits(): """Can we write a TPF back to a fits file?""" for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: # `delete=False` is necessary to enable writing to the file on Windows # but it means we have to clean up the tmp file ourselves tmp = tempfile.NamedTemporaryFile(delete=False) try: tpf.to_fits(tmp.name) finally: tmp.close() os.remove(tmp.name)
def test_tpfcollection(): tpf = KeplerTargetPixelFile(filename_tpf_all_zeros) tpf2 = KeplerTargetPixelFile(filename_tpf_one_center) tpfc = TargetPixelFileCollection([tpf, tpf2]) assert len(tpfc) == 2 assert tpfc.data == [tpf, tpf2] tpfc.append(tpf2) assert len(tpfc) == 3 assert tpfc[0] == tpf assert tpfc[1] == tpf2 assert tpfc[2] == tpf2 with pytest.raises(IndexError): tpfc[51] # ensure index by boolean array also works for TPFs tpfc_f = tpfc[[False, True, True]] assert tpfc_f.data == [tpf2, tpf2] assert type(tpfc_f) is TargetPixelFileCollection # Test __setitem__ tpf3 = KeplerTargetPixelFile(filename_tpf_one_center, targetid=55) tpfc[1] = tpf3 assert tpfc[1] == tpf3 tpfc.append(tpf2) assert tpfc[2] == tpf2 str(tpfc) # Regression test for #564
def test_custom_aperture_mask(): """Can we provide a custom lightcurve to show?""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [KeplerTargetPixelFile(filename_tpf_tabby_lite), TessTargetPixelFile(example_tpf)] import bokeh for tpf in tpfs: mask = tpf.flux[0, :, :] == tpf.flux[0, :, :] tpf.interact(aperture_mask=mask) mask = None tpf.interact(aperture_mask=mask) mask = "threshold" tpf.interact(aperture_mask=mask)
def test_to_lightcurve(): for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: tpf.to_lightcurve() tpf.to_lightcurve(aperture_mask=None) tpf.to_lightcurve(aperture_mask="all") lc = tpf.to_lightcurve(aperture_mask="threshold") assert lc.time.scale == "tdb" assert lc.label == tpf.hdu[0].header["OBJECT"] if np.any(tpf.pipeline_mask): tpf.to_lightcurve(aperture_mask="pipeline") else: with pytest.raises(ValueError): tpf.to_lightcurve(aperture_mask="pipeline")
def test_tpf_math(): """Can you add, subtract, multiply and divide?""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tpf_all_zeros), ] # These should work for tpf in tpfs: for other in [1, np.ones(tpf.flux.shape[1:]), np.ones(tpf.shape)]: tpf + other tpf - other tpf * other tpf / other tpf += other tpf -= other tpf *= other tpf /= other # These should fail with a value error because their shape is wrong. for tpf in tpfs: for other in [ np.asarray([1, 2]), np.arange(len(tpf.time) - 1), np.ones([100, 1]), np.ones([1, 2, 3]), ]: with pytest.raises(ValueError): tpf + other # Check the values are correct assert np.all(((tpf.flux.value + 2) == (tpf + 2).flux.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux.value - 2) == (tpf - 2).flux.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux.value * 2) == (tpf * 2).flux.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux.value / 2) == (tpf / 2).flux.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux_err.value * 2) == (tpf * 2).flux_err.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux_err.value / 2) == (tpf / 2).flux_err.value)[np.isfinite(tpf.flux)])
def test_cutout(): """Test tpf.cutout() function.""" for tpf in [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tess, quality_bitmask=None), ]: ntpf = tpf.cutout(size=2) assert ntpf.flux[0].shape == (2, 2) assert ntpf.flux_err[0].shape == (2, 2) assert ntpf.flux_bkg[0].shape == (2, 2) ntpf = tpf.cutout((0, 0), size=3) ntpf = tpf.cutout(size=(1, 2)) assert ntpf.flux.shape[1] == 2 assert ntpf.flux.shape[2] == 1 ntpf = tpf.cutout(SkyCoord(tpf.ra, tpf.dec, unit="deg"), size=2) ntpf = tpf.cutout(size=2) assert np.product(ntpf.flux.shape[1:]) == 4 assert ntpf.targetid == "{}_CUTOUT".format(tpf.targetid)
def test_custom_exported_filename(): """Can we provide a custom lightcurve to show?""" import bokeh with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [KeplerTargetPixelFile(filename_tpf_tabby_lite), TessTargetPixelFile(example_tpf)] for tpf in tpfs: tpf.interact(exported_filename="demo.fits") tpf[0:2].interact() tpf[0:2].interact(exported_filename="string_only") tpf[0:2].interact(exported_filename="demo2.FITS") tpf[0:2].interact(exported_filename="demo3.png") tpf[0:2].interact(exported_filename="") tpf.interact(exported_filename=210690913) mask = tpf.time == tpf.time tpf[mask].interact()
def test_tpf_ones(centroid_method): """Does the LightCurve of a one-flux TPF make sense?""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tpf_one_center), ] for tpf in tpfs: lc = tpf.to_lightcurve(aperture_mask="all", centroid_method=centroid_method) assert np.all(lc.flux.value == 1) assert np.all( (lc.centroid_col.value < tpf.column + tpf.shape[1]).all() * (lc.centroid_col.value > tpf.column).all()) assert np.all((lc.centroid_row.value < tpf.row + tpf.shape[2]).all() * (lc.centroid_row.value > tpf.row).all())
def test_tpf_ones(centroid_method): """Does the LightCurve of a one-flux TPF make sense? Regression test for #1103.""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tpf_one_center), ] for tpf in tpfs: lc = tpf.to_lightcurve(aperture_mask="all", centroid_method=centroid_method) assert np.all(lc.flux.value == 1) # The test TPF file contains 3x3 pixels with a single bright pixel in the center pixel. # Because pixel coordinates refer to the center of a pixel (cf. #755), # we expect the centroid to be exactly one larger than the corner coordinates. # This is a regression test for #1103. assert np.all(lc.centroid_row.value == tpf.row + 1) assert np.all(lc.centroid_col.value == tpf.column + 1)