Quickstart Tutorial

1.1 Fast Light Curves

As a simple first example, we will use \(\texttt{eleanor}\) to create a target pixel file (TPF) and light curve for a given TIC target.

[1]:
from IPython.display import Image
[2]:
import eleanor
import numpy as np
import matplotlib.pyplot as plt

First, we will load the data for TIC 38846515 (WASP-100), a relatively bright star observed in Sector 1. \(\texttt{eleanor}\) is able to extract a light curve easily and automatically for this unblended object. Calling source will assign a \(\textit{Gaia}\) ID, TESS magnitude, sector, camera, ccd, and associated postcard.

[3]:
star = eleanor.Source(tic=38846515, sector=1)

We can also pass through a Gaia DR2 ID or RA/Dec pair, either as a tuple or an Astropy SkyCoord object. For example, the following three calls all point to the same target:

[4]:
star = eleanor.Source(tic=38846515, sector=1)

print('Found TIC {0} (Gaia {1}), with TESS magnitude {2}, RA {3}, and Dec {4}'
     .format(star.tic, star.gaia, star.tess_mag, star.coords[0], star.coords[1]))

star = eleanor.Source(coords=(68.959732, -64.02704), sector=1)

print('Found TIC {0} (Gaia {1}), with TESS magnitude {2}, RA {3}, and Dec {4}'
     .format(star.tic, star.gaia, star.tess_mag, star.coords[0], star.coords[1]))

star = eleanor.Source(gaia=4675352109658261376, sector=1)

print('Found TIC {0} (Gaia {1}), with TESS magnitude {2}, RA {3}, and Dec {4}'
     .format(star.tic, star.gaia, star.tess_mag, star.coords[0], star.coords[1]))
Found TIC 38846515 (Gaia 4675352109658261376), with TESS magnitude 10.307, RA 68.959732, and Dec -64.02704
Found TIC 38846515 (Gaia 4675352109658261376), with TESS magnitude 10.307, RA 68.959732, and Dec -64.02704
Created TAP+ (v1.0.1) - Connection:
        Host: gea.esac.esa.int
        Use HTTPS: False
        Port: 80
        SSL Port: 443
Found TIC 38846515 (Gaia 4675352109658261376), with TESS magnitude 10.307, RA 68.95981586357303, and Dec -64.02703903114245

Gaia has quite a bit of precision on the star’s position! Now that we have our Source information, we simply call the TargetData() function, which will extract a target pixel file, perform aperture photometry with an automatically optimized aperture choice, and complete some simple systematics corrections.

[5]:
data = eleanor.TargetData(star, height=15, width=15, bkg_size=31, do_psf=True, do_pca=True)

/Users/ozymandias1/anaconda2/envs/python3/lib/python3.5/site-packages/scipy/signal/_savitzky_golay.py:135: RuntimeWarning: internal gelsd driver lwork query error, required iwork dimension not returned. This is likely the result of LAPACK bug 0038, fixed in LAPACK 3.2.2 (released July 21, 2010). Falling back to 'gelss' driver.
  coeffs, _, _, _ = lstsq(A, y)
/Users/ozymandias1/anaconda2/envs/python3/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: compiletime version 3.6 of module 'tensorflow.python.framework.fast_tensor_util' does not match runtime version 3.5
  return f(*args, **kwds)
100%|██████████| 1282/1282 [00:14<00:00, 86.22it/s]

\(\texttt{eleanor}\) may download a file here. Don’t be afraid of this download. We have created an intermediate step between FFIs and TPFs called \(\textbf{postcards}\). In order to create a TPF, \(\texttt{eleanor}\) downloads the postcard your source falls on. We’ll talk through the flags you can set, but let’s look at a light curve first.

[6]:
q = data.quality == 0

plt.plot(data.time[q], data.raw_flux[q]/np.median(data.raw_flux[q])-0.01, 'k')
plt.plot(data.time[q], data.corr_flux[q]/np.median(data.corr_flux[q]) + 0.01, 'r')
plt.plot(data.time[q], data.pca_flux[q]/np.median(data.pca_flux[q]) + 0.03, 'y')
plt.plot(data.time[q], data.psf_flux[q]/np.median(data.psf_flux[q]) + 0.05, 'b')

plt.ylabel('Normalized Flux')
plt.xlabel('Time')
[6]:
Text(0.5,0,'Time')
../_images/getting_started_tutorial_12_1.png

There’s a planet there! What does our aperture look like?

[7]:
plt.imshow(data.aperture)
[7]:
<matplotlib.image.AxesImage at 0x119189860>
../_images/getting_started_tutorial_14_1.png

Let’s save these data to a FITS file so we have them later. By default, this will be saved to a ~/.eleanor directory, but that can be changed by setting a directory.

[8]:
data.save()
WARNING: VerifyWarning: Card is too long, comment will be truncated. [astropy.io.fits.card]

1.2 Custom Apertures

That was easy! But what if you’re not satisfied with \(\texttt{eleanor}\)’s default choice of aperture? Well, we provide you with two ways to create your own aperture.

  1. \(\texttt{eleanor}\) can help you create your own mask. By calling custom_aperture, you can choose from a circular or rectangular aperture. You can also choose the size (radius or length x width) and the pixel the aperture is centered on. The aperture will only be created on pixels within the TPF (it won’t spill over to other pixels)
[9]:
eleanor.TargetData.custom_aperture(data, shape='circle', r=1)
eleanor.TargetData.get_lightcurve(data)
  1. You can pass in your own mask. Create a 2D array of the same shape as your TPF and pass in the aperture using the following command
[10]:
mask = np.zeros(np.shape(data.tpf[0]))
mask[6:8,6:8] = 1
plt.imshow(mask, origin='lower')
data.get_lightcurve(aperture=mask)
../_images/getting_started_tutorial_21_0.png
[11]:
plt.plot(data.time[q], data.raw_flux[q], '.')

plt.ylabel('Flux')
plt.xlabel('Time')

plt.show()
../_images/getting_started_tutorial_22_0.png

1.2.1 Ultra-Custom Apertures: Click the pixels you want!

We have created a user-friendly method to create your own aperture by selecting the pixels you wish to be included in the photometry. Here’s how you would go about doing so:

vis = eleanor.Visualize(target) cust_lc = vis.click_aperture()
[12]:
Image(url='customApExample.gif')
[12]:

Currently, this feature only works when called from the terminal. We are working towards creating an option to embed this feature in a Jupyter Notebook… So stay tuned!

1.3 Systematics Corrections

When we called eleanor.TargetData() in 1.1, some simple systematics corrections were automatically performed on the light curve. Let’s apply those explicitly to the newly created raw light curve from the custom aperture.

[13]:
corr_flux = eleanor.TargetData.jitter_corr(data, flux=data.raw_flux)
eleanor.__path__
[13]:
['/Users/ozymandias1/research/tess/eleanor/eleanor']
[14]:
plt.plot(data.time[q], corr_flux[q], 'k.')

plt.ylabel('Flux')
plt.xlabel('Time')
[14]:
Text(0.5,0,'Time')
../_images/getting_started_tutorial_31_1.png

We can then run pca with this flux time series to remove any shared systematics with nearby stars.

[15]:
eleanor.TargetData.pca(data, flux=corr_flux, modes=4)
[16]:
plt.plot(data.time[q], data.pca_flux[q], 'k.')
plt.ylabel('Flux')
plt.xlabel('Time')
[16]:
Text(0.5,0,'Time')
../_images/getting_started_tutorial_34_1.png

PSF modeling is always an option too!

[17]:
eleanor.TargetData.psf_lightcurve(data, model='gaussian', likelihood='poisson')
plt.plot(data.time[q], data.psf_flux[q], 'k.')
plt.ylabel('Flux')
plt.xlabel('Time')
100%|██████████| 1282/1282 [00:15<00:00, 80.33it/s]
[17]:
Text(0.5,0,'Time')
../_images/getting_started_tutorial_36_2.png

1.4 Stars Observed in Multiple Sectors

\(\texttt{eleanor}\) has some built-in tools to make it easier to work with stars that are observed in multiple TESS sectors. Let’s consider WASP-100 again, which was observed in both Sectors 1 and 2. When we previously called eleanor.Source(), we can instead call eleanor.multi_sectors(), which will make a list of Source objects for all sectors requested.

[19]:
star = eleanor.multi_sectors(tic=38846515, sectors=[1,2])
[20]:
print(star)
[<eleanor.source.Source object at 0x11c1774e0>, <eleanor.source.Source object at 0x11c1bfb00>]

Yep, it’s a list of objects! We can then call eleanor.TargetData() on each.

[21]:
data0 = eleanor.TargetData(star[0], height=15, width=15, bkg_size=31, do_psf=True, do_pca=False)
data1 = eleanor.TargetData(star[1], height=15, width=15, bkg_size=31, do_psf=True, do_pca=False)

q0 = data0.quality == 0
q1 = data1.quality == 0

plt.plot(data0.time[q0], data0.psf_flux[q0]/np.median(data0.psf_flux[q0]) + 0.05, 'k.')
plt.plot(data1.time[q1], data1.psf_flux[q1]/np.median(data1.psf_flux[q1]) + 0.04, 'r.')

plt.ylabel('Normalized Flux')
plt.xlabel('Time')

plt.show()
100%|██████████| 1282/1282 [00:14<00:00, 85.56it/s]
100%|██████████| 1245/1245 [00:14<00:00, 84.30it/s]
../_images/getting_started_tutorial_42_1.png

Presently, \(\texttt{eleanor}\) will only work with data from Sectors 1 and 2; future releases will handle additional sectors.

If you are only interested in one Sector your star was observed in, you can call eleanor.Source(sector=1) and specify the Sector you are interested in. If your star was observed in multiple sectors and you call eleanor.Source(), it will return the light curve from the most recent Sector the star was observed in.

1.5 Good practices

We’re still exploring what the best practices are generally. Good practices seem to differ across the detector, but here’s what we believe so far. If you discover anything that works well for you, we and other \(\texttt{eleanor}\) users would surely love to know them!

Good background subtraction is very important. The size of the region to use for an “ideal” background changes across the detector. Generally, bigger is better, we typically recommend using a region larger than the standard TPF. Currently, the background used must be a rectangle centered on the star, with size bkg_size

PSF modeling (do_psf=True) seems to work very well for relatively bright, isolated stars. Presently the only PSF model is a Gaussian, but both Gaussian and Poisson likelihood functions are possible. Do note that this requires tensorflow, and there is not presently a tensorflow package for Python 3.7. This will thus only work for python 3.0 - 3.6. Note that PSF modeling is very much in beta and our current implementation has known issues for very faint stars (fainter than I ~ 15, generally).

If you find anything that works well for your science, or uncover any issues, please let us know! Github issues or pull requests are welcomed.