Source code for lightkurve.io.eleanor

"""Reader for GSFC-ELEANOR-LITE light curve files.
Details can be found at https://archive.stsci.edu/hlsp/eleanor and https://archive.stsci.edu/hlsp/gsfc-eleanor-lite
"""
from ..lightcurve import TessLightCurve
from ..utils import TessQualityFlags
from astropy import units as u

from .generic import read_generic_lightcurve

import numpy as np

[docs]def read_eleanor_lightcurve(filename, flux_column="CORR_FLUX", quality_bitmask="default" ): """Returns a `~lightkurve.lightcurve.LightCurve` object given a light curve file from eleanor package or GSFC-ELEANOR-LITE Pipeline. By default, eleanor's `CORR_FLUX` column is used to populate the `flux` values. Note that the "FLUX_ERR" column in the Eleanor FITS file is referred to the uncertainty of "RAW_FLUX", not "CORR_FLUX". Thus the uncertainty reported in the 'flux_err' column here is calculated as follows: corr_flux_err = corr_flux*raw_flux_err/raw_flux. For completeness, the original raw_flux's error is added as a "raw_flux_err" column. In terms of quality flags, eleanor uses the TESS SPOC quality flags by identifying short-cadence targets that fall on each camera-CCD pairing for a given sector. However, eleanor, also adds two new quality flags -- bit 17 (decimal value 131072)) and bit 18 (decimal value 262144). More information on eleanor: https://github.com/afeinstein20/eleanor More information on GSFC-ELEANOR-LITE Pipeline: https://archive.stsci.edu/hlsp/gsfc-eleanor-lite Parameters ---------- filename : str Local path or remote url of a GSFC-ELEANOR-LITE light curve FITS file. flux_column : 'RAW_FLUX', 'CORR_FLUX', 'PCA_FLUX', or 'FLUX_BKG' Which column in the FITS file contains the preferred flux data? By default the "Corrected Flux" flux (CORR_FLUX) is used. quality_bitmask : str or int Bitmask (integer) which identifies the quality flag bitmask that should be used to mask out bad cadences. If a string is passed, it has the following meaning: * "none": no cadences will be ignored (`quality_bitmask=0`). * "default": cadences with flags indicating AttitudeTweak, SafeMode, CoarsePoint, EarthPoint, Desat, or ManualExclude will be ignored. * "hard": cadences with default flags, ApertureCosmic, CollateralCosmic, Straylight, or Straylight2 will be ignored. * "hardest": cadences with all the above flags will be ignored, in addition to cadences with GSFC-ELEANOR-LITE bit flags of 17 (decimal value 131072) and 18 (decimal value 262144). """ lc = read_generic_lightcurve( filename, time_column="TIME".lower(), flux_column=flux_column.lower(), flux_err_column = "FLUX_ERR".lower(), time_format="btjd", quality_column= "QUALITY".lower(), centroid_col_column = "X_CENTROID".lower(), centroid_row_column = "Y_CENTROID".lower(), cadenceno_column = "FFIINDEX".lower() ) if quality_bitmask == "hardest": # Eleanor has 2 additional bits on top of the 16 TESS SPOC bits # they are excluded when hardest is specified. quality_bitmask = TessQualityFlags.HARDEST_BITMASK | 2** 17 | 2**18 quality_mask = TessQualityFlags.create_quality_mask( quality_array=lc["quality"], bitmask=quality_bitmask ) lc = lc[quality_mask] # Eleanor FITS file do not have units specified. re-add them. for colname in ["flux", "flux_err", "raw_flux", "corr_flux", "pca_flux", "psf_flux"]: if colname in lc.colnames: if lc[colname].unit is not None: # for case flux, flux_err, lightkurve has forced it to be u.dimensionless_unscaled # can't reset a unit, so we create a new column lc[colname] = u.Quantity(lc[colname].value, "electron/s") else: lc[colname].unit = "electron/s" for colname in ["flux_bkg"]: if colname in lc.colnames: lc[colname].unit = u.percent for colname in ["centroid_col", "centroid_row", "x_centroid", "y_centroid", "x_com", "y_com"]: if colname in lc.colnames: lc[colname].unit = u.pix for colname in ["barycorr"]: if colname in lc.colnames: lc[colname].unit = u.day # In Eleanor fits file, raw_flux's error is in flux_err, which breaks Lightkurve convention. # To account for this, the corr_flux error is calculated from corr_flux_err = corr_flux*raw_flux_err/raw_flux. For completeness, # the original raw_flux's error is added as a "raw_flux_err" column lc["raw_flux_err"] = lc["flux_err"] if flux_column.lower() != 'raw_flux': lc["flux_err"] = lc[flux_column.lower()]*lc["raw_flux_err"]/lc["raw_flux"] # vanilla eleanor has cadence saved as float, # convert to int to ensure we stick with the convention for colname in ["ffiindex", "cadenceno"]: if colname in lc.colnames: if not np.issubdtype(lc[colname].dtype, np.int_): lc[colname] = np.asarray(lc[colname].value, dtype=int) if ( lc.meta.get("TVERSION") is not None and lc.meta.get("GITHUB") == "https://github.com/afeinstein20/eleanor" ): # the above headers are GSFC-ELEANOR-LITE-specific, and are not present in vanilla eleanor # cf. https://github.com/afeinstein20/eleanor/blob/main/eleanor/targetdata.py lc.meta["AUTHOR"] = "GSFC-ELEANOR-LITE" else: lc.meta["AUTHOR"] = "ELEANOR" # Eleanor light curves are not normalized by default lc.meta["NORMALIZED"] = False tic = lc.meta.get("TIC_ID") if tic is not None: # compatibility with SPOC, QLP, etc. lc.meta["TARGETID"] = tic lc.meta["TICID"] = tic lc.meta["OBJECT"] = f"TIC {tic}" # for Lightkurve's plotting methods lc.meta["LABEL"] = f"TIC {tic}" return TessLightCurve(data=lc)