from IPython.display import Image
import warnings
warnings.filterwarnings('ignore')
import eleanor
import numpy as np
from astropy import units as u
import matplotlib.pyplot as plt
from astropy.coordinates import SkyCoord
To update eleanor
to work with newly digested sectors on MAST (Mikulski Archive for Space Telescopes), one does not need to update the eleanor
version, but rather we have everything you need set-up in eleanor.Update()
.
This call will download a target in the CVZ of either the northern or southern ecliptic hemisphere to create quality flags for all targets in this sector. This will also download the co-trending basis vectors (CBVs) used to best detrend systematics from our light curves. All of this data is stored in a hidden local directory: ~/.eleanor/metadata/sNNNN
, where NNNN
corresponds to the sector.
This shouldn't take long, but the exact time will depend on the strength of your internet connection.
eleanor.Update(sector=27)
Downloading URL https://mast.stsci.edu/tesscut/api/v0.1/astrocut?ra=68.95970833333332&dec=-64.02703611111112&y=31&x=31&units=px§or=27 to ./tesscut_20201006093809.zip ... [Done] Inflating... This is the first light curve you have made for this sector. Getting eleanor metadata products for Sector 27... This will only take a minute, and only needs to be done once. Any other light curves you make in this sector will be faster. Target Acquired Cadences Calculated Quality Flags Assured CBVs Made Success! Sector 27 now available.
<eleanor.update.Update at 0x12613ad68>
If you are having trouble creating a light curve later down the line, it may be worth clearing this directory and trying to redownload all of the files.
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.
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}$ DR2 ID, TESS magnitude, sector, camera, ccd, and associated postcard.
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]))
INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_bkg.fits with expected size 78955200. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc.fits with expected size 158022720. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1_tess_v2_pm.txt with expected size 237847. [astroquery.query] Found TIC 38846515 (Gaia 4675352109658261376), with TESS magnitude 10.3157, RA 68.9597092399964, and Dec -64.0270368810381
Here, the software is connecting to the MAST servers to download an $\texttt{eleanor}$ postcard file, postcard background file, and the pointing model for that sector-camera-CCD. A postcard is a 104 $\times$ 148 pixel cutout region of the entire FFI. The postcard background file is a 2D-interpolated background model across the postcard. The pointing model is an additional file created that performs an affine transformation on top of the WCS to ensure the most accurate pixel location of your target is.
If you do not know what sector your target was observed in, calling eleanor.Source()
without a sector keyword passed through explicitly will return the most recent sector for which the star was observed. If you think your target may have been observed in multiple sectors, you may want to consider eleanor.multi_sectors()
, as described below.
In addition to passing in a TIC ID, we can also pass through a Simbad-resolvable name, a Gaia DR2 ID, or an RA/Dec pair, either as a tuple or an Astropy SkyCoord object. For example, the following three calls all point to the same target:
star = eleanor.Source(name='WASP-100', 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]))
coords = (68.959732, -64.02704)
# or
coords = SkyCoord(ra=68.959732, dec=-64.02704, unit=(u.deg, u.deg))
star = eleanor.Source(coords=coords, 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]))
INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_bkg.fits with expected size 78955200. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc.fits with expected size 158022720. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1_tess_v2_pm.txt with expected size 237847. [astroquery.query] Found TIC 38846515 (Gaia 4675352109658261376), with TESS magnitude 10.3157, RA 68.95970916666666, and Dec -64.02703666666666 INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_bkg.fits with expected size 78955200. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc.fits with expected size 158022720. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1_tess_v2_pm.txt with expected size 237847. [astroquery.query] Found TIC 38846515 (Gaia 4675352109658261376), with TESS magnitude 10.3157, RA 68.959732, and Dec -64.02704 Created TAP+ (v1.2.1) - Connection: Host: gea.esac.esa.int Use HTTPS: True Port: 443 SSL Port: 443 Created TAP+ (v1.2.1) - Connection: Host: geadata.esac.esa.int Use HTTPS: True Port: 443 SSL Port: 443 INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_bkg.fits with expected size 78955200. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc.fits with expected size 158022720. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1_tess_v2_pm.txt with expected size 237847. [astroquery.query] Found TIC 38846515 (Gaia 4675352109658261376), with TESS magnitude 10.3157, 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 eleanor.TargetData()
function, which will extract a target pixel file from the postcard, perform aperture photometry, and complete some simple systematics corrections. This function chooses an aperture which optimizes the light curve for transit searches.
We can also set some operations when calling this function. For example, do_pca = True
tells $\texttt{eleanor}$ to use the cotrending basis vectors on a background subtracted light curve without any additional correction. And do_psf = True
creates a point spread function modeled light curve of our target.
We can also pass through a regressors
argument that is either a list of arrays of length time or 'corner'
. These will be passed in as other terms to regress against in the detrending. If 'corner'
is set, it will use the four pixels in the corners of the TPF to infer the background. regressors
is an optional argument: if it is not set, no additional regressors will be used. This is shown in more detail in the tips, tricks, and hacks notebook.
In addition to automatically choosing an aperture, eleanor.TargetData()
also tries a few different background subtractions to remove as much background noise as possible. The three options it tries are:
1D postcard background : A constant ($3\mu + 2med$) is calculated from each postcard frame
1D TPF background : A constant ($3\mu + 2med$) is calculated from each TPF frame
2D background : The 2D background pixels are subtracted from the TPF
For both 1D options, stars are masked before estimating the background value.
data = eleanor.TargetData(star, height=15, width=15, bkg_size=31, do_psf=False, do_pca=True, regressors='corner')
WARNING: Logging before flag parsing goes to stderr. W1006 09:40:37.417151 4633564608 module_wrapper.py:139] From //anaconda3/lib/python3.7/site-packages/eleanor/targetdata.py:841: The name tf.logging.set_verbosity is deprecated. Please use tf.compat.v1.logging.set_verbosity instead. W1006 09:40:37.417876 4633564608 module_wrapper.py:139] From //anaconda3/lib/python3.7/site-packages/eleanor/targetdata.py:841: The name tf.logging.ERROR is deprecated. Please use tf.compat.v1.logging.ERROR instead. 100%|██████████| 1282/1282 [00:11<00:00, 112.48it/s]
Let's look at our new light curves!
Plotted below are the following:
Before plotting, we can use quality flags to mask poor quality data. Our quality flags are taken from the two-minute $\textit{TESS}$ light curves and binned to 30-minutes. We are very generous with our masking, so any flag that applies to the entire FFI is marked in data.quality
. We also introduce our own quality flag for when the pointing model significantly deviates from a best-fit line in the sector (see Figure 2 in Feinstein et al. 2019).
plt.figure(figsize=(15,5))
q = data.quality == 0
plt.plot(data.time[q], data.raw_flux[q]/np.nanmedian(data.raw_flux[q])+0.06, 'k')
plt.plot(data.time[q], data.corr_flux[q]/np.nanmedian(data.corr_flux[q]) + 0.03, 'r')
plt.plot(data.time[q], data.pca_flux[q]/np.nanmedian(data.pca_flux[q]), 'g')
#plt.plot(data.time[q], data.psf_flux[q]/np.nanmedian(data.psf_flux[q]) - 0.02, 'b')
plt.ylabel('Normalized Flux')
plt.xlabel('Time [BJD - 2457000]')
plt.title('WASP-100');
There's a planet there!
For this star, we found the postcard level 1D background did a good job at removing additional noise in the data. We can check which background model was used by calling:
data.bkg_type
'2D_BKG_MODEL'
We can even plot the background as a function of time to see what was removed from our light curve. All three background models are saved and can be called by the following:
1D postcard background : data.bkg_type = 'PC_LEVEL' : keyword = data.flux_bkg
1D TPF background : data.bkg_type = 'TPF_LEVEL' : keyword = data.tpf_flux_bkg
2D TPF backround : data.bkg_type = 'TPF_2D_LEVEL' : keyword = data.bkg_tpf
plt.figure(figsize=(15,5))
plt.plot(data.time, data.flux_bkg, 'k', label='1D postcard', linewidth=3)
plt.plot(data.time, data.tpf_flux_bkg, 'r--', label='1D TPF', linewidth=2)
plt.ylabel('Normalized Flux')
plt.xlabel('Time [BJD - 2457000]')
plt.legend();
And to see what a frame of the 2D background looks like, we can plot it as
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10,4))
ax1.imshow(data.tpf[0])
ax1.set_title('Target Pixel File')
ax2.imshow(data.bkg_tpf[0])
ax2.set_title('2D interpolated background');
What does our automatically chosen aperture look like? And how does it compare to where the star falls on the TPF?
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10,4))
ax1.imshow(data.tpf[0])
ax1.set_title('Target Pixel File')
ax2.imshow(data.aperture)
ax2.set_title('Aperture');
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
.
data.save()
With one line of code, we can pass this through as a lightkurve object and begin using the functionality of that package.
lk = data.to_lightkurve()
lk.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x15fbe25c0>
$\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.
star = eleanor.multi_sectors(tic=38846515, sectors=[1,2])
I1006 09:40:53.029156 4633564608 query.py:325] Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_bkg.fits with expected size 78955200. I1006 09:40:53.230607 4633564608 query.py:325] Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc.fits with expected size 158022720.
INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_bkg.fits with expected size 78955200. [astroquery.query] INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc.fits with expected size 158022720. [astroquery.query]
I1006 09:40:53.416737 4633564608 query.py:325] Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1_tess_v2_pm.txt with expected size 237847.
INFO: Found cached file /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0001-4-1-cal-0902-1078_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0001-4-1_tess_v2_pm.txt with expected size 237847. [astroquery.query] Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:HLSP/eleanor/postcards/s0002/4-1/hlsp_eleanor_tess_ffi_postcard-s0002-4-1-cal-1490-0646_tess_v2_bkg.fits to /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0002-4-1-cal-1490-0646_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0002-4-1-cal-1490-0646_tess_v2_bkg.fits ... [Done] Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:HLSP/eleanor/postcards/s0002/4-1/hlsp_eleanor_tess_ffi_postcard-s0002-4-1-cal-1490-0646_tess_v2_pc.fits to /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0002-4-1-cal-1490-0646_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0002-4-1-cal-1490-0646_tess_v2_pc.fits ... [Done] Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:HLSP/eleanor/postcards/s0002/4-1/hlsp_eleanor_tess_ffi_postcard-s0002-4-1_tess_v2_pm.txt to /Users/arcticfox/.eleanor/mastDownload/HLSP/hlsp_eleanor_tess_ffi_postcard-s0002-4-1-cal-1490-0646_tess_v2_pc/hlsp_eleanor_tess_ffi_postcard-s0002-4-1_tess_v2_pm.txt ... [Done]
In this case, I only wanted sectors 1 and 2. However, I could have passed through sectors='all'
to get all sectors in which this star was observed.
print(star)
[<eleanor.source.Source object at 0x16082cd68>, <eleanor.source.Source object at 0x127af8ba8>]
Yep, it's a list of objects!
We can then call eleanor.TargetData()
on each.
plt.figure(figsize=(15,5))
data = []
plot_fmt = ['k.', 'r.']
for s in star:
datum = eleanor.TargetData(s, height=15, width=15, bkg_size=31, do_psf=False, do_pca=False)
data.append(datum)
for sector, datum in enumerate(data):
q = datum.quality == 0
plt.plot(datum.time[q], datum.corr_flux[q]/np.median(datum.corr_flux[q]), plot_fmt[sector])
plt.ylabel('Normalized Flux', fontsize=24)
plt.xlabel('Time', fontsize=24)
plt.show()
Loading file hlsp_eleanor_tess_ffi_tic38846515_s01_tess_v2.0.0rc2_lc.fits found on disk
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.
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! You can also find some tips, tricks, and hacks in the next example notebook.
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 models usable are Gaussian and Moffat profiles. Both Gaussian and Poisson likelihood functions are possible as well. Do note that this requires tensorflow<2.0. 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.