Replicating Vanderburg & Johnson 2014 using lightkurve¶
Vanderburg and Johnson 2014 introduced a method for “Self Flat Fielding” by tracking how the lightcurve changes with motion of the spacecraft.
We reproduce the publication algorithm in a companion
notebook, which explains how
the method works, and illustrates some of the python code underlying the
code we put into
In this notebook we replicate the K2SFF method using only the
lightkurve package. We follow the same example K2 source, #60021426,
as that in the publication. We start from the Target Pixel File and
proceed to a “systematics corrected” lightcurve plot similar to the one
in the paper and in our companion notebook. We hope to show the
ease-of-use of the new
lightkurve toolkit, and that it achieves
identical performace with published papers.
%matplotlib inline import numpy as np import matplotlib.pyplot as plt
from lightkurve import KeplerTargetPixelFile from lightkurve import SFFCorrector
pathname = 'https://archive.stsci.edu/pub/k2/eng/long_cadence/kplr060021426-2014044044430_lpd-targ.fits' tpf = KeplerTargetPixelFile(pathname)
We saved the mask for this target in our previous notebook, so we can just load it directly.
VDB_J_mask = np.load('VDB_J_2014_mask.npy')
ax = tpf.plot(aperture_mask=tpf.pipeline_mask, mask_color='b', frame=300, scale='linear', cmap='gray',show_colorbar=False) tpf.plot(aperture_mask=VDB_J_mask, frame=300, scale='linear', cmap='gray', ax=ax, mask_color='pink');
The Vanderburg and Johnson mask is slightly bigger than the Kepler pipeline mask.
From the paper: > We exclude data from the first 2.5 days of the Two-Wheel Concept Engineering Test
We also exclude points labeled by the Kepler pipeline as having poor quality, where the QUALITY tag of the Kepler FITS file data structure was not 0.
We identify the points during which Kepler’s thrusters were firing through analysis of the image centroids. […] We identify the points during which the spacecraft fires its thrusters as 5–σ outliers from the distribution of ds/dt points and exclude them from further calculations.
Thruster firings are automatically flagged in most K2 campaigns, and the exceptions are getting fixed with data reprocessing, so we will not replicate the thruster firing analysis.
lc_raw = tpf.to_lightcurve(aperture_mask=VDB_J_mask)
Exlude the first 2.5 days and non-zero quality flags, following Vanderburg & Johnson.
first_2p5_days = lc_raw.time - lc_raw.time < 2.5 nonzero_quality_flags = lc_raw.quality != 0 keep_indices = ~first_2p5_days & ~nonzero_quality_flags
lightkurvesupports indexing, slicing, and boolean masking just like
lc_trim = lc_raw[keep_indices] lc = lc_trim.normalize()
Instantiate and apply the SFF corrector.
sff = SFFCorrector()
lc_corrected = sff.correct(lc.time, lc.flux, lc.centroid_col, lc.centroid_row, niters=1, windows=1, polyorder=5)
100%|██████████| 1/1 [00:00<00:00, 14.99it/s]
lightkurvereleases may return the trend by default.
long_term_trend = sff.trend
plt.figure(figsize=(10,6)) dy = 0.004 plt.plot(lc.time, lc.flux + dy, 'ko', ms=4) plt.plot(lc.time, lc.flux+dy, 'o', color='#3498db', ms=3) plt.plot(lc_corrected.time, lc_corrected.flux * long_term_trend, 'o', color='pink', ms = 3) plt.xlabel('BJD - 2454833') plt.ylabel('Relative Brightness') plt.xlim(1862, 1870) plt.ylim(0.994, 1.008);
Neat! The raw flux slope looks steeper than the publication figure, perhaps owing to different choices in aperture mask, background subtraction, or other subtle differences. But overall the corrected flux looks very similar to the result obtained in Figure 5.
You can look at other diagnostics of the SFF correction with some convenience functions.
<matplotlib.axes._subplots.AxesSubplot at 0xa24f479e8>