Beispiel #1
0
def find_number_of_PCs(results, regressors, lc):
    '''
    Purpose:
        Find the number of principal components to use in the PCA method
    '''

    # Parameters / Criteria
    npc = 7
    nbins = 40  # number of bins to divide the each PC
    threshold_variance = 1e-4  # 5 # -> 500% # THIS IS NOT USED.

    dm = lk.DesignMatrix(regressors,
                         name='regressors').pca(npc).append_constant()
    rc = lk.RegressionCorrector(lc)
    lc_regressed = rc.correct(dm)

    # Find the median of the moving variance for each PCs
    boxsize = np.floor(dm.values[:, 0].size / nbins).astype(int)
    pcs_variances = []
    for ipc in range(npc):
        pcs_variances.append(
            pd.Series(dm.values[:, ipc]).rolling(boxsize).var().median())
    # pcs_variances = [ pd.Series(dm.values[:,ipc]).rolling(boxsize).var().median() for ipc in range(npc) ]
    pcs_variances = np.array(pcs_variances)
    relative_change_variances = np.abs(
        np.diff(pcs_variances) / pcs_variances[:-1])  # < THIS IS NOT USED.

    # Select PCs with variance above threshold value
    ind_bad_pcs = np.argwhere(pcs_variances > threshold_variance)
    if ind_bad_pcs.size > 0:
        # Find index first PC that exceeds threshold value. This is the new npc
        new_npc = ind_bad_pcs[0].item()
    else:
        print(
            f'No PCs with variance>{threshold_variance}. All {npc} PCs used.')
        new_npc = npc

    # Store to results
    results['pca_all'] = {'coef':rc.coefficients,\
                          'pc':[dm.values[:,i] for i in range(dm.rank)],\
                          'dm':dm,\
                          'rc':rc,\
                          'npc':npc,\
                          'npc_used':new_npc,\
                          'pc_variances':pcs_variances,\
                          'threshold_variance':threshold_variance,\
                          'nbins':nbins}

    return new_npc, dm, rc
Beispiel #2
0
 def build(self, object_info: MissionObjectInfo, sherlock_dir, caches_root_dir):
     mission_id = object_info.mission_id()
     sherlock_id = object_info.sherlock_id()
     logging.info("Retrieving star catalog info...")
     mission, mission_prefix, id = super().parse_object_id(mission_id)
     if mission_prefix not in self.star_catalogs:
         raise ValueError("Wrong object id " + mission_id)
     cadence = object_info.cadence if object_info.cadence is not None else "short"
     author = object_info.author if object_info.author is not None else self.authors[mission]
     star_info = starinfo.StarInfo(sherlock_id, *self.star_catalogs[mission_prefix].catalog_info(id))
     logging.info("Downloading lightcurve files...")
     sectors = None if object_info.sectors == 'all' or mission != constants.MISSION_TESS else object_info.sectors
     campaigns = None if object_info.sectors == 'all' or mission != constants.MISSION_K2 else object_info.sectors
     quarters = None if object_info.sectors == 'all' or mission != constants.MISSION_KEPLER else object_info.sectors
     tokens = sectors if sectors is not None else campaigns if campaigns is not None else quarters
     tokens = tokens if tokens is not None else "all"
     apertures = {}
     tpf_search_results = lk.search_targetpixelfile(str(mission_id))
     for tpf_search_result in tpf_search_results:
         logging.info("There is data for Mission: %s, Year %.0f, Author: %s, ExpTime: %.0f",
                      tpf_search_result.mission[0], tpf_search_result.year[0], tpf_search_result.author[0],
                      tpf_search_result.exptime[0].value)
     tpfs_dir = sherlock_dir + "/tpfs/"
     if not os.path.exists(tpfs_dir):
         os.mkdir(tpfs_dir)
     if object_info.apertures is None:
         lcf_search_results = lk.search_lightcurve(str(mission_id), mission=mission, cadence=cadence,
                                        sector=sectors, quarter=quarters,
                                        campaign=campaigns, author=author)
         lcf = lcf_search_results.download_all(download_dir=caches_root_dir + LIGHTKURVE_CACHE_DIR)
         tpfs = lk.search_targetpixelfile(str(mission_id), mission=mission, cadence=cadence,
                                        sector=sectors, quarter=quarters,
                                        campaign=campaigns, author=author)\
             .download_all(download_dir=caches_root_dir + LIGHTKURVE_CACHE_DIR,
                           cutout_size=(CUTOUT_SIZE, CUTOUT_SIZE))
         if lcf is None:
             raise ObjectProcessingError("The target " + str(mission_id) + " is not available for the author " + author +
                              ", cadence " + str(cadence) + "s and sectors " + str(tokens))
         lc_data = self.extract_lc_data(lcf)
         lc = None
         matching_objects = []
         for tpf in tpfs:
             shutil.copy(tpf.path, tpfs_dir + os.path.basename(tpf.path))
             if mission_prefix == self.MISSION_ID_KEPLER:
                 sector = tpf.quarter
             elif mission_prefix == self.MISSION_ID_TESS:
                 sector = tpf.sector
             if mission_prefix == self.MISSION_ID_KEPLER_2:
                 sector = tpf.campaign
             apertures[sector] = ApertureExtractor.from_boolean_mask(tpf.pipeline_mask, tpf.column, tpf.row)
         for i in range(0, len(lcf.data)):
             if lcf.data[i].label == mission_id:
                 if lc is None:
                     lc = lcf.data[i].normalize()
                 else:
                     lc = lc.append(lcf.data[i].normalize())
             else:
                 matching_objects.append(lcf.data[i].label)
         matching_objects = set(matching_objects)
         if len(matching_objects) > 0:
             logging.warning("================================================")
             logging.warning("TICS IN THE SAME PIXEL: " + str(matching_objects))
             logging.warning("================================================")
         if lc is None:
             tokens = sectors if sectors is not None else campaigns if campaigns is not None else quarters
             tokens = tokens if tokens is not None else "all"
             raise ObjectProcessingError("The target " + str(mission_id) + " is not available for the author " + author +
                              ", cadence " + str(cadence) + "s and sectors " + str(tokens))
         lc = lc.remove_nans()
         transits_min_count = self.__calculate_transits_min_count(len(lcf))
         if mission_prefix == self.MISSION_ID_KEPLER:
             sectors = [lcfile.quarter for lcfile in lcf]
         elif mission_prefix == self.MISSION_ID_TESS:
             sectors = [file.sector for file in lcf]
         elif mission_prefix == self.MISSION_ID_KEPLER_2:
             logging.info("Correcting K2 motion in light curve...")
             sectors = [lcfile.campaign for lcfile in lcf]
             lc = lc.to_corrector("sff").correct(windows=20)
         source = "tpf"
     else:
         logging.info("Using user apertures!")
         tpf_search_results = lk.search_targetpixelfile(str(mission_id), mission=mission, cadence=cadence,
                                          sector=sectors, quarter=quarters, campaign=campaigns,
                                          author=author)
         tpfs = tpf_search_results.download_all(download_dir=caches_root_dir + LIGHTKURVE_CACHE_DIR,
                                                cutout_size=(CUTOUT_SIZE, CUTOUT_SIZE))
         source = "tpf"
         apertures = object_info.apertures
         lc = None
         for tpf in tpfs:
             shutil.copy(tpf.path, tpfs_dir + os.path.basename(tpf.path))
             if mission_prefix == self.MISSION_ID_KEPLER:
                 sector = tpf.quarter
             elif mission_prefix == self.MISSION_ID_TESS:
                 sector = tpf.sector
             elif mission_prefix == self.MISSION_ID_KEPLER_2:
                 sector = tpf.campaign
             boolean_aperture = ApertureExtractor.from_pixels_to_boolean_mask(apertures[sector], tpf.column, tpf.row,
                                                                      CUTOUT_SIZE, CUTOUT_SIZE)
             tpf.plot(aperture_mask=boolean_aperture, mask_color='red')
             plt.savefig(sherlock_dir + "/fov/Aperture_[" + str(sector) + "].png")
             plt.close()
             if mission_prefix == self.MISSION_ID_KEPLER:
                 corrector = lk.KeplerCBVCorrector(tpf)
                 corrector.plot_cbvs([1, 2, 3, 4, 5, 6, 7])
                 raw_lc = tpf.to_lightcurve(aperture_mask=boolean_aperture).remove_nans()
                 plt.savefig(sherlock_dir + "/Corrector_components[" + str(sector) + "].png")
                 plt.close()
                 it_lc = corrector.correct([1, 2, 3, 4, 5])
                 ax = raw_lc.plot(color='C3', label='SAP Flux', linestyle='-')
                 it_lc.plot(ax=ax, color='C2', label='CBV Corrected SAP Flux', linestyle='-')
                 plt.savefig(sherlock_dir + "/Raw_vs_CBVcorrected_lc[" + str(sector) + "].png")
                 plt.close()
             elif mission_prefix == self.MISSION_ID_KEPLER_2:
                 raw_lc = tpf.to_lightcurve(aperture_mask=boolean_aperture).remove_nans()
                 it_lc = raw_lc.to_corrector("sff").correct(windows=20)
                 ax = raw_lc.plot(color='C3', label='SAP Flux', linestyle='-')
                 it_lc.plot(ax=ax, color='C2', label='CBV Corrected SAP Flux', linestyle='-')
                 plt.savefig(sherlock_dir + "/Raw_vs_SFFcorrected_lc[" + str(sector) + "].png")
                 plt.close()
             elif mission_prefix == self.MISSION_ID_TESS:
                 temp_lc = tpf.to_lightcurve(aperture_mask=boolean_aperture)
                 where_are_NaNs = np.isnan(temp_lc.flux)
                 temp_lc = temp_lc[np.where(~where_are_NaNs)]
                 regressors = tpf.flux[np.argwhere(~where_are_NaNs), ~boolean_aperture]
                 temp_token_lc = [temp_lc[i: i + 2000] for i in range(0, len(temp_lc), 2000)]
                 regressors_token = [regressors[i: i + 2000] for i in range(0, len(regressors), 2000)]
                 it_lc = None
                 raw_it_lc = None
                 item_index = 0
                 for temp_token_lc_item in temp_token_lc:
                     regressors_token_item = regressors_token[item_index]
                     design_matrix = lk.DesignMatrix(regressors_token_item, name='regressors').pca(5).append_constant()
                     corr_lc = lk.RegressionCorrector(temp_token_lc_item).correct(design_matrix)
                     if it_lc is None:
                         it_lc = corr_lc
                         raw_it_lc = temp_token_lc_item
                     else:
                         it_lc = it_lc.append(corr_lc)
                         raw_it_lc = raw_it_lc.append(temp_token_lc_item)
                     item_index = item_index + 1
                 ax = raw_it_lc.plot(label='Raw light curve')
                 it_lc.plot(ax=ax, label='Corrected light curve')
                 plt.savefig(sherlock_dir + "/Raw_vs_DMcorrected_lc[" + str(sector) + "].png")
                 plt.close()
             if lc is None:
                 lc = it_lc.normalize()
             else:
                 lc = lc.append(it_lc.normalize())
         lc = lc.remove_nans()
         lc.plot(label="Normalized light curve")
         plt.savefig(sherlock_dir + "/Normalized_lc[" + str(sector) + "].png")
         plt.close()
         transits_min_count = self.__calculate_transits_min_count(len(tpfs))
         if mission_prefix == self.MISSION_ID_KEPLER or mission_id == self.MISSION_ID_KEPLER_2:
             sectors = [lcfile.quarter for lcfile in tpfs]
         elif mission_prefix == self.MISSION_ID_TESS:
             sectors = [file.sector for file in tpfs]
         if mission_prefix == self.MISSION_ID_KEPLER_2:
             logging.info("Correcting K2 motion in light curve...")
             sectors = [lcfile.campaign for lcfile in tpfs]
         sectors = None if sectors is None else np.unique(sectors)
         lc_data = None
     return LcBuild(lc, lc_data, star_info, transits_min_count, cadence, None, sectors, source, apertures)
Beispiel #3
0
    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
Beispiel #4
0
    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_LCs(CLUSTERS,phot_type):
    NUMBER_PCA_COMPONENTS = 5 #no of vectors for PCA
    #initialize the masks
    star_mask=np.empty([len(tpfs),cutout_size,cutout_size],dtype='bool')
    if phot_type == 'pixel': # if pixel photometry is requested, define a different variable
        radius_mask=np.empty([len(tpfs),cutout_size,cutout_size],dtype='bool')
    sky_mask=np.empty([len(tpfs),cutout_size,cutout_size],dtype='bool')

    frame = tpfs[0].shape[0]//2
    # obtain the aperture and the background masks with help of cluster radius and percentile (85%)
    if phot_type == 'pixel':
        radius_mask[0],sky_mask[0] = circle_aperture(tpfs[0][frame].flux,tpfs[0][frame].flux, \
						     Complete_Clusters[Complete_Clusters['NAME'] == CLUSTERS[0]]['CORE_RADIUS'].values[0],85)
    elif phot_type == 'ensemble': 
        star_mask[0],sky_mask[0] = circle_aperture(tpfs[0][frame].flux,tpfs[0][frame].flux, \
						   Complete_Clusters[Complete_Clusters['NAME'] == CLUSTERS[0]]['CORE_RADIUS'].values[0],85)

    # if pixel photometry, iterate over each pixel in the radius mask and download LCs
    if phot_type == 'pixel':
        for i in range(len(np.where(radius_mask[0])[0])):
            star_mask=np.zeros([len(tpfs),cutout_size,cutout_size],dtype='bool')
            pixel_loc=np.where(radius_mask[0])[0][i],np.where(radius_mask[0])[1][i]
            star_mask[0][pixel_loc]=True

            lightcurves = [tpfs[i].to_lightcurve(aperture_mask=star_mask[i]) for i in range(len(tpfs))];
            for i in range(len(lightcurves)):
                lightcurves[i]=lightcurves[i][lightcurves[i].flux_err > 0]
            
            #PCA correction
            regressors = [tpfs[i].flux[:, sky_mask[i]] for i in range(len(tpfs))]# The regressor is the inverse of the aperture
            #Design a matrix for linear regression
            dms = [lk.DesignMatrix(r, name='regressors').pca(NUMBER_PCA_COMPONENTS).append_constant() for r in regressors]
            #Remove noise using linear regression against a DesignMatrix.
            correctors = [lk.RegressionCorrector(lc) for lc in lightcurves]
            correctedLCs = [correctors[i].correct(dms[i]) for i in range(len(correctors))]#this is how to subtract the background noise from the star pixels

            #polyomial correction. to remove long period systematic trends that survived the PCA correction
            correctedLCs_poly,poly_terms = polynomial_correction(correctedLCs[0])
            #save the pixel corrected LCs
            correctedLCs_poly.to_csv(CLUSTERS[0]+' pixels/core_pixels/corrected_LCs_CORE_RADIUS_pixel_no.{0}'.format(pixel_loc))

    # is ensemble photometry, download LC for entire aperture
    elif phot_type == 'ensemble':
        lightcurves = [tpfs[i].to_lightcurve(aperture_mask=star_mask[i]) for i in range(len(tpfs))];
        for i in range(len(lightcurves)):
            lightcurves[i]=lightcurves[i][lightcurves[i].flux_err > 0]
        regressors = [tpfs[i].flux[:, sky_mask[i]] for i in range(len(tpfs))]# The regressor is the inverse of the aperture
        #Design a matrix for linear regression
        dms = [lk.DesignMatrix(r, name='regressors').pca(NUMBER_PCA_COMPONENTS).append_constant() for r in regressors]
        #Remove noise using linear regression against a DesignMatrix.
        correctors = [lk.RegressionCorrector(lc) for lc in lightcurves]
        correctedLCs = [correctors[i].correct(dms[i]) for i in range(len(correctors))]
        #polynomial correction
        correctedLCs_poly,poly_terms = polynomial_correction(correctedLCs[0])
        
        #calculate the lomb-scargle periodogram for the ensemble corrected LC for a range frequencies
        t = correctedLCs_poly[correctedLCs_poly.quality == 0].time
        dy = correctedLCs_poly[correctedLCs_poly.quality == 0].flux_err
        y = correctedLCs_poly[correctedLCs_poly.quality == 0].flux
        omega=np.arange(0.05,11,0.01)
        P_LS = LombScargle(t, y, dy=dy).power(omega)# LS power
#         max_power=np.max(P_LS)
#         freq_at_max_power=omega[np.argmax(P_LS)]
        return omega, P_LS #return frequencies and LS power
Beispiel #6
0
def extract_light_curve(fits_filename, outputdir, return_msg=True):

    # Output name
    output = Path(fits_filename.stem + '_corrected.pickled')
    output = outputdir / output

    # Parameters and  Criteria:
    sigma_clipping = 5  # To be applied after the detrending of the light curve

    # Structure the data to be saved
    results = {
        'tic': None,
        'sector': None,
        'ra': None,
        'dec': None,
        'headers': None,  # Headers from the original FITS file
        'fit': None,  # Result from fit
        'neighbours_all': None,  # All neighbours stars info
        'neighbours_used': None,  # Used neighbours stars info
        'target': None,  # Target star info
        'aperture_threshold': None,  # HDU to store tabular information
        'pca_all': None,  # PCA results
        'pca_used': None,  # PCA results
        'centroids': None,  # Centroids results
        'excluded_intervals': None,  # Excluded intervals in days
        'lc_raw': None,  # Light curves
        'lc_raw_nonan': None,  # Light curves
        'lc_trend': None,  # Light curves
        'lc_regressed': None,  # Light curves
        'lc_regressed_notoutlier': None,  # Light curves
        'median_image': None,
        'masks': None,
        'tag': None
    }

    # Save information from header from original FITS file
    HDUL, ext = [], 0
    while True:
        try:
            HDUL.append(
                fits.getheader(fits_filename.as_posix(), ext=ext).tostring())
            ext += 1
        except IndexError:
            break
        except Exception as e:
            print('Unexpected exception when reading headers from FITS: ', e)
            break
    results['headers'] = HDUL

    # Load the TESS taret pixel file
    try:
        tpf = lk.TessTargetPixelFile(fits_filename.as_posix())
    except Exception as e:
        # Save results
        err_msg = f'"lightkurve.TessTargetPixelFile()" could not open file {fits_filename.as_posix()}. Exception: {e}'
        results['tag'] = err_msg
        picklefile = open(output.as_posix(), 'wb')
        pickle.dump(results, picklefile)
        picklefile.close()
        if return_msg: return err_msg
        return
    tic = str(tpf.get_keyword('ticid'))
    sector = str(tpf.get_keyword('sector'))
    target_ra = np.float(tpf.ra)
    target_dec = np.float(tpf.dec)
    # Store to results
    results['tic'], results['sector'] = tic, sector
    results['ra'], results['dec'] = target_ra, target_dec

    # Initialize messages
    id_msg = f'TIC {tic} Sector {sector}: Skipped: '
    OK_msg = f'TIC {tic} Sector {sector}: OK'

    # Calculate the median image
    with warnings.catch_warnings():
        warnings.simplefilter('ignore')
        median_image = np.nanmedian(tpf.flux, axis=0)
        # Store to results
        results['median_image'] = median_image

    # Estimate of aperture mask and background mask
    ap_mask_threshold, bkg_mask_threshold = 5, 3
    ap_mask = threshold_mask(median_image,
                             threshold=ap_mask_threshold,
                             reference_pixel='center')
    ap_bkg = ~threshold_mask(
        median_image, threshold=bkg_mask_threshold, reference_pixel=None)
    # Exclude NaN values outside the camera
    ap_bkg &= ~np.isnan(median_image)
    # Estimate the median flux background
    median_bkg_flux = np.median(median_image[ap_bkg])
    # Store to results
    results['masks'] = {'aperture':ap_mask,\
                        'background':ap_bkg}

    # Check validity of aperture mask
    OK_ap_mask, err_msg = check_aperture_mask(ap_mask, id_msg)
    # If aperture is not good, exit program with corresponding message
    if not OK_ap_mask:
        # Save results
        results['tag'] = err_msg
        picklefile = open(output.as_posix(), 'wb')
        pickle.dump(results, picklefile)
        picklefile.close()
        if return_msg: return err_msg
        return

    # Refine aperture
    try:
        WCS = tpf.wcs
    except IndexError:
        # Save results
        err_msg = id_msg + 'No WCS info in header'
        results['tag'] = err_msg
        picklefile = open(output.as_posix(), 'wb')
        pickle.dump(results, picklefile)
        picklefile.close()
        if return_msg: return err_msg
        return
    ap_mask,\
    target_coord_pixel, target_tmag,\
    nb_coords_pixel, nb_tmags,\
    err_msg = refine_aperture(results, tic, target_ra, target_dec, WCS,\
                  ap_mask, ap_mask_threshold, median_image, prepend_err_msg=id_msg)
    # If not satisfactory aperture mask
    if ap_mask is None:
        # Save results
        results['tag'] = err_msg
        picklefile = open(output.as_posix(), 'wb')
        pickle.dump(results, picklefile)
        picklefile.close()
        if return_msg: return err_msg
        return

    # Variation in time of aperture's center of mass
    centroid_col, centroid_row = tpf.estimate_centroids(aperture_mask=ap_mask,
                                                        method='quadratic')
    centroid_col -= tpf.column
    centroid_row -= tpf.row
    sqrt_col2_row2 = np.sqrt(centroid_col**2 + centroid_row**2)
    # Store to results
    results['centroids'] = {'col':centroid_col,\
                            'row':centroid_row,\
                            'sqrt_col2_row2':sqrt_col2_row2,\
                            'time':tpf.time}

    # Fit the image and find the contamination fraction within the aperture mask
    fitted_image, err_msg = contamination(results, median_image,ap_mask,\
                                 target_coord_pixel, target_tmag,\
                                 nb_coords_pixel, nb_tmags,\
                                 tpf.wcs,median_bkg_flux,
                                 prepend_err_msg=id_msg)
    if fitted_image is None:
        # Save results
        results['tag'] = err_msg
        picklefile = open(output.as_posix(), 'wb')
        pickle.dump(results, picklefile)
        picklefile.close()
        if return_msg: return err_msg
        return

    # Generate the raw light curve
    lc_raw = tpf.to_lightcurve(aperture_mask=ap_mask, method='aperture')
    # Store to results
    results['lc_raw'] = {'flux':lc_raw.flux,\
                         'time':lc_raw.time}

    # Find the indices of the quality mask that created the light curve
    ind = np.argwhere(tpf.quality_mask == True)
    # Masks with True value the light curve times with null or NaN flux
    mask = lc_raw.flux == 0
    mask |= lc_raw.flux == np.nan
    # Set to False the indices to be masked (ignored).
    # Note that we take a subset from `ind` because the masks where defined from the light curve
    tpf.quality_mask[ind[mask]] = False

    # Exclude intervals previously decided
    exclude_interval(tpf, sector, results)

    # Generate the light curve
    lc = tpf.to_lightcurve(aperture_mask=ap_mask, method='aperture')
    # Store to results
    results['lc_raw_nonan'] = {'flux':lc.flux,\
                               'time':lc.time}

    # Make a design matrix and pass it to a linear regression corrector
    regressors = tpf.flux[:, ap_bkg]

    # Number of PCs to use
    npc, dm, rc = find_number_of_PCs(results, regressors, lc)

    if npc == 0:
        # Save results
        results['tag'] = id_msg + 'None PC used, no detrended done.'
        picklefile = open(output.as_posix(), 'wb')
        pickle.dump(results, picklefile)
        picklefile.close()
        if return_msg: return err_msg
        return

    try:
        # Detrend light curve using PCA
        dm = lk.DesignMatrix(regressors,
                             name='regressors').pca(npc).append_constant()
        rc = lk.RegressionCorrector(lc)
        lc_regressed = rc.correct(dm)
        lc_trend = rc.diagnostic_lightcurves['regressors']

        # Sigma clipping the remove outliers
        lc_regressed_no_outliers, lc_mask_regressed_outliers = lc_regressed.remove_outliers(
            return_mask=True, sigma=sigma_clipping)

        # Store to results
        results['lc_trend']                = {'flux':lc_trend.flux,\
                                              'time':lc_trend.time}
        results['lc_regressed']            = {'flux':lc_regressed.flux,\
                                              'time':lc_regressed.time,\
                                              'outlier_mask':lc_mask_regressed_outliers,\
                                              'sigma_clipping':sigma_clipping}
        results['lc_regressed_notoutlier'] = {'flux':lc_regressed_no_outliers.flux,\
                                              'time':lc_regressed_no_outliers.time}
        results['pca_used']                = {'coef':rc.coefficients,\
                                              'pc':[dm.values[:,i] for i in range(dm.rank)],\
                                              'dm':dm,\
                                              'rc':rc,\
                                              'npc':npc}

        # Save results
        results['tag'] = 'OK'
        picklefile = open(output.as_posix(), 'wb')
        pickle.dump(results, picklefile)
        picklefile.close()
        if return_msg: return OK_msg
        return

    except Exception as e:
        print('!!!!!!!!!!!!!!!!!!!!!!!!!')
        print(f'   Sector {sector}.')
        print('EXCEPTION:', e)
        print('!!!!!!!!!!!!!!!!!!!!!!!!!')
        if return_msg: return id_msg + '::' + repr(e) + '::' + str(e)
        return
Beispiel #7
0

    #Select best
    cdpp = [lk.estimate_cdpp() for lk in lkf]
    bidx = np.argmin(cdpp)
    lkf  = lkf[bidx]

    color_print('\nAperture chosen: ', 'lightcyan', str(bidx+1) + 'px radius' if args.circ==0 else 'No. ' + str(bidx), 'default',
                '\tNumber of pixels inside: ', 'lightcyan', str(dap[bidx].sum()), 'default')


    #PCA
    if args.pca:
        import lightkurve
        regressors = flux[:, ~dap[bidx]]
        dm         = lightkurve.DesignMatrix(regressors, name='regressors')

        dm = dm.pca(5)
        dm = dm.append_constant()

        corrector = lightkurve.RegressionCorrector(lkf)
        corr_flux = corrector.correct(dm)
        lkf = lkf - corrector.model_lc + np.percentile(corrector.model_lc.flux, 5)
        #lkf.flux  = lkf.flux - corrector.model_lc + np.percentile(corrector.model_lc.flux, 5)

    #PLD?
    elif args.pld:
        '''
        if iP is None:
            mask = np.ones(time.size).astype(bool)
        else:
def build_X(
    time,
    pos_corr1,
    pos_corr2,
    flux=None,
    t_model=None,
    background=False,
    cbvs=None,
    spline=True,
    spline_period=0.75,
    sff=False,
    windows=20,
    bins=15,
):
    """Build a design matrix to model pixel in target pixel files

    Parameters
    ----------
    tpf : lightkurve.TargetPixelFile
        Input target pixel file to make the design matrix for
    flux : np.ndarray
        The SAP flux to use for creating the design matrix
    t_model: None or np.ndarray
        The transit model, if None no transit model will be used in the design matrix
    cbvs: None or np.ndarray
        Cotrending Basis vectors. If None will not be used in design matrix
    spline: bool
        Whether to use a B-Spline in time
    spline_period: float
        If using a spline, what time period the knots should be spaced at

    Returns
    -------
    SA : scipy.sparse.csr_matrix
        The design matrix to use to detrend the input TPF
    """

    r, c = np.nan_to_num(pos_corr1), np.nan_to_num(pos_corr2)
    r[np.abs(r) > 10] = 0
    c[np.abs(r) > 10] = 0
    breaks = np.where((np.diff(time) > (np.median(np.diff(time)) * 20)))[0] - 1
    breaks = breaks[breaks > 0]
    if sff:
        lc = lk.KeplerLightCurve(time=time,
                                 flux=time**0,
                                 centroid_col=pos_corr1,
                                 centroid_row=pos_corr2)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            s = lk.correctors.SFFCorrector(lc)
            _ = s.correct(windows=windows, bins=bins, timescale=spline_period)
            centroids = s.dmc["sff"].X
    else:
        if np.nansum(r) == 0:
            ts0 = np.asarray(
                [np.in1d(time, t) for t in np.array_split(time, breaks)])
            ts1 = np.asarray([
                np.in1d(time, t) * (time - t.mean()) / (t[-1] - t[0])
                for t in np.array_split(time, breaks)
            ])
            time_array = np.vstack([ts0, ts1, ts1**2]).T
            centroids = np.copy(time_array)
        else:
            centroids = np.nan_to_num(
                np.vstack([
                    r**idx * c**jdx for idx in np.arange(0, 4)
                    for jdx in range(0, 4)
                ]).T)
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                centroids = lk.correctors.DesignMatrix(centroids).split(
                    list(breaks)).X
    A = csr_matrix(np.copy(centroids))

    if cbvs is not None:
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            A = hstack([
                A,
                lk.DesignMatrix(np.nan_to_num(cbvs)).split(list(breaks)).X
            ]).tocsr()
    if spline:
        spline_dm = create_sparse_spline_matrix(
            time,
            n_knots=int(np.max([4,
                                int((time[-1] - time[0]) // spline_period)
                                ]))).X
        A = hstack([csr_matrix(A), spline_dm]).tocsr()
    if flux is None:
        if t_model is not None:
            return hstack([A, np.atleast_2d(t_model).T]).tocsr()
        return A

    #    SA = A.multiply(np.atleast_2d(flux).T).tocsr()
    if t_model is not None:
        SA = hstack([A, np.atleast_2d(t_model).T]).tocsr()
    else:
        SA = A.tocsr()
    return SA
Beispiel #9
0
def build_X(tpf,
            flux,
            t_model=None,
            background=False,
            cbvs=None,
            spline=True,
            spline_period=2,
            sff=False):
    """Build a design matrix to use in the model"""
    r, c = np.nan_to_num(tpf.pos_corr1), np.nan_to_num(tpf.pos_corr2)
    r[np.abs(r) > 10] = 0
    c[np.abs(r) > 10] = 0

    if sff:
        r = lk.SFFCorrector(lk.LightCurve(tpf.time, flux))
        _ = r.correct()
        centroids = r.X['sff']
    else:
        breaks = np.where((np.diff(tpf.time) > (0.0202 * 10)))[0] - 1
        breaks = breaks[breaks > 0]

        if r.sum() == 0:
            ts0 = np.asarray([
                np.in1d(tpf.time, t) for t in np.array_split(tpf.time, breaks)
            ])
            ts1 = np.asarray([
                np.in1d(tpf.time, t) * (tpf.time - t.mean()) / (t[-1] - t[0])
                for t in np.array_split(tpf.time, breaks)
            ])
            centroids = np.vstack([ts0, ts1, ts1**2]).T

        else:
            rs0 = np.asarray([
                np.in1d(tpf.time, t) for t in np.array_split(tpf.time, breaks)
            ])
            rs1 = np.asarray([
                np.in1d(tpf.time, t) * (r - r[np.in1d(tpf.time, t)].mean())
                for t in np.array_split(tpf.time, breaks)
            ])
            cs1 = np.asarray([
                np.in1d(tpf.time, t) * (c - c[np.in1d(tpf.time, t)].mean())
                for t in np.array_split(tpf.time, breaks)
            ])
            centroids = np.vstack([
                rs1, cs1, rs1 * cs1, rs1**2, cs1**2, rs1**2 * cs1,
                rs1 * cs1**2, rs1**2 * cs1**2, rs1**3 * cs1**3,
                rs1**3 * cs1**2, rs1**3 * cs1, rs1**3, cs1**3, cs1**3 * rs1,
                cs1**3 * rs1**2
            ]).T

    A = np.copy(centroids)
    if cbvs is not None:
        A = np.hstack([A, np.nan_to_num(cbvs)])
    if background:
        bkg = lk.DesignMatrix(
            tpf.flux[:, ~tpf.create_threshold_mask()]).pca(3).values
        A = np.hstack([A, bkg])
    if spline:
        spline_dm = lk.correctors.designmatrix.create_spline_matrix(
            tpf.time,
            n_knots=np.max(
                [4, int(
                    (tpf.time[-1] - tpf.time[0]) // spline_period)])).values
        A = np.hstack([A, spline_dm])

    SA = np.atleast_2d(flux).T * A

    if t_model is not None:
        SA = np.hstack([
            SA,
            np.atleast_2d(np.ones(len(tpf.time))).T,
            np.atleast_2d(t_model).T
        ])
    else:
        SA = np.hstack([SA, np.atleast_2d(np.ones(len(tpf.time))).T])
    return csr_matrix(SA)
    def __init__(self,
                 targetpixelfile,
                 gaia=True,
                 magnitude_limit=18,
                 frequencies=[],
                 frequnit=u.uHz,
                 principle_components=5,
                 aperture=None,
                 **kwargs):

        #Defining an aperture that will be used in plotting and making empty 2-d arrays of the correct size for masks
        if targetpixelfile.pipeline_mask.any() == False:
            self.aperture = aperture
        else:
            self.aperture = targetpixelfile.pipeline_mask
        self.tpf = targetpixelfile

        # Make a design matrix and pass it to a linear regression corrector
        self.raw_lc = self.tpf.to_lightcurve(aperture_mask=self.aperture)
        self.dm = lk.DesignMatrix(
            self.tpf.flux[:, ~self.tpf.create_threshold_mask()],
            name='regressors').pca(principle_components)
        rc = lk.RegressionCorrector(self.raw_lc)
        corrected_lc = rc.correct(self.dm.append_constant())
        corrected_lc[np.where(corrected_lc.quality == 0)]
        self.corrected_lc = corrected_lc.remove_outliers()
        self.frequency_list = np.asarray((frequencies * frequnit).to(1 / u.d))
        self.principle_components = principle_components

        def Obtain_Initial_Phase(tpf, corrected_lc, frequency_list):

            flux = corrected_lc.flux.value
            times = corrected_lc.time.value - np.mean(corrected_lc.time.value)
            pg = corrected_lc.to_periodogram(frequency=np.append(
                [0.0001], frequency_list),
                                             ls_method='slow')
            initial_flux = np.asarray(pg.power[1:])

            initial_phase = np.zeros(len(frequency_list))

            def lc_model(time, amp, freq, phase):
                return amp * np.sin(2 * np.pi * freq * time + phase)

            def background_model(time, height):
                return np.ones(len(time)) * height

            for j in np.arange(len(frequency_list)):
                for i in np.arange(len(frequency_list)):

                    if (i == 0):
                        model = lm.Model(lc_model,
                                         independent_vars=['time'],
                                         prefix='f{0:d}'.format(i))
                        model += lm.Model(background_model,
                                          independent_vars=['time'])
                    else:
                        model += lm.Model(lc_model,
                                          independent_vars=['time'],
                                          prefix='f{0:d}'.format(i))

                    model.set_param_hint('f{0:d}phase'.format(i),
                                         min=-np.pi,
                                         max=np.pi,
                                         value=initial_phase[i],
                                         vary=False)
                    model.set_param_hint('f{0:d}amp'.format(i),
                                         value=initial_flux[i],
                                         vary=False)
                    model.set_param_hint('height',
                                         value=np.mean(flux),
                                         vary=False)
                    model.set_param_hint('f{0:d}freq'.format(i),
                                         value=frequency_list[i],
                                         vary=False)

                params = model.make_params()
                params['f{0:d}phase'.format(j)].set(vary=True)
                params['f{0:d}phase'.format(j)].set(value=initial_phase[j])
                params['f{0:d}phase'.format(j)].set(brute_step=np.pi / 10)
                result = model.fit(corrected_lc.flux.value,
                                   params,
                                   time=times,
                                   method='brute')
                initial_phase[j] = result.best_values['f{0:d}phase'.format(j)]

            return initial_phase

        self.initial_phases = Obtain_Initial_Phase(self.tpf, self.corrected_lc,
                                                   self.frequency_list)

        def Obtain_Final_Phase(tpf, corrected_lc, frequency_list,
                               initial_phases):

            flux = corrected_lc.flux.value
            times = corrected_lc.time.value - np.mean(corrected_lc.time.value)
            pg = corrected_lc.to_periodogram(frequency=np.append(
                [0.0001], frequency_list),
                                             ls_method='slow')
            initial_flux = np.asarray(pg.power[1:])

            def lc_model(time, amp, freq, phase):
                return amp * np.sin(2 * np.pi * freq * time + phase)

            def background_model(time, height):
                return np.ones(len(time)) * height

            for i in np.arange(len(frequency_list)):

                if (i == 0):
                    model = lm.Model(lc_model,
                                     independent_vars=['time'],
                                     prefix='f{0:d}'.format(i))
                    model += lm.Model(background_model,
                                      independent_vars=['time'])
                else:
                    model += lm.Model(lc_model,
                                      independent_vars=['time'],
                                      prefix='f{0:d}'.format(i))

                model.set_param_hint('f{0:d}phase'.format(i),
                                     min=-np.pi,
                                     max=np.pi,
                                     value=initial_phases[i],
                                     vary=True)
                model.set_param_hint('f{0:d}amp'.format(i),
                                     value=initial_flux[i],
                                     vary=True)
                model.set_param_hint('height', value=np.mean(flux), vary=True)
                model.set_param_hint('f{0:d}freq'.format(i),
                                     value=frequency_list[i],
                                     vary=False)

            params = model.make_params()

            result = model.fit(corrected_lc.flux.value, params, time=times)

            final_phases = [
                result.best_values['f{0:d}phase'.format(j)]
                for j in np.arange(len(frequency_list))
            ]

            return final_phases

        self.final_phases = Obtain_Final_Phase(self.tpf, self.corrected_lc,
                                               self.frequency_list,
                                               self.initial_phases)

        def Obtain_Final_Fit(tpf, corrected_lc, frequency_list, final_phases):

            flux = corrected_lc.flux.value
            times = corrected_lc.time.value - np.mean(corrected_lc.time.value)
            pg = corrected_lc.to_periodogram(frequency=np.append(
                [0.0001], frequency_list),
                                             ls_method='slow')
            initial_flux = np.asarray(pg.power[1:])

            def lc_model(time, amp, freq, phase):
                return amp * np.sin(2 * np.pi * freq * time + phase)

            def background_model(time, height):
                return np.ones(len(time)) * height

            for i in np.arange(len(frequency_list)):

                if (i == 0):
                    model = lm.Model(lc_model,
                                     independent_vars=['time'],
                                     prefix='f{0:d}'.format(i))
                    model += lm.Model(background_model,
                                      independent_vars=['time'])
                else:
                    model += lm.Model(lc_model,
                                      independent_vars=['time'],
                                      prefix='f{0:d}'.format(i))

                model.set_param_hint('f{0:d}phase'.format(i),
                                     value=final_phases[i],
                                     vary=False)
                model.set_param_hint('f{0:d}amp'.format(i),
                                     value=initial_flux[i],
                                     vary=True)
                model.set_param_hint('height', value=np.mean(flux), vary=True)
                model.set_param_hint('f{0:d}freq'.format(i),
                                     value=frequency_list[i],
                                     vary=False)

            params = model.make_params()

            result = model.fit(corrected_lc.flux.value, params, time=times)

            return result

        heats = []
        heats_error = []
        #Iterating through columns of pixels
        for i in np.arange(0, len(self.aperture)):

            #Iterating through rows of pixels
            for j in np.arange(0, len(self.aperture[0])):

                #Making an empty 2-d array
                mask = np.zeros((len(self.aperture), len(self.aperture[0])),
                                dtype=bool)

                #Iterating to isolate pixel by pixel to get light curves
                mask[i][j] = True

                #Getting the light curve for a pixel and excluding any flagged data
                lightcurve = self.tpf.to_lightcurve(aperture_mask=mask)
                rcc = lk.RegressionCorrector(lightcurve)
                lc = rcc.correct(self.dm.append_constant())
                #lc = lc[np.where(lc.quality == 0)]
                #lc = lc.remove_outliers()

                bestfit = Obtain_Final_Fit(self.tpf, lc, self.frequency_list,
                                           self.final_phases)
                heat = np.asarray([
                    bestfit.best_values['f{0:d}amp'.format(n)]
                    for n in np.arange(len(self.frequency_list))
                ])
                #heat = bestfit.best_values['f0amp']# / bestfit.params['f0amp'].stderr
                heat_error = np.asarray([
                    bestfit.params['f{0:d}amp'.format(n)].stderr
                    for n in np.arange(len(self.frequency_list))
                ])

                #Extending the list of fitting data for each pixel
                heats.extend([heat])
                heats_error.extend([heat_error])

        #Taking the final list and turning it into a 2-d numpy array with the same dimensions of the full postage stamp
        #heats = np.reshape(np.asarray(heats),(len(self.aperture),len(self.aperture[0])))
        #heats_error = np.reshape(np.asarray(heats_error),(len(self.aperture),len(self.aperture[0])))
        heats = np.asarray(heats)
        heats_error = np.asarray(heats_error)

        #Defining self.periodogram as this 2-d array of periodogram data
        self.heatmap = heats.T
        self.heatmap_error = heats_error.T
        self.timeserieslength = (self.tpf.time.max() -
                                 self.tpf.time.min()).value
        self.gaiadata = None

        if (gaia == True):
            """Make the Gaia Figure Elements"""
            # Get the positions of the Gaia sources
            c1 = SkyCoord(self.tpf.ra, self.tpf.dec, frame='icrs', unit='deg')
            # Use pixel scale for query size
            pix_scale = 4.0  # arcseconds / pixel for Kepler, default
            if self.tpf.mission == 'TESS':
                pix_scale = 21.0
            # We are querying with a diameter as the radius, overfilling by 2x.
            from astroquery.vizier import Vizier
            Vizier.ROW_LIMIT = -1
            result = Vizier.query_region(
                c1,
                catalog=["I/345/gaia2"],
                radius=Angle(np.max(self.tpf.shape[1:]) * pix_scale, "arcsec"))

            no_targets_found_message = ValueError(
                'Either no sources were found in the query region '
                'or Vizier is unavailable')
            too_few_found_message = ValueError(
                'No sources found brighter than {:0.1f}'.format(
                    magnitude_limit))
            if result is None:
                raise no_targets_found_message
            elif len(result) == 0:
                raise too_few_found_message
            result = result["I/345/gaia2"].to_pandas()

            result = result[result.Gmag < magnitude_limit]
            if len(result) == 0:
                raise no_targets_found_message

            year = ((self.tpf.time[0].jd - 2457206.375) * u.day).to(u.year)
            pmra = ((np.nan_to_num(np.asarray(result.pmRA)) *
                     u.milliarcsecond / u.year) * year).to(u.deg).value
            pmdec = ((np.nan_to_num(np.asarray(result.pmDE)) *
                      u.milliarcsecond / u.year) * year).to(u.deg).value
            result.RA_ICRS += pmra
            result.DE_ICRS += pmdec
            radecs = np.vstack([result['RA_ICRS'], result['DE_ICRS']]).T
            coords = self.tpf.wcs.all_world2pix(radecs, 0)

            # Gently size the points by their Gaia magnitude
            sizes = 64.0 / 2**(result['Gmag'] / 5.0)
            one_over_parallax = 1.0 / (result['Plx'] / 1000.)
            source = dict(ra=result['RA_ICRS'],
                          dec=result['DE_ICRS'],
                          source=result['Source'].astype(str),
                          Gmag=result['Gmag'],
                          plx=result['Plx'],
                          one_over_plx=one_over_parallax,
                          x=coords[:, 0],
                          y=coords[:, 1],
                          size=sizes)

            self.gaiadata = source

        class frequency_heatmap:
            def __init__(self, tpf, heats, heats_error, frequencies,
                         gaia_data):
                self.heat_stamp = heats
                self.gaiadata = gaia_data
                self.heatmap_error = heats_error
                self.size = tpf.pipeline_mask.shape
                self.frequencies = frequencies

            def centroid(self):

                #Residuals to minimize relative to the error bars
                def residual(params, amp, amperr):

                    x = params['x']
                    y = params['y']
                    sigma = params['sigma']

                    xpix, ypix = np.meshgrid(np.arange(self.size[0]),
                                             np.arange(self.size[1]))

                    res = []
                    for i in np.arange(len(self.frequencies)):
                        height = params['height{0:d}'.format(i)]

                        model = height * np.exp(-(((x - xpix) / sigma)**2 +
                                                  ((y - ypix) / sigma)**2) / 2)

                        res.extend([(amp[i].reshape(self.size) - model) /
                                    amperr[i].reshape(self.size)])

                    return np.asarray(res)

                #Set starting values to converge from
                self.heatmap_error[np.where(
                    self.heatmap_error == None)] = np.nan
                composite_heatmap = self.heat_stamp.sum(axis=0).reshape(
                    self.size) / ((np.nansum(
                        self.heatmap_error**2, axis=0))**(1 / 2)).reshape(
                            self.size)  #issue with numpy using sqrt?
                c = np.where(composite_heatmap == composite_heatmap.max())
                params = Parameters()
                for i in np.arange(len(frequencies)):
                    params.add('height{0:d}'.format(i),
                               value=np.max(self.heat_stamp[i]))
                params.add('x', value=c[1][0])
                params.add('y', value=c[0][0])
                params.add('sigma', value=1)

                #Do the fit
                minner = Minimizer(residual,
                                   params,
                                   fcn_args=(self.heat_stamp,
                                             self.heatmap_error))
                self.result = minner.minimize()
                fit = self.result.params.valuesdict()
                self.x = fit['x']
                self.y = fit['y']

            def star_list(self):
                gaia_data = self.gaiadata
                no_gaia_data_message = ValueError(
                    'No gaia data initialized in PixelMapPeriodogram class')
                if gaia_data == None:
                    raise no_gaia_data_message

                else:
                    distances = np.square(self.x - gaia_data['x']) + np.square(
                        self.y - gaia_data['y'])
                    closest_star_mask = np.where(
                        np.square(self.x - gaia_data['x']) +
                        np.square(self.y - gaia_data['y']) == (
                            np.square(self.x - gaia_data['x']) +
                            np.square(self.y - gaia_data['y'])).min())
                    stars = dict(
                        ra=np.asarray(gaia_data['ra']),
                        dec=np.asarray(gaia_data['dec']),
                        source=np.asarray(gaia_data['source']),
                        x=np.asarray(gaia_data['x']),
                        y=np.asarray(gaia_data['y']),
                        distance=distances,
                        probability=2 * stats.norm.sf(
                            distances,
                            scale=np.sqrt(self.result.params['x'].stderr**2 +
                                          self.result.params['y'].stderr**2))
                    )  #I believe mutiply by 2 since we wont have a negative distance
                    starlist = pd.DataFrame.from_dict(stars)
                    self.stars = starlist.sort_values(by=[r'distance'])

        fh = frequency_heatmap(self.tpf, self.heatmap, self.heatmap_error,
                               self.frequency_list, self.gaiadata)
        fh.centroid()
        fh.star_list()
        self.centroid = [fh.x, fh.y]
        self.heatmap = self.heatmap.sum(axis=0).reshape(
            self.aperture.shape[0], self.aperture.shape[1]) / np.sqrt(
                (self.heatmap_error**2).sum(axis=0)).reshape(
                    self.aperture.shape[0], self.aperture.shape[1])
        self.starfit = fh.stars.reset_index()
        self.result = fh.result
 def build(self, object_info, sherlock_dir):
     mission_id = object_info.mission_id()
     sherlock_id = object_info.sherlock_id()
     quarters = None
     sectors = None
     logging.info("Retrieving star catalog info...")
     mission, mission_prefix, id = super().parse_object_id(mission_id)
     if mission_prefix not in self.star_catalogs:
         raise ValueError("Wrong object id " + mission_id)
     star_info = starinfo.StarInfo(
         sherlock_id, *self.star_catalogs[mission_prefix].catalog_info(id))
     logging.info("Downloading lightcurve files...")
     sectors = None if object_info.sectors == 'all' or mission != "TESS" else object_info.sectors
     quarters = None if object_info.sectors == 'all' or mission != "K2" else object_info.sectors
     campaigns = None if object_info.sectors == 'all' or mission != "Kepler" else object_info.sectors
     if object_info.aperture_file is None:
         lcf = lk.search_lightcurve(str(mission_id), mission=mission, cadence="short",
                                        sector=sectors, quarter=quarters,
                                        campaign=campaigns, author=self.authors[mission])\
             .download_all()
         if lcf is None:
             raise ObjectProcessingError(
                 "Light curve not found for object id " + mission_id)
         lc = None
         matching_objects = []
         for i in range(0, len(lcf.PDCSAP_FLUX)):
             if lcf.PDCSAP_FLUX[i].label == mission_id:
                 if lc is None:
                     lc = lcf.PDCSAP_FLUX[i].normalize()
                 else:
                     lc = lc.append(lcf.PDCSAP_FLUX[i].normalize())
             else:
                 matching_objects.append(lcf.PDCSAP_FLUX[i].label)
         if len(matching_objects) > 0:
             logging.warning(
                 "================================================")
             logging.warning("TICS IN THE SAME PIXEL: " +
                             str(matching_objects))
             logging.warning(
                 "================================================")
         lc = lc.remove_nans()
         transits_min_count = self.__calculate_transits_min_count(len(lcf))
         if mission_prefix == self.MISSION_ID_KEPLER or mission_id == self.MISSION_ID_KEPLER_2:
             quarters = [lcfile.quarter for lcfile in lcf]
         elif mission_prefix == self.MISSION_ID_TESS:
             sectors = [file.sector for file in lcf]
         if mission_prefix == self.MISSION_ID_KEPLER_2:
             logging.info("Correcting K2 motion in light curve...")
             quarters = [lcfile.campaign for lcfile in lcf]
             lc = lc.to_corrector("sff").correct(windows=20)
         return lc, star_info, transits_min_count, np.unique(
             sectors), np.unique(quarters)
     else:
         logging.info("Using user apertures!")
         tpfs = lk.search_targetpixelfile(
             str(mission_id),
             mission=mission,
             cadence="short",
             sector=sectors,
             quarter=quarters,
             campaign=campaigns,
             author=authors[mission]).download_all()
         apertures = {}
         if isinstance(object_info.aperture_file, str):
             aperture = []
             with open(object_info.aperture_file, 'r') as fd:
                 reader = csv.reader(fd)
                 for row in reader:
                     aperture.append(row)
                 aperture = np.array(aperture)
             for tpf in tpfs:
                 if mission_prefix == self.MISSION_ID_KEPLER:
                     apertures[tpf.quarter] = aperture
                 elif mission_prefix == self.MISSION_ID_TESS:
                     apertures[tpf.sector] = aperture
                 elif mission_prefix == self.MISSION_ID_KEPLER_2:
                     apertures[tpf.campaign] = aperture
         else:
             for sector, aperture_file in object_info.aperture_file.items():
                 aperture = []
                 with open(aperture_file, 'r') as fd:
                     reader = csv.reader(fd)
                     for row in reader:
                         aperture.append(row)
                 aperture = np.array(aperture)
                 apertures[sector] = aperture
         lc = None
         for tpf in tpfs:
             if mission_prefix == self.MISSION_ID_KEPLER:
                 sector = tpf.quarter
             elif mission_prefix == self.MISSION_ID_TESS:
                 sector = tpf.sector
             elif mission_prefix == self.MISSION_ID_KEPLER_2:
                 sector = tpf.campaign
             aperture = apertures[sector].astype(bool)
             tpf.plot(aperture_mask=aperture, mask_color='red')
             plt.savefig(sherlock_dir + "/Aperture_[" + str(sector) +
                         "].png")
             plt.close()
             if mission_prefix == self.MISSION_ID_KEPLER:
                 corrector = lk.KeplerCBVCorrector(tpf)
                 corrector.plot_cbvs([1, 2, 3, 4, 5, 6, 7])
                 raw_lc = tpf.to_lightcurve(
                     aperture_mask=aperture).remove_nans()
                 plt.savefig(sherlock_dir + "/Corrector_components[" +
                             str(sector) + "].png")
                 plt.close()
                 it_lc = corrector.correct([1, 2, 3, 4, 5])
                 ax = raw_lc.plot(color='C3',
                                  label='SAP Flux',
                                  linestyle='-')
                 it_lc.plot(ax=ax,
                            color='C2',
                            label='CBV Corrected SAP Flux',
                            linestyle='-')
                 plt.savefig(sherlock_dir + "/Raw_vs_CBVcorrected_lc[" +
                             str(sector) + "].png")
                 plt.close()
             elif mission_prefix == self.MISSION_ID_KEPLER_2:
                 raw_lc = tpf.to_lightcurve(
                     aperture_mask=aperture).remove_nans()
                 it_lc = raw_lc.to_corrector("sff").correct(windows=20)
                 ax = raw_lc.plot(color='C3',
                                  label='SAP Flux',
                                  linestyle='-')
                 it_lc.plot(ax=ax,
                            color='C2',
                            label='CBV Corrected SAP Flux',
                            linestyle='-')
                 plt.savefig(sherlock_dir + "/Raw_vs_SFFcorrected_lc[" +
                             str(sector) + "].png")
                 plt.close()
             elif mission_prefix == self.MISSION_ID_TESS:
                 temp_lc = tpf.to_lightcurve(aperture_mask=aperture)
                 where_are_NaNs = np.isnan(temp_lc.flux)
                 temp_lc = temp_lc[np.where(~where_are_NaNs)]
                 regressors = tpf.flux[np.argwhere(~where_are_NaNs),
                                       ~aperture]
                 temp_token_lc = [
                     temp_lc[i:i + 2000]
                     for i in range(0, len(temp_lc), 2000)
                 ]
                 regressors_token = [
                     regressors[i:i + 2000]
                     for i in range(0, len(regressors), 2000)
                 ]
                 it_lc = None
                 raw_it_lc = None
                 item_index = 0
                 for temp_token_lc_item in temp_token_lc:
                     regressors_token_item = regressors_token[item_index]
                     design_matrix = lk.DesignMatrix(
                         regressors_token_item,
                         name='regressors').pca(5).append_constant()
                     corr_lc = lk.RegressionCorrector(
                         temp_token_lc_item).correct(design_matrix)
                     if it_lc is None:
                         it_lc = corr_lc
                         raw_it_lc = temp_token_lc_item
                     else:
                         it_lc = it_lc.append(corr_lc)
                         raw_it_lc = raw_it_lc.append(temp_token_lc_item)
                     item_index = item_index + 1
                 ax = raw_it_lc.plot(label='Raw light curve')
                 it_lc.plot(ax=ax, label='Corrected light curve')
                 plt.savefig(sherlock_dir + "/Raw_vs_DMcorrected_lc[" +
                             str(sector) + "].png")
                 plt.close()
             if lc is None:
                 lc = it_lc.normalize()
             else:
                 lc = lc.append(it_lc.normalize())
         lc = lc.remove_nans()
         lc.plot(label="Normalized light curve")
         plt.savefig(sherlock_dir + "/Normalized_lc[" + str(sector) +
                     "].png")
         plt.close()
         transits_min_count = self.__calculate_transits_min_count(len(tpfs))
         if mission_prefix == self.MISSION_ID_KEPLER or mission_id == self.MISSION_ID_KEPLER_2:
             quarters = [lcfile.quarter for lcfile in tpfs]
         elif mission_prefix == self.MISSION_ID_TESS:
             sectors = [file.sector for file in tpfs]
         if mission_prefix == self.MISSION_ID_KEPLER_2:
             logging.info("Correcting K2 motion in light curve...")
             quarters = [lcfile.campaign for lcfile in tpfs]
         return lc, star_info, transits_min_count, np.unique(
             sectors), np.unique(quarters)