Aperture Photometry

Understanding aperture photometry & making custom apertures.

Learning goals

In our previous tutorials (LightCurve object and LightCurveFile object) we learned about aperture photometry and the Simple Aperture Photometry (SAP) and Pre-search Data Conditioning SAP (PDCSAP) flux.

We have not however discussed how these apertures are chosen by the pipeline or how to examine them.

In this proposal we will cover the following, - How apertures are defined. - How can we examine a pre-defined aperture. - How we can define and modify an aperture and recover the light curve.

SPOC apertures

In aperture photometry A set of pixels in the image are chosen and we sum those to produce a single flux value. The SPOC produces an optimal aperture, which is used by default in Lightkurve, and determined by the data processing pipeline. This is the default aperture used by Lightkurve and is optimized to ensure that the stellar signal has a high signal to noise ratio, with minimal contamination from the background.

We sum these same pre-selected pixels for every image at each cadence to produce a light curve.

There are however, some cases where you might want to produce your own aperture. The field may be crowded, or you may wish to change the aperture size to change the relative contribution of the background. Lightkurve offers tools to select pixels programmatically.

We will show you how to examine the pre-selected aperture and how to modify it if you wish.


This tutorial requires: - Lightkurve - Matplotlib - numpy

Defining terms

  • Target Pixel File (TPF): A file containing the original CCD pixel observations from which light curves are extracted.
  • LightCurve Object: Obtained from a TPF and contains light curve information derived using simple aperture photometry.
  • LightCurveFile Object: Obtained from MAST and contains both SAP flux and PSDCSAP flux.
  • Cadence: The rate at which TESS photometric observations are stored.
  • Sector: One of TESS’s 27 (to date) observing periods, approximately ~27 days in duration.
  • Simple Aperture Photometry (SAP): The act of summing all pixel values in a pre-defined aperture as a function of time.
  • Pre-search Data Conditioning SAP flux (PDCSAP) flux : SAP flux from which long term trends have been removed using so-called Co-trending Basis Vectors (CBVs). PDCSAP flux is usually cleaner data than the SAP flux and will have fewer systematic trends.
%matplotlib inline
import numpy as np
import lightkurve as lk
import matplotlib.pyplot as plt

Downloading the data

For this tutorial lets use the L 98-59 System again, focusing on planet c. First let’s search for a TPF for this object.

search_result = lk.search_targetpixelfile('TIC 307210830')
SearchResult containing 7 data products.
0TESS Sector 2SPOC307210830tess2018234235059-s0002-0000000307210830-0121-s_tp.fits0.0
1TESS Sector 5SPOC307210830tess2018319095959-s0005-0000000307210830-0125-s_tp.fits0.0
2TESS Sector 8SPOC307210830tess2019032160000-s0008-0000000307210830-0136-s_tp.fits0.0
3TESS Sector 9SPOC307210830tess2019058134432-s0009-0000000307210830-0139-s_tp.fits0.0
4TESS Sector 10SPOC307210830tess2019085135100-s0010-0000000307210830-0140-s_tp.fits0.0
5TESS Sector 11SPOC307210830tess2019112060037-s0011-0000000307210830-0143-s_tp.fits0.0
6TESS Sector 12SPOC307210830tess2019140104343-s0012-0000000307210830-0144-s_tp.fits0.0

Lets pick and download the data for sector 2.

tpf_file = search_result[0].download()
TessTargetPixelFile(TICID: 307210830)

We now have a TPF file for our object in sector 2. The optimal aperture is stored in the TPF as the pipeline_mask property. We can have a look at it by calling it here:

array([[False, False, False, False, False, False, False, False, False,
        False, False],
       [False, False, False, False, False, False, False, False, False,
        False, False],
       [False, False, False, False, False, False, False, False, False,
        False, False],
       [False, False, False, False, False, False, False, False, False,
        False, False],
       [False, False, False, False, False, False, False, False, False,
        False, False],
       [False, False, False, False,  True,  True,  True, False, False,
        False, False],
       [False, False, False, False,  True,  True,  True,  True, False,
        False, False],
       [False, False, False, False,  True,  True,  True,  True, False,
        False, False],
       [False, False, False, False, False,  True,  True, False, False,
        False, False],
       [False, False, False, False, False, False, False, False, False,
        False, False],
       [False, False, False, False, False, False, False, False, False,
        False, False]])

As you can see, it is a boolean array detailing which pixels are included. We can plot this aperture over the top of our TPF using the plot() function, and passing in the mask to the aperture_mask keyword.


We now see the SPOC optimal aperture mask overlaid on top of our object of interest.

Using the provided optimal aperture in pipeline_mask and the TPF we can perform simple aperture photometry via the extract_aperture_photometry function as shown below,

lc = tpf_file.extract_aperture_photometry()
TessLightCurve targetid=307210830 length=18317
electron / selectron / spixpix

The same result can also be obtained via,

lc = tpf_file.to_lightcurve(aperture_mask=tpf_file.pipeline_mask)

Creating your own masks

You don’t necessarily have to pass in the pipeline_mask to the plot() function, it can be any mask you choose yourself, provided it is the right shape. We will now explain how to adjust this mask using the create_threshold_mask function. This method will identify the pixels in the TPF which show a median flux that is brighter than threshold times the standard deviation above the overall median. The standard deviation is estimated in a robust way by multiplying the Median Absolute Deviation (MAD) with 1.4826. In this example we will pick 10 as our threshold.

target_mask = tpf_file.create_threshold_mask(threshold=10, reference_pixel='center')
n_target_pixels = target_mask.sum()

We have now created a target mask which covers 13 pixels. Lets plot this up and see what it looks like.

tpf_file.plot(aperture_mask=target_mask, mask_color='r');

We see that this is slightly different to the optimal aperture previously defined. It also looks like there might be too many background pixels included. Lets see if we can adjust this.

Specify an aperture array

We need to define a new aperture array such that our aperture will cover our object of interest only. We have seen that apertures are defined within boolean arrays, based on this lets make up a new array.

aper_new = np.zeros(tpf_file.shape[1:], dtype=bool)
aper_new[5:8, 4:7] = True
tpf_file.plot(aperture_mask=aper_new, mask_color='red')
<matplotlib.axes._subplots.AxesSubplot at 0x7fa1790b85c0>

OK great, it looks like we have covered our object,but not included too much background. Lets now make this into a light curve.

target_lc_new = tpf_file.to_lightcurve(aperture_mask=aper_new)
TessLightCurve targetid=307210830 length=18317
electron / selectron / spixpix

Compare data & light curves

We have now created light curve objects using both the SPOC pre-defined aperture and a mask of our own devising. Lets plot these light curves up and examine the difference.


As you can see the light curves from the two apertures look very different. It looks as if the aperture we have defined manually may have less background or contaminating flux from scattered than the SPOC aperture. We will learn more about contamination in our next tutorial.