def make_custom_lc( self, sector=None, sap_mask=None, aper_radius=None, percentile=None, threshold_sigma=None, use_pld=True, pixel_components=3, spline_n_knots=100, spline_degree=3, background_mask=None, pca_nterms=5, with_offset=True, ): """ create a custom lightcurve with background subtraction, based on this tutorial: https://docs.lightkurve.org/tutorials/04-how-to-remove-tess-scattered-light-using-regressioncorrector.html Parameters ---------- sector : int or str specific sector or all aper_radius: int aperture mask radius percentile: float aperture mask percentile threshold_sigma: float aperture mask threshold [sigma] pca_nterms : int number of pca terms to use Returns ------- corrected_lc : lightkurve object """ if self.verbose: print("Using lightcurve with custom aperture.") sector = sector if sector is not None else self.sector sap_mask = sap_mask if sap_mask else self.sap_mask aper_radius = aper_radius if aper_radius else self.aper_radius percentile = percentile if percentile else self.percentile threshold_sigma = (threshold_sigma if threshold_sigma else self.threshold_sigma) if self.tpf is None: tpf, tpf_info = self.get_tpf(sector=sector, return_df=True) else: if self.tpf.sector == sector: tpf = self.tpf else: tpf, tpf_info = self.get_tpf(sector=sector, return_df=True) # Make an aperture mask and a raw light curve self.aper_mask = parse_aperture_mask( tpf, sap_mask=sap_mask, aper_radius=aper_radius, percentile=percentile, threshold_sigma=threshold_sigma, verbose=False, ) raw_lc = tpf.to_lightcurve(method="aperture", aperture_mask=self.aper_mask) # remove nans idx = (np.isnan(raw_lc.time) | np.isnan(raw_lc.flux) | np.isnan(raw_lc.flux_err)) self.tpf = tpf[~idx] self.raw_lc = raw_lc[~idx] if use_pld: if self.verbose: print("Removing scattered light + applying PLD") pld = lk.TessPLDCorrector(self.tpf, aperture_mask=self.aper_mask) if background_mask is None: background_mask = ~self.aper_mask corrected_lc = pld.correct( pixel_components=pixel_components, spline_n_knots=spline_n_knots, spline_degree=spline_degree, background_mask=background_mask, ) self.corrector = pld else: if self.verbose: print("Removing scattered light") # Make a design matrix and pass it to a linear regression corrector regressors = tpf.flux[~idx][:, ~self.aper_mask] dm = (lk.DesignMatrix( regressors, name="pixels").pca(pca_nterms).append_constant()) # Regression Corrector Object rc = lk.RegressionCorrector(self.raw_lc) self.corrector = rc corrected_lc = rc.correct(dm) # Optional: Remove the scattered light, allowing for the large offset from scattered light if with_offset: corrected_lc = (self.raw_lc - rc.model_lc + np.percentile(rc.model_lc.flux, q=5)) lc = corrected_lc.normalize() self.lc_custom = lc # compute Contamination if self.gaia_sources is None: gaia_sources = self.query_gaia_dr2_catalog(radius=120, verbose=False) else: gaia_sources = self.gaia_sources fluxes = get_fluxes_within_mask(self.tpf, self.aper_mask, gaia_sources) self.contratio = sum(fluxes) - 1 if self.tic_params is None: _ = self.query_tic_catalog(return_nearest_xmatch=True) tic_contratio = self.tic_params.contratio dcontratio = abs(tic_contratio - self.contratio) if (tic_contratio is not None) & (dcontratio > 0.5): print(f"contratio: {self.contratio:.2f} (TIC={tic_contratio:.2f})") # add method lc.detrend = lambda: detrend(lc) return lc
def make_custom_lc( self, sector=None, tpf_size=None, sap_mask=None, aper_radius=None, percentile=None, threshold_sigma=None, use_pld=True, pixel_components=3, spline_n_knots=100, spline_degree=3, background_mask=None, pca_nterms=5, with_offset=True, ): """ create a custom lightcurve based on this tutorial: https://docs.lightkurve.org/tutorials/04-how-to-remove-tess-scattered-light-using-regressioncorrector.html Parameters ---------- sector : int or str specific sector or all cutout_size : tuple tpf cutout size aper_radius: int aperture mask radius percentile: float aperture mask percentile threshold_sigma: float aperture mask threshold [sigma] method : float PLD (default) Returns ------- corrected_lc : lightkurve object """ if self.verbose: print("Using lightcurve with custom aperture.") sector = sector if sector is not None else self.sector sap_mask = sap_mask if sap_mask else self.sap_mask aper_radius = aper_radius if aper_radius else self.aper_radius percentile = percentile if percentile else self.percentile threshold_sigma = (threshold_sigma if threshold_sigma else self.threshold_sigma) cutout_size = tpf_size if tpf_size else self.cutout_size tpf_tesscut = self.get_tpf_tesscut(sector=sector, cutout_size=cutout_size) self.aper_mask = parse_aperture_mask( tpf_tesscut, sap_mask=sap_mask, aper_radius=aper_radius, percentile=percentile, threshold_sigma=threshold_sigma, verbose=False, ) raw_lc = tpf_tesscut.to_lightcurve(method="aperture", aperture_mask=self.aper_mask) # remove nans idx = (np.isnan(raw_lc.time) | np.isnan(raw_lc.flux) | np.isnan(raw_lc.flux_err)) self.tpf_tesscut = tpf_tesscut[~idx] self.lc_custom_raw = raw_lc[~idx] if use_pld: if self.verbose: print("Removing scattered light + applying PLD") pld = lk.TessPLDCorrector(self.tpf_tesscut, aperture_mask=self.aper_mask) if background_mask is None: background_mask = ~self.aper_mask corrected_lc = pld.correct( pixel_components=pixel_components, spline_n_knots=spline_n_knots, spline_degree=spline_degree, background_mask=background_mask, ) self.corrector = pld else: if self.verbose: print("Removing scattered light") # Make a design matrix and pass it to a linear regression corrector regressors = tpf_tesscut.flux[~idx][:, ~self.aper_mask] dm = (lk.DesignMatrix( regressors, name="regressors").pca(nterms=pca_nterms).append_constant()) rc = lk.RegressionCorrector(raw_lc) self.corrector = rc corrected_lc = rc.correct(dm) # Optional: Remove the scattered light, allowing for the large offset from scattered light if with_offset: corrected_lc = (raw_lc - rc.model_lc + np.percentile(rc.model_lc.flux, q=5)) lc = corrected_lc.normalize() self.lc_custom = lc # compute Contamination if self.gaia_sources is None: gaia_sources = self.query_gaia_dr2_catalog(radius=120) else: gaia_sources = self.gaia_sources fluxes = get_fluxes_within_mask(self.tpf_tesscut, self.aper_mask, gaia_sources) self.contratio = sum(fluxes) - 1 # add method lc.detrend = lambda: detrend(lc) return lc
def get_lc(self, lctype="pdcsap", sector=None, quality_bitmask=None): """ """ sector = sector if sector is not None else self.sector quality_bitmask = (quality_bitmask if quality_bitmask else self.quality_bitmask) if self.lcf is not None: # reload lcf if already in memory if self.lcf.sector == sector: lcf = self.lcf else: query_str = (f"TIC {self.ticid}" if self.ticid else self.target_coord) if self.verbose: print( f"Searching lightcurvefile for {query_str} (sector {sector})" ) q = lk.search_lightcurvefile(query_str, sector=sector, mission=MISSION) if len(q) == 0: if self.verbose: print( f"Searching lightcurvefile for {self.target_coord.to_string()} (sector {sector})" ) q = lk.search_lightcurvefile(self.target_coord, sector=sector, mission=MISSION) assert q is not None, "Empty result. Check long cadence." if self.verbose: print(f"Found {len(q)} lightcurves") if (sector == "all") & (len(self.all_sectors) > 1): lcf = q.download_all(quality_bitmask=quality_bitmask) else: lcf = q.download(quality_bitmask=quality_bitmask) self.lcf = lcf else: query_str = (f"TIC {self.ticid}" if self.ticid else self.target_coord) if self.verbose: print( f"Searching lightcurvefile for {query_str} (sector {sector})" ) q = lk.search_lightcurvefile(query_str, sector=sector, mission=MISSION) if len(q) == 0: if self.verbose: print( f"Searching lightcurvefile for {self.target_coord.to_string()} (sector {sector})" ) q = lk.search_lightcurvefile(self.target_coord, sector=sector, mission=MISSION) assert q is not None, "Empty result. Check long cadence." if self.verbose: print(f"Found {len(q)} lightcurves") if (sector == "all") & (len(self.all_sectors) > 1): lcf = q.download_all(quality_bitmask=quality_bitmask) else: lcf = q.download(quality_bitmask=quality_bitmask) self.lcf = lcf assert lcf is not None, "Empty result. Check long cadence." sap = lcf.SAP_FLUX pdcsap = lcf.PDCSAP_FLUX if isinstance(lcf, lk.LightCurveFileCollection): # merge multi-sector into one lc if len(lcf) > 1: sap0 = sap[0].normalize() sap = [sap0.append(l.normalize()) for l in sap[1:]][0] pdcsap0 = pdcsap[0].normalize() pdcsap = [pdcsap0.append(l.normalize()) for l in pdcsap[1:]][0] else: raise ValueError( f"Only sector {lcf[0].sector} (in {self.all_sectors}) is available" ) self.lc_sap = sap self.lc_pdcsap = pdcsap if lctype == "pdcsap": # add detrend method to lc instance pdcsap.detrend = lambda: detrend(pdcsap) return pdcsap.remove_nans().normalize() else: sap.detrend = lambda: detrend(sap) return sap.remove_nans().normalize()
def _get_lc(self, lctype="pdcsap", campaign=None, quality_bitmask=None): """ FIXME: refactor to lightcurve.py? """ campaign = campaign if campaign is not None else self.campaign quality_bitmask = (quality_bitmask if quality_bitmask is not None else self.quality_bitmask) if self.lcf is not None: # reload lcf if already in memory if self.lcf.campaign == campaign: lcf = self.lcf else: query_str = (f"EPIC {self.epicid}" if self.epicid else self.target_coord) if self.verbose: print( f"Searching lightcurvefile for {query_str} (campaign {campaign})" ) q = lk.search_lightcurvefile(query_str, campaign=campaign, mission="K2") if len(q) == 0: if self.verbose: print( f"Searching lightcurvefile for {self.target_coord.to_string()} (campaign {campaign})" ) q = lk.search_lightcurvefile(self.target_coord, campaign=campaign, mission="K2") assert q is not None, "Empty result. Check long cadence." if self.verbose: print(f"Found {len(q)} lightcurves") if (campaign == "all") & (len(self.all_campaigns) > 1): NotImplementedError # lcf = q.download_all(quality_bitmask=quality_bitmask) else: lcf = q.download(quality_bitmask=quality_bitmask) self.lcf = lcf else: query_str = (f"EPIC {self.epicid}" if self.epicid else self.target_coord) if self.verbose: print( f"Searching lightcurvefile for {query_str} (campaign {campaign})" ) q = lk.search_lightcurvefile(query_str, campaign=campaign, mission="K2") if len(q) == 0: if self.verbose: print( f"Searching lightcurvefile for ra,dec=({self.target_coord.to_string()}) (campaign {campaign})" ) q = lk.search_lightcurvefile(self.target_coord, campaign=campaign, mission="K2") assert q is not None, "Empty result. Check long cadence." if self.verbose: print(f"Found {len(q)} lightcurves") if (campaign == "all") & (len(self.all_campaigns) > 1): NotImplementedError # lcf = q.download_all(quality_bitmask=quality_bitmask) else: lcf = q.download(quality_bitmask=quality_bitmask) self.lcf = lcf assert lcf is not None, "Empty result. Check long cadence." sap = lcf.SAP_FLUX pdcsap = lcf.PDCSAP_FLUX if isinstance(lcf, lk.LightCurveFileCollection): # merge multi-campaign into one lc if len(lcf) > 1: sap0 = sap[0].normalize() sap = [sap0.append(l.normalize()) for l in sap[1:]][0] pdcsap0 = pdcsap[0].normalize() pdcsap = [pdcsap0.append(l.normalize()) for l in pdcsap[1:]][0] else: raise ValueError( f"Only campaign {lcf[0].campaign} (in {self.all_campaigns}) is available" ) self.lc_sap = sap self.lc_pdcsap = pdcsap if lctype == "pdcsap": # add detrend method to lc instance pdcsap.detrend = lambda: detrend(pdcsap) return pdcsap.remove_nans().normalize() else: sap.detrend = lambda: detrend(sap) return sap.remove_nans().normalize()