コード例 #1
0
def build_ktransit_model(ticid, lc, rprs=0.02, vary_transit=True):
    from ktransit import FitTransit
    fitT = FitTransit()

    model = BoxLeastSquares(lc.time, lc.flux)
    results = model.autopower(0.16, minimum_period=2., maximum_period=21.)
    period = results.period[np.argmax(results.power)]
    t0 = results.transit_time[np.argmax(results.power)]
    if rprs is None:
        depth = results.depth[np.argmax(results.power)]
        rprs = depth ** 2

    fitT.add_guess_star(rho=0.022, zpt=0, ld1=0.6505,ld2=0.1041) #come up with better way to estimate this using AS
    fitT.add_guess_planet(T0=t0, period=period, impact=0.5, rprs=rprs)

    ferr = np.ones_like(lc.time) * 0.00001
    fitT.add_data(time=lc.time,flux=lc.flux,ferr=ferr)#*1e-3)

    vary_star = ['zpt']      # free stellar parameters
    if vary_transit:
        vary_planet = (['period', 'impact',       # free planetary parameters
            'T0', #'esinw', 'ecosw',
            'rprs']) #'impact',               # free planet parameters are the same for every planet you model
    else:
        vary_planet = (['rprs'])

    fitT.free_parameters(vary_star, vary_planet)
    fitT.do_fit()                   # run the fitting

    return fitT
コード例 #2
0
ファイル: giants.py プロジェクト: skgrunblatt/giants
    def pdf_summary(self, ticid, out_fname):
        """

        """
        self.ticid = ticid
        with PdfPages(out_fname) as pdf:

            ql_fig = self.plot(self.ticid, save_postcard=True)
            pdf.savefig(ql_fig)
            plt.close()
            lc = self.lc

            time, flux, flux_err = lc.time, lc.flux, lc.flux_err

            model = BoxLeastSquares(time, flux)
            results = model.autopower(0.16,
                                      minimum_period=2.,
                                      maximum_period=21.)
            period = results.period[np.argmax(results.power)]
            t0 = results.transit_time[np.argmax(results.power)]

            vt_fig = plot_transit_vetting(self.ticid, period, t0, lc=self.lc)
            pdf.savefig(vt_fig)
            plt.close()

            ica_fig = make_ica_plot(self.ticid)
            pdf.savefig(ica_fig)
            plt.close()

            star_fig = self.plot_starry_model(lc)
            pdf.savefig(star_fig)
            plt.close()
コード例 #3
0
def periodogram(time, lightcurve):
    
    period_grid = np.exp(np.linspace(np.log(1), np.log(15), 50000))
    
    bls = BoxLeastSquares(time, lightcurve)
    bls_power = bls.power(period_grid, 0.1, oversample=20)
    return bls, bls_power, period_grid
コード例 #4
0
def make_transit_periodogram(t, y, dy=0.01):
    """
    Plots a periodogram to determine likely period of planet transit candidtaes 
    in a dataset, based on a box least squared method.
    """
    model = BoxLeastSquares(t * u.day, y, dy=0.01)
    periodogram = model.autopower(0.2, objective="snr")
    plt.figure()
    plt.plot(periodogram.period, periodogram.power, 'k')
    plt.xlabel('Period [days]')
    plt.ylabel('Power')
    max_power_i = np.argmax(periodogram.power)
    best_fit = periodogram.period[max_power_i]
    print('Best Fit Period: {} days'.format(best_fit))
    stats = model.compute_stats(periodogram.period[max_power_i],
                                periodogram.duration[max_power_i],
                                periodogram.transit_time[max_power_i])
    return stats, best_fit
コード例 #5
0
def get_bls_features(x, t):
    features = []
    # print(x[0])
    for i in range(x.shape[0]):
        # adapted from http://docs.astropy.org/en/stable/stats/bls.html#peak-statistics
        bls = BoxLeastSquares(t, x[i])
        periodogram = bls.autopower(
            40, minimum_n_transit=5
        )  # arg is the granularity of considered durations
        max_power = np.argmax(periodogram.power)
        stats = bls.compute_stats(periodogram.period[max_power],
                                  periodogram.duration[max_power],
                                  periodogram.transit_time[max_power])
        # TODO: use dataframe?
        features.append([stats[s][0] / stats[s][1] for s in stat_names])
        # based on https://arxiv.org/pdf/astro-ph/0206099.pdf
        #         ratios.append(stats["depth"][0] / stats["depth"][1])  # depth over uncertainty
        if (i + 1) % 10 == 0:
            print(".", end="")
        if (i + 1) % 500 == 0:
            print()
    print()
    return np.array(features)
コード例 #6
0
ファイル: abls.py プロジェクト: JinbiaoJi/astrobase
def _parallel_bls_worker(task):
    '''
    This wraps Astropy's BoxLeastSquares for use with bls_parallel_pfind below.

    `task` is a tuple::

        task[0] = times
        task[1] = mags
        task[2] = errs
        task[3] = magsarefluxes

        task[4] = minfreq
        task[5] = nfreq
        task[6] = stepsize

        task[7] = ndurations
        task[8] = mintransitduration
        task[9] = maxtransitduration

        task[10] = blsobjective
        task[11] = blsmethod
        task[12] = blsoversample

    '''

    try:

        times, mags, errs = task[:3]
        magsarefluxes = task[3]

        minfreq, nfreq, stepsize = task[4:7]

        ndurations, mintransitduration, maxtransitduration = task[7:10]

        blsobjective, blsmethod, blsoversample = task[10:]

        frequencies = minfreq + nparange(nfreq) * stepsize
        periods = 1.0 / frequencies

        # astropy's BLS requires durations in units of time
        durations = nplinspace(mintransitduration * periods.min(),
                               maxtransitduration * periods.min(), ndurations)

        # set up the correct units for the BLS model
        if magsarefluxes:

            blsmodel = BoxLeastSquares(times * u.day,
                                       mags * u.dimensionless_unscaled,
                                       dy=errs * u.dimensionless_unscaled)

        else:

            blsmodel = BoxLeastSquares(times * u.day,
                                       mags * u.mag,
                                       dy=errs * u.mag)

        blsresult = blsmodel.power(periods * u.day,
                                   durations * u.day,
                                   objective=blsobjective,
                                   method=blsmethod,
                                   oversample=blsoversample)

        return {
            'blsresult': blsresult,
            'blsmodel': blsmodel,
            'durations': durations,
            'power': nparray(blsresult.power)
        }

    except Exception as e:

        LOGEXCEPTION('BLS for frequency chunk: (%.6f, %.6f) failed.' %
                     (frequencies[0], frequencies[-1]))

        return {
            'blsresult': None,
            'blsmodel': None,
            'durations': durations,
            'power': nparray([npnan for x in range(nfreq)]),
        }
コード例 #7
0
    def from_lightcurve(lc, **kwargs):
        """Creates a Periodogram from a LightCurve using the Box Least Squares (BLS) method."""
        time_unit = (kwargs.pop("time_unit", "day"))
        if time_unit not in dir(u):
            raise ValueError('{} is not a valid unit for time.'.format(time_unit))

        try:
            from astropy.stats import BoxLeastSquares
        except ImportError:
            raise Exception("BLS requires AstroPy v3.1 or later")

        # BoxLeastSquares will not work if flux or flux_err contain NaNs
        lc = lc.remove_nans()
        if np.isfinite(lc.flux_err).all():
            dy = lc.flux_err
        else:
            dy = None

        bls = BoxLeastSquares(lc.time, lc.flux, dy)
        duration = kwargs.pop("duration", 0.25)
        minimum_period = kwargs.pop("minimum_period", None)
        maximum_period = kwargs.pop("maximum_period", None)
        period = kwargs.pop("period", None)
        if minimum_period is None:
            if 'period' in kwargs:
                minimum_period = period.min()
            else:
                minimum_period = np.max([np.median(np.diff(lc.time)) * 4,
                                         np.max(duration) + np.median(np.diff(lc.time))])
        if maximum_period is None:
            if 'period' in kwargs:
                maximum_period = period.max()
            else:
                maximum_period = (np.max(lc.time) - np.min(lc.time)) / 3.

        frequency_factor = kwargs.pop("frequency_factor", 10)
        df = frequency_factor * np.min(duration) / (np.max(lc.time) - np.min(lc.time))**2
        npoints = int(((1/minimum_period) - (1/maximum_period))/df)

        # Too many points
        if npoints > 1e5:
            log.warning('`period` contains {} points.'
                        'Periodogram is likely to be large, and slow to evaluate. '
                        'Consider setting `frequency_factor` to a higher value.'
                        ''.format(np.round(npoints, 4)))

        # Way too many points
        if npoints > 1e7:
            raise ValueError('`period` contains {} points.'
                             'Periodogram is too large to evaluate. '
                             'Consider setting `frequency_factor` to a higher value.'
                             ''.format(np.round(npoints, 4)))

        period = kwargs.pop("period",
                            bls.autoperiod(duration,
                                           minimum_period=minimum_period,
                                           maximum_period=maximum_period,
                                           frequency_factor=frequency_factor))

        result = bls.power(period, duration, **kwargs)
        if not isinstance(result.period, u.quantity.Quantity):
            result.period = u.Quantity(result.period, time_unit)
        if not isinstance(result.power, u.quantity.Quantity):
            result.power = result.power * u.dimensionless_unscaled

        return BoxLeastSquaresPeriodogram(frequency=1. / result.period,
                                          power=result.power,
                                          default_view='period',
                                          label=lc.label,
                                          targetid=lc.targetid,
                                          transit_time=result.transit_time,
                                          duration=result.duration,
                                          depth=result.depth,
                                          bls_result=result,
                                          snr=result.depth_snr,
                                          bls_obj=bls,
                                          time=lc.time,
                                          flux=lc.flux,
                                          time_unit=time_unit)
コード例 #8
0
f = []

for fn in files:
    ti, fi = np.genfromtxt(fn, usecols=(0,1), unpack=True)
    t.append(ti)
    f.append(fi / np.nanmedian(fi))

t = np.concatenate(t)
f = np.concatenate(f)

fig, ax = plt.subplots(figsize=[15,3])
ax.plot(t, f, '-k', lw=1, zorder=-2)
ax.scatter(t, f, c='gold', edgecolor='black', s=15, lw=.5, zorder=-1)

durations = np.linspace(0.05, 0.2, 50)# * u.day
model     = BLS(t,f)
result    = model.autopower(durations, frequency_factor=5.0, maximum_period=30.0)
idx       = np.argmax(result.power)

period = result.period[idx]
t0     = result.transit_time[idx]
dur    = result.duration[idx]
depth  = result.depth[idx]

ph = (t - t0 + 0.5*period) % period - 0.5*period

fig2, ax2 = plt.subplots(figsize=[8,2])
ax2.scatter(ph, f, c='gold', edgecolor='black', s=15, lw=.5)

plt.show()
コード例 #9
0
    def build_model(x, y, yerr, period_prior, t0_prior, depth, minimum_period=2, maximum_period=30, r_star_prior=5.0, t_star_prior=5000, m_star_prior=None, start=None):
        """Build an exoplanet model for a dataset and set of planets

        Paramters
        ---------
        x : array-like
            The time series (in days); this should probably be centered
        y : array-like
            The relative fluxes (in parts per thousand)
        yerr : array-like
            The uncertainties on ``y``
        period_prior : list
            The literature values for periods of the planets (in days)
        t0_prior : list
            The literature values for phases of the planets in the same
            coordinates as `x`
        rprs_prior : list
            The literature values for the ratio of planet radius to star
            radius
        start : dict
            A dictionary of model parameters where the optimization
            should be initialized

        Returns:
            A PyMC3 model specifying the probabilistic model for the light curve

        """

        model = BoxLeastSquares(x, y)
        results = model.autopower(0.16, minimum_period=minimum_period, maximum_period=maximum_period)
        if period_prior is None:
            period_prior = results.period[np.argmax(results.power)]
        if t0_prior is None:
            t0_prior = results.transit_time[np.argmax(results.power)]
        if depth is None:
            depth = results.depth[np.argmax(results.power)]

        period_prior = np.atleast_1d(period_prior)
        t0_prior = np.atleast_1d(t0_prior)
        # rprs_prior = np.atleast_1d(rprs_prior)

        with pm.Model() as model:

            # Set model variables
            model.x = np.asarray(x, dtype=np.float64)
            model.y = np.asarray(y, dtype=np.float64)
            model.yerr = np.asarray(yerr + np.zeros_like(x), dtype=np.float64)

            '''Stellar Parameters'''
            # The baseline (out-of-transit) flux for the star in ppt
            mean = pm.Normal("mean", mu=0.0, sd=10.0)

            try:
                r_star_mu = target_list[target_list['ID'] == ticid]['rad'].values[0]
            except:
                r_star_mu = r_star_prior
            if m_star_prior is None:
                try:
                    m_star_mu = target_list[target_list['ID'] == ticid]['mass'].values[0]
                except:
                    m_star_mu = 1.2
                if np.isnan(m_star_mu):
                    m_star_mu = 1.2
            else:
                m_star_mu = m_star_prior
            r_star = pm.Normal("r_star", mu=r_star_mu, sd=1.)
            m_star = pm.Normal("m_star", mu=m_star_mu, sd=1.)
            t_star = pm.Normal("t_star", mu=t_star_prior, sd=200)
            rho_star_mu = ((m_star_mu*u.solMass).to(u.g) / ((4/3) * np.pi * ((r_star_mu*u.solRad).to(u.cm))**3)).value
            rho_star = pm.Normal("rho_star", mu=rho_star_mu, sd=.25)

            '''Orbital Parameters'''
            # The time of a reference transit for each planet
            t0 = pm.Normal("t0", mu=t0_prior, sd=2., shape=1)
            period = pm.Uniform("period", testval=period_prior,
                                lower=minimum_period,
                                upper=maximum_period,
                                shape=1)

            b = pm.Uniform("b", testval=0.5, shape=1)

            # Set up a Keplerian orbit for the planets
            model.orbit = xo.orbits.KeplerianOrbit(
                period=period, t0=t0, b=b, r_star=r_star, m_star=m_star)#rho_star=rho_star)

            # track additional orbital parameters
            a = pm.Deterministic("a", model.orbit.a)
            incl = pm.Deterministic("incl", model.orbit.incl)

            '''Planet Parameters'''
            # quadratic limb darkening paramters
            u_ld = xo.distributions.QuadLimbDark("u_ld")

            estimated_rpl = r_star*(depth)**(1/2)

            # logr = pm.Normal("logr", testval=np.log(estimated_rpl), sd=1.)
            r_pl = pm.Uniform("r_pl",
                              testval=estimated_rpl,
                              lower=0.,
                              upper=1.)

            # r_pl = pm.Deterministic("r_pl", tt.exp(logr))
            rprs = pm.Deterministic("rprs", r_pl / r_star)
            teff = pm.Deterministic('teff', t_star * tt.sqrt(0.5*(1/a)))

            # Compute the model light curve using starry
            model.light_curves = xo.StarryLightCurve(u_ld).get_light_curve(
                                    orbit=model.orbit, r=r_pl, t=model.x)

            model.light_curve = pm.math.sum(model.light_curves, axis=-1) + mean


            pm.Normal("obs",
                      mu=model.light_curve,
                      sd=model.yerr,
                      observed=model.y)

            # Fit for the maximum a posteriori parameters, I've found that I can get
            # a better solution by trying different combinations of parameters in turn
            if start is None:
                start = model.test_point
            map_soln = xo.optimize(start=start, vars=[period, t0])
            map_soln = xo.optimize(start=map_soln, vars=[r_pl, mean])
            map_soln = xo.optimize(start=map_soln, vars=[period, t0, mean])
            map_soln = xo.optimize(start=map_soln, vars=[r_pl, mean])
            map_soln = xo.optimize(start=map_soln)
            model.map_soln = map_soln

        return model
コード例 #10
0
ファイル: plotting.py プロジェクト: skgrunblatt/giants
def plot_quicklook(lc, ticid, breakpoints, target_list, save_data=True, outdir=None):

    if outdir is None:
        outdir = os.path.join(self.PACKAGEDIR, 'outputs')

    time, flux, flux_err = lc.time, lc.flux, lc.flux_err

    model = BoxLeastSquares(time, flux)
    results = model.autopower(0.16, minimum_period=2., maximum_period=21.)
    period = results.period[np.argmax(results.power)]
    t0 = results.transit_time[np.argmax(results.power)]
    depth = results.depth[np.argmax(results.power)]
    depth_snr = results.depth_snr[np.argmax(results.power)]

    '''
    Plot Filtered Light Curve
    -------------------------
    '''
    plt.subplot2grid((4,4),(1,0),colspan=2)

    plt.plot(time, flux, 'k', label="filtered")
    for val in breakpoints:
        plt.axvline(val, c='b', linestyle='dashed')
    plt.legend()
    plt.ylabel('Normalized Flux')
    plt.xlabel('Time')

    osample=5.
    nyq=283.

    # calculate FFT
    freq, amp, nout, jmax, prob = lomb.fasper(time, flux, osample, 3.)
    freq = 1000. * freq / 86.4
    bin = freq[1] - freq[0]
    fts = 2. * amp * np.var(flux * 1e6) / (np.sum(amp) * bin)

    use = np.where(freq < nyq + 150)
    freq = freq[use]
    fts = fts[use]

    # calculate ACF
    acf = np.correlate(fts, fts, 'same')
    freq_acf = np.linspace(-freq[-1], freq[-1], len(freq))

    fitT = build_ktransit_model(ticid=ticid, lc=lc, vary_transit=False)
    dur = _individual_ktransit_dur(fitT.time, fitT.transitmodel)

    freq = freq
    fts1 = fts/np.max(fts)
    fts2 = scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 5)
    fts3 = scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 50)

    '''
    Plot Periodogram
    ----------------
    '''
    plt.subplot2grid((4,4),(0,2),colspan=2,rowspan=4)
    plt.loglog(freq, fts/np.max(fts))
    plt.loglog(freq, scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 5), color='C1', lw=2.5)
    plt.loglog(freq, scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 50), color='r', lw=2.5)
    plt.axvline(283,-1,1, ls='--', color='k')
    plt.xlabel("Frequency [uHz]")
    plt.ylabel("Power")
    plt.xlim(10, 400)
    plt.ylim(1e-4, 1e0)

    # annotate with transit info
    font = {'family':'monospace', 'size':10}
    plt.text(10**1.04, 10**-3.50, f'depth = {depth:.4f}        ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    plt.text(10**1.04, 10**-3.62, f'depth_snr = {depth_snr:.4f}    ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    plt.text(10**1.04, 10**-3.74, f'period = {period:.3f} days    ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    plt.text(10**1.04, 10**-3.86, f't0 = {t0:.3f}            ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    try:
        # annotate with stellar params
        # won't work for TIC ID's not in the list
        if isinstance(ticid, str):
            ticid = int(re.search(r'\d+', str(ticid)).group())
        Gmag = target_list[target_list['ID'] == ticid]['GAIAmag'].values[0]
        Teff = target_list[target_list['ID'] == ticid]['Teff'].values[0]
        R = target_list[target_list['ID'] == ticid]['rad'].values[0]
        M = target_list[target_list['ID'] == ticid]['mass'].values[0]
        plt.text(10**1.7, 10**-3.50, rf"G mag = {Gmag:.3f} ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
        plt.text(10**1.7, 10**-3.62, rf"Teff = {int(Teff)} K  ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
        plt.text(10**1.7, 10**-3.74, rf"R = {R:.3f} $R_\odot$  ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
        plt.text(10**1.7, 10**-3.86, rf"M = {M:.3f} $M_\odot$    ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    except:
        pass

    # plot ACF inset
    ax = plt.gca()
    axins = inset_axes(ax, width=2.0, height=1.4)
    axins.plot(freq_acf, acf)
    axins.set_xlim(1,25)
    axins.set_xlabel("ACF [uHz]")

    '''
    Plot BLS
    --------
    '''
    plt.subplot2grid((4,4),(2,0),colspan=2)

    plt.plot(results.period, results.power, "k", lw=0.5)
    plt.xlim(results.period.min(), results.period.max())
    plt.xlabel("period [days]")
    plt.ylabel("log likelihood")

    # Highlight the harmonics of the peak period
    plt.axvline(period, alpha=0.4, lw=4)
    for n in range(2, 10):
        plt.axvline(n*period, alpha=0.4, lw=1, linestyle="dashed")
        plt.axvline(period / n, alpha=0.4, lw=1, linestyle="dashed")

    phase = (t0 % period) / period
    foldedtimes = (((time - phase * period) / period) % 1)
    foldedtimes[foldedtimes > 0.5] -= 1
    foldtimesort = np.argsort(foldedtimes)
    foldfluxes = flux[foldtimesort]
    plt.subplot2grid((4,4), (3,0),colspan=2)
    plt.scatter(foldedtimes, flux, s=2)
    plt.plot(np.sort(foldedtimes), scipy.ndimage.filters.median_filter(foldfluxes, 40), lw=2, color='r', label=f'P={period:.2f} days, dur={dur:.2f} hrs')
    plt.xlabel('Phase')
    plt.ylabel('Flux')
    plt.xlim(-0.5, 0.5)
    plt.ylim(-0.0025, 0.0025)
    plt.legend(loc=0)

    fig = plt.gcf()
    fig.patch.set_facecolor('white')
    fig.suptitle(f'{ticid}', fontsize=14)
    fig.set_size_inches(10, 7)

    if save_data:
        np.savetxt(outdir+'/timeseries/'+str(ticid)+'.dat.ts', np.transpose([time, flux]), fmt='%.8f', delimiter=' ')
        np.savetxt(outdir+'/fft/'+str(ticid)+'.dat.ts.fft', np.transpose([freq, fts]), fmt='%.8f', delimiter=' ')
        with open(os.path.join(outdir,"transit_stats.txt"), "a+") as file:
            file.write(f"{ticid} {depth} {depth_snr} {period} {t0} {dur}\n")

    return fig
コード例 #11
0
ファイル: TESSdetrending.py プロジェクト: daxfeliz/SSMV-Felix
        data[d]))[0]  #first  (zero indexing in python) column
    mag = np.transpose(np.loadtxt(
        data[d]))[1]  #second (zero indexing in python) column
    magerror = np.transpose(np.loadtxt(
        data[d]))[2]  #third (zero indexing in python) column

    flux = 10.0**(mag / -2.5) / np.mean(10.0**(mag / -2.5))
    fluxerror = flux * (10.0**(magerror / 2.5) - 1.0)

    #detrending
    lc = lk.LightCurve(time, flux, fluxerror)
    detrended_lc = lc.flatten(window_length=window_size).bin(
        binsize=bin_size).remove_outliers(sigma=Nsig)

    #doing BLS search:
    bls = BoxLeastSquares(detrended_lc.time, detrended_lc.flux,
                          detrended_lc.flux_err)
    periods = np.arange(0.23,
                        (max(detrended_lc.time) - min(detrended_lc.time)), 0.1)
    durations = np.arange((1.0 / 24.0), (5.0 / 24.0), 0.1)  #1 hr to 5 hrs
    periodogram = bls.power(periods, durations, objective='snr')

    #phase folding with best BLS model
    index = np.argmax(periodogram.power)
    print(index)
    best_period = periodogram.period[index]
    print(best_period)
    best_t0 = periodogram.transit_time[index]
    print(best_t0)
    detrendedphasefoldedlc = [
        detrended_lc.fold(period=best_period, t0=best_t0).phase,
        detrended_lc.fold(period=best_period, t0=best_t0).flux,
コード例 #12
0
ファイル: tess_lightcurves.py プロジェクト: theakozakis/TESS
def tess_lightcurves(filename, TIC):

    import numpy as np
    from astropy.io import fits
    import matplotlib.pyplot as plt

    tpf_url = str(filename)
    with fits.open(tpf_url) as hdus:
        tpf = hdus[1].data
        tpf_hdr = hdus[1].header
        tpf_mask = hdus[2].data

    time = tpf["TIME"]
    flux = tpf["FLUX"]
    m = np.any(np.isfinite(flux), axis=(1, 2)) & (tpf["QUALITY"] == 0)
    time = np.ascontiguousarray(time[m] - np.min(time[m]), dtype=np.float64)
    flux = np.ascontiguousarray(flux[m], dtype=np.float64)

    mean_img = np.median(flux, axis=0)
    plt.imshow(mean_img.T, cmap="gray_r")
    plt.title("TESS image of Pi Men")
    plt.xticks([])
    plt.yticks([])

    from scipy.signal import savgol_filter

    # Sort the pixels by median brightness
    order = np.argsort(mean_img.flatten())[::-1]

    # A function to estimate the windowed scatter in a lightcurve
    def estimate_scatter_with_mask(mask):
        f = np.sum(flux[:, mask], axis=-1)
        smooth = savgol_filter(f, 1001, polyorder=5)
        return 1e6 * np.sqrt(np.median((f / smooth - 1)**2))

    # Loop over pixels ordered by brightness and add them one-by-one
    # to the aperture
    masks, scatters = [], []
    for i in range(10, 100):
        msk = np.zeros_like(tpf_mask, dtype=bool)
        msk[np.unravel_index(order[:i], mean_img.shape)] = True
        scatter = estimate_scatter_with_mask(msk)
        masks.append(msk)
        scatters.append(scatter)

    # Choose the aperture that minimizes the scatter
    pix_mask = masks[np.argmin(scatters)]

    # Plot the selected aperture
    plt.imshow(mean_img.T, cmap="gray_r")
    plt.imshow(pix_mask.T, cmap="Reds", alpha=0.3)
    plt.title("TIC" + str(TIC) + ": selected aperture ")
    plt.xticks([])
    plt.yticks([])
    #    plt.savefig('/Users/Admin/Documents/Research_Lisa/TESS/plots/'+str(TIC)+'_aperture.pdf')
    plt.close()

    plt.figure(figsize=(10, 5))
    sap_flux = np.sum(flux[:, pix_mask], axis=-1)
    sap_flux = (sap_flux / np.median(sap_flux) - 1) * 1e3
    plt.plot(time, sap_flux, "k")
    plt.xlabel("time [days]")
    plt.ylabel("relative flux [ppt]")
    plt.title("TIC" + str(TIC) + ": raw light curve")
    plt.xlim(time.min(), time.max())
    #    plt.savefig('/Users/Admin/Documents/Research_Lisa/TESS/plots/'+str(TIC)+'_raw_lc.pdf')
    plt.close()

    # Build the first order PLD basis
    X_pld = np.reshape(flux[:, pix_mask], (len(flux), -1))
    X_pld = X_pld / np.sum(flux[:, pix_mask], axis=-1)[:, None]

    # Build the second order PLD basis and run PCA to reduce the number of dimensions
    X2_pld = np.reshape(X_pld[:, None, :] * X_pld[:, :, None], (len(flux), -1))
    U, _, _ = np.linalg.svd(X2_pld, full_matrices=False)
    X2_pld = U[:, :X_pld.shape[1]]

    # Construct the design matrix and fit for the PLD model
    X_pld = np.concatenate((np.ones((len(flux), 1)), X_pld, X2_pld), axis=-1)
    XTX = np.dot(X_pld.T, X_pld)
    w_pld = np.linalg.solve(XTX, np.dot(X_pld.T, sap_flux))
    pld_flux = np.dot(X_pld, w_pld)

    # Plot the de-trended light curve
    plt.figure(figsize=(10, 5))
    plt.plot(time, sap_flux - pld_flux, "k")
    plt.xlabel("time [days]")
    plt.ylabel("de-trended flux [ppt]")
    plt.title("TIC" + str(TIC) + ": initial de-trended light curve")
    plt.xlim(time.min(), time.max())
    #    plt.savefig('/Users/Admin/Documents/Research_Lisa/TESS/plots/'+str(TIC)+'_detrend_lc.pdf')
    plt.close()

    from astropy.stats import BoxLeastSquares

    period_grid = np.exp(np.linspace(np.log(1), np.log(15), 50000))

    bls = BoxLeastSquares(time, sap_flux - pld_flux)
    bls_power = bls.power(period_grid, 0.1, oversample=20)

    # Save the highest peak as the planet candidate
    index = np.argmax(bls_power.power)
    bls_period = bls_power.period[index]
    bls_t0 = bls_power.transit_time[index]
    bls_depth = bls_power.depth[index]
    transit_mask = bls.transit_mask(time, bls_period, 0.2, bls_t0)

    fig, axes = plt.subplots(2, 1, figsize=(10, 10))

    # Plot the periodogram
    ax = axes[0]
    ax.axvline(np.log10(bls_period), color="C1", lw=5, alpha=0.8)
    ax.plot(np.log10(bls_power.period), bls_power.power, "k")
    ax.annotate("period = {0:.4f} d".format(bls_period), (0, 1),
                xycoords="axes fraction",
                xytext=(5, -5),
                textcoords="offset points",
                va="top",
                ha="left",
                fontsize=12)
    ax.set_ylabel("bls power")
    ax.set_yticks([])
    ax.set_xlim(np.log10(period_grid.min()), np.log10(period_grid.max()))
    ax.set_xlabel("log10(period)")

    # Plot the folded transit
    ax = axes[1]
    x_fold = (time - bls_t0 + 0.5 * bls_period) % bls_period - 0.5 * bls_period
    m = np.abs(x_fold) < 0.4
    ax.plot(x_fold[m], sap_flux[m] - pld_flux[m], ".k")

    # Overplot the phase binned light curve
    bins = np.linspace(-0.41, 0.41, 32)
    denom, _ = np.histogram(x_fold, bins)
    num, _ = np.histogram(x_fold, bins, weights=sap_flux - pld_flux)
    denom[num == 0] = 1.0
    ax.plot(0.5 * (bins[1:] + bins[:-1]), num / denom, color="C1")

    ax.set_xlim(-0.3, 0.3)
    ax.set_ylabel("de-trended flux [ppt]")
    ax.set_xlabel("time since transit")
    plt.title("TIC" + str(TIC))
    plt.savefig('/Users/Admin/Documents/Research_Lisa/TESS/plots/' + str(TIC) +
                '_period_detrend_lc.pdf')
    plt.close()

    m = ~transit_mask
    XTX = np.dot(X_pld[m].T, X_pld[m])
    w_pld = np.linalg.solve(XTX, np.dot(X_pld[m].T, sap_flux[m]))
    pld_flux = np.dot(X_pld, w_pld)

    x = np.ascontiguousarray(time, dtype=np.float64)
    y = np.ascontiguousarray(sap_flux - pld_flux, dtype=np.float64)

    plt.figure(figsize=(10, 5))
    plt.plot(time, y, "k")
    plt.xlabel("time [days]")
    plt.ylabel("de-trended flux [ppt]")
    plt.title("TIC" + str(TIC) + ": final de-trended light curve")
    plt.xlim(time.min(), time.max())
    #    plt.savefig('/Users/Admin/Documents/Research_Lisa/TESS/plots/'+str(TIC)+'_detrend_lc_final.pdf')
    plt.close()

    plt.figure(figsize=(10, 5))

    x_fold = (x - bls_t0 + 0.5 * bls_period) % bls_period - 0.5 * bls_period
    m = np.abs(x_fold) < 0.3
    plt.plot(x_fold[m], pld_flux[m], ".k", ms=4)

    bins = np.linspace(-0.5, 0.5, 60)
    denom, _ = np.histogram(x_fold, bins)
    num, _ = np.histogram(x_fold, bins, weights=pld_flux)
    denom[num == 0] = 1.0
    plt.plot(0.5 * (bins[1:] + bins[:-1]), num / denom, color="C1", lw=2)
    plt.xlim(-0.2, 0.2)
    plt.title("TIC" + str(TIC))
    plt.xlabel("time since transit")
    plt.ylabel("PLD model flux")
    #    plt.savefig('/Users/Admin/Documents/Research_Lisa/TESS/plots/'+str(TIC)+'_PLD_model.pdf')
    plt.close()
コード例 #13
0
ファイル: plotting.py プロジェクト: skgrunblatt/giants
def superplot(lc, ticid, breakpoints, target_list, save_data=False, outdir=None):
    """

    """

    time, flux, flux_err = lc.time, lc.flux, lc.flux_err

    model = BoxLeastSquares(time, flux)
    results = model.autopower(0.16, minimum_period=2., maximum_period=21.)
    period = results.period[np.argmax(results.power)]
    t0 = results.transit_time[np.argmax(results.power)]
    depth = results.depth[np.argmax(results.power)]
    depth_snr = results.depth_snr[np.argmax(results.power)]

    '''
    Plot Filtered Light Curve
    -------------------------
    '''
    plt.subplot2grid((8,16),(1,0),colspan=4, rowspan=1)

    plt.plot(time, flux, 'k', label="filtered")
    for val in breakpoints:
        plt.axvline(val, c='b', linestyle='dashed')
    plt.legend()
    plt.ylabel('Normalized Flux')
    plt.xlabel('Time')

    osample=5.
    nyq=283.

    # calculate FFT
    freq, amp, nout, jmax, prob = lomb.fasper(time, flux, osample, 3.)
    freq = 1000. * freq / 86.4
    bin = freq[1] - freq[0]
    fts = 2. * amp * np.var(flux * 1e6) / (np.sum(amp) * bin)

    use = np.where(freq < nyq + 150)
    freq = freq[use]
    fts = fts[use]

    # calculate ACF
    acf = np.correlate(fts, fts, 'same')
    freq_acf = np.linspace(-freq[-1], freq[-1], len(freq))

    fitT = build_ktransit_model(ticid=ticid, lc=lc, vary_transit=False)
    dur = _individual_ktransit_dur(fitT.time, fitT.transitmodel)

    freq = freq
    fts1 = fts/np.max(fts)
    fts2 = scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 5)
    fts3 = scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 50)

    '''
    Plot Periodogram
    ----------------
    '''
    plt.subplot2grid((8,16),(0,4),colspan=4,rowspan=4)
    plt.loglog(freq, fts/np.max(fts))
    plt.loglog(freq, scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 5), color='C1', lw=2.5)
    plt.loglog(freq, scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 50), color='r', lw=2.5)
    plt.axvline(283,-1,1, ls='--', color='k')
    plt.xlabel("Frequency [uHz]")
    plt.ylabel("Power")
    plt.xlim(10, 400)
    plt.ylim(1e-4, 1e0)

    # annotate with transit info
    font = {'family':'monospace', 'size':10}
    plt.text(10**1.04, 10**-3.50, f'depth = {depth:.4f}        ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    plt.text(10**1.04, 10**-3.62, f'depth_snr = {depth_snr:.4f}    ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    plt.text(10**1.04, 10**-3.74, f'period = {period:.3f} days    ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    plt.text(10**1.04, 10**-3.86, f't0 = {t0:.3f}            ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    try:
        # annotate with stellar params
        # won't work for TIC ID's not in the list
        if isinstance(ticid, str):
            ticid = int(re.search(r'\d+', str(ticid)).group())
        Gmag = target_list[target_list['ID'] == ticid]['GAIAmag'].values[0]
        Teff = target_list[target_list['ID'] == ticid]['Teff'].values[0]
        R = target_list[target_list['ID'] == ticid]['rad'].values[0]
        M = target_list[target_list['ID'] == ticid]['mass'].values[0]
        plt.text(10**1.7, 10**-3.50, rf"G mag = {Gmag:.3f} ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
        plt.text(10**1.7, 10**-3.62, rf"Teff = {int(Teff)} K  ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
        plt.text(10**1.7, 10**-3.74, rf"R = {R:.3f} $R_\odot$  ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
        plt.text(10**1.7, 10**-3.86, rf"M = {M:.3f} $M_\odot$    ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none'))
    except:
        pass

    '''# plot ACF inset
    ax = plt.gca()
    axins = inset_axes(ax, width=2.0, height=1.4)
    axins.plot(freq_acf, acf)
    axins.set_xlim(1,25)
    axins.set_xlabel("ACF [uHz]")'''

    '''
    Plot BLS
    --------
    '''
    plt.subplot2grid((8,16),(2,0),colspan=4, rowspan=1)

    plt.plot(results.period, results.power, "k", lw=0.5)
    plt.xlim(results.period.min(), results.period.max())
    plt.xlabel("period [days]")
    plt.ylabel("log likelihood")

    # Highlight the harmonics of the peak period
    plt.axvline(period, alpha=0.4, lw=4)
    for n in range(2, 10):
        plt.axvline(n*period, alpha=0.4, lw=1, linestyle="dashed")
        plt.axvline(period / n, alpha=0.4, lw=1, linestyle="dashed")

    phase = (t0 % period) / period
    foldedtimes = (((time - phase * period) / period) % 1)
    foldedtimes[foldedtimes > 0.5] -= 1
    foldtimesort = np.argsort(foldedtimes)
    foldfluxes = flux[foldtimesort]
    plt.subplot2grid((8,16), (3,0),colspan=2)
    plt.scatter(foldedtimes, flux, s=2)
    plt.plot(np.sort(foldedtimes), scipy.ndimage.filters.median_filter(foldfluxes, 40), lw=2, color='r', label=f'P={period:.2f} days, dur={dur:.2f} hrs')
    plt.xlabel('Phase')
    plt.ylabel('Flux')
    plt.xlim(-0.5, 0.5)
    plt.ylim(-0.0025, 0.0025)
    plt.legend(loc=0)

    fig = plt.gcf()
    fig.patch.set_facecolor('white')
    fig.suptitle(f'{ticid}', fontsize=14)
    fig.set_size_inches(12, 10)

    if save_data:
        np.savetxt(outdir+'/timeseries/'+str(ticid)+'.dat.ts', np.transpose([time, flux]), fmt='%.8f', delimiter=' ')
        np.savetxt(outdir+'/fft/'+str(ticid)+'.dat.ts.fft', np.transpose([freq, fts]), fmt='%.8f', delimiter=' ')
        with open(os.path.join(outdir,"transit_stats.txt"), "a+") as file:
            file.write(f"{ticid} {depth} {depth_snr} {period} {t0} {dur}\n")

    """
    ---------------
    TRANSIT VETTING
    ---------------
    """
    tpf = get_cutout(ticid, cutout_size=11)
    ica_lcs = find_ica_components(tpf)

    fig = plt.subplot2grid((8,16),(0,8),colspan=4,rowspan=4)
    fig.patch.set_facecolor('white')

    tpf.plot(ax=fig, title='', show_colorbar=False)
    add_gaia_figure_elements(tpf, fig)

    fig = plt.subplot2grid((8,16),(2,8),colspan=4,rowspan=2)
    lc.fold(2*period, t0+period/2).scatter(ax=fig, c='k', label='Odd Transit')
    lc.fold(2*period, t0+period/2).bin(3).plot(ax=fig, c='C1', lw=2)
    plt.xlim(-.5, 0)
    rms = np.std(lc.flux)
    plt.ylim(-3*rms, rms)

    fig = plt.subplot2grid((8,16),(3,8),colspan=4,rowspan=2)
    lc.fold(2*period, t0+period/2).scatter(ax=fig, c='k', label='Even Transit')
    lc.fold(2*period, t0+period/2).bin(3).plot(ax=fig, c='C1', lw=2)
    plt.xlim(0, .5)
    plt.ylim(-3*rms, rms)

    fig = plt.subplot2grid((8,16),(0,12),colspan=4,rowspan=4)
    for i,ilc in enumerate(ica_lcs):
        scale = 1
        plt.plot(ilc + i*scale)
    plt.xlim(0, len(ica_lcs[0]))
    plt.ylim(-scale, len(ica_lcs)*scale)

    """
    STARRY MODEL
    ------------
    """
    from .utils import _fit

    x, y, yerr = lc.time, lc.flux, lc.flux_err
    model, static_lc = _fit(x, y, yerr, target_list=target_list)

    model_lc = lk.LightCurve(time=x, flux=static_lc)

    with model:
        period = model.map_soln['period'][0]
        t0 = model.map_soln['t0'][0]
        r_pl = model.map_soln['r_pl'] * 9.96
        a = model.map_soln['a'][0]
        b = model.map_soln['b'][0]

    try:
        r_star = target_list[target_list['ID'] == ticid]['rad'].values[0]
    except:
        r_star = 10.

    fig = plt.subplot2grid((8,16),(4,0),colspan=4,rowspan=2)
    '''
    Plot unfolded transit
    ---------------------
    '''
    lc.scatter(c='k', label='Corrected Flux')
    lc.bin(binsize=7).plot(c='b', lw=1.5, alpha=.75, label='binned')
    model_lc.plot(c='r', lw=2, label='Transit Model')
    plt.ylim([-.002, .002])
    plt.xlim([lc.time[0], lc.time[-1]])

    fig = plt.subplot2grid((8,16),(6,0),colspan=4,rowspan=2)
    '''
    Plot folded transit
    -------------------
    '''
    lc.fold(period, t0).scatter(c='k', label=rf'$P={period:.3f}, t0={t0:.3f}, '
                                                         'R_p={r_pl:.3f} R_J, b={b:.3f}')
    lc.fold(period, t0).bin(binsize=7).plot(c='b', alpha=.75, lw=2)
    model_lc.fold(period, t0).plot(c='r', lw=2)
    plt.xlim([-0.5, .5])
    plt.ylim([-.002, .002])
コード例 #14
0
ファイル: plotting.py プロジェクト: skgrunblatt/giants
def make_ica_plot(tic, tpf=None):
    """
    """

    if tpf is None:
        tpf = lk.search_tesscut(f'TIC {tic}').download(cutout_size=11)
    raw_lc = tpf.to_lightcurve(aperture_mask='all')

    ##Perform ICA
    n_components = 20

    X = np.ascontiguousarray(np.nan_to_num(tpf.flux), np.float64)
    X_flat = X.reshape(len(tpf.flux), -1) #turns three dimensional into two dimensional

    f1 = np.reshape(X_flat, (len(X), -1))
    X_pix = f1 / np.nansum(X_flat, axis=-1)[:, None]

    ica = FastICA(n_components=n_components) #define n_components
    S_ = ica.fit_transform(X_pix)
    A_ = ica.mixing_ #combine x_flat to get x

    a = np.dot(S_.T, S_)
    a[np.diag_indices_from(a)] += 1e-5
    b = np.dot(S_.T, raw_lc.flux)

    w = np.linalg.solve(a, b)

    comp_lcs = []
    blss = []
    max_powers = []

    for i,s in enumerate(S_.T):
        component_lc = s * w[i]
        comp_lcs.append(component_lc)
        # plt.plot(component_lc + i*1e5)

        model = BoxLeastSquares(tpf.time, component_lc)
        results = model.autopower(0.16, minimum_period=.5, maximum_period=24.)
        # model = transitleastsquares(tpf.time, component_lc)
        # results = model.power()
        period, power = results.period, results.power
        blss.append([period, power])
        # print(results.depth_snr[np.argmax(power)])
        if (np.std(component_lc) > 1e4) or (np.abs(period[np.argmax(power)] - 14) < 2) or (results.depth[np.argmax(power)]/np.median(component_lc) < 0):
            power = [0]

        max_powers.append(np.max(power))

    # plt.ylim(-1e5, 10e5)

    best_pers = blss[np.argmax(max_powers)][0]
    best_powers = blss[np.argmax(max_powers)][1]

    period = best_pers[np.argmax(best_powers)]

    transit_lc = lk.LightCurve(time=tpf.time, flux=comp_lcs[np.argmax(max_powers)])

    fig, ax = plt.subplots(2, 3, figsize=(10, 7))
    fig.suptitle(f'TIC {tic}')

    for i,c in enumerate(comp_lcs):
        ax[0,0].plot(tpf.time, c + i*1e5)
    ax[0,0].set_ylim(-1e5, n_components*1e5)
    ax[0,0].set_xlim(tpf.time[0], tpf.time[-1])
    ax[0,0].set_xlabel('Time')
    ax[0,0].set_ylabel('Flux')
    ax[0,0].yaxis.set_major_formatter(mtick.FormatStrFormatter('%.e'))
    ax[0,0].set_title('ICA Components')

    transit_lc.plot(ax=ax[0,1])
    ax[0,1].set_xlim(tpf.time[0], tpf.time[-1])
    ax[0,1].yaxis.set_major_formatter(mtick.FormatStrFormatter('%.e'))
    ax[0,1].set_title('ICA comp with max BLS power')

    transit_lc.remove_outliers(9).fold(period).scatter(ax=ax[0,2], c='k', label=f'Period={period:.2f}')
    transit_lc.remove_outliers(9).fold(period).bin(7).plot(ax=ax[0,2], c='r', lw=2, C='C1', label='Binned')
    ax[0,2].set_ylim(-5*np.std(transit_lc.flux), 2*np.std(transit_lc.flux))
    ax[0,2].set_xlim(-.5,.5)
    ax[0,2].set_title('Folded ICA Transit Component')

    A_useful = A_.reshape(11,11,n_components).T #reshape from 2d to 3d

    weighted_comp = A_useful[np.argmax(max_powers)].T * w[np.argmax(max_powers)]

    ax[1,0].imshow(weighted_comp, origin='lower')
    ax[1,1].imshow(tpf.flux[200], origin='lower')
    im = ax[1,2].imshow(weighted_comp / tpf.flux[200], origin='lower')

    ax[1,0].set_title('Weighted Transit Component')
    ax[1,1].set_title('TPF')
    ax[1,2].set_title('Model / Flux')

    plt.colorbar(im)
    fig.tight_layout(rect=[0, 0.03, 1, 0.95])
    fig.patch.set_facecolor('white')
    fig.set_size_inches(10, 7)

    return fig
コード例 #15
0
ファイル: abls.py プロジェクト: JinbiaoJi/astrobase
def bls_parallel_pfind(
    times,
    mags,
    errs,
    magsarefluxes=False,
    startp=0.1,  # by default, search from 0.1 d to...
    endp=100.0,  # ... 100.0 d -- don't search full timebase
    stepsize=1.0e-4,
    mintransitduration=0.01,  # minimum transit length in phase
    maxtransitduration=0.4,  # maximum transit length in phase
    ndurations=100,
    autofreq=True,  # figure out f0, nf, and df automatically
    blsobjective='likelihood',
    blsmethod='fast',
    blsoversample=5,
    blsmintransits=3,
    blsfreqfactor=10.0,
    nbestpeaks=5,
    periodepsilon=0.1,  # 0.1
    sigclip=10.0,
    endp_timebase_check=True,
    verbose=True,
    nworkers=None,
):
    '''Runs the Box Least Squares Fitting Search for transit-shaped signals.

    Breaks up the full frequency space into chunks and passes them to parallel
    BLS workers.

    Based on the version of BLS in Astropy 3.1:
    `astropy.stats.BoxLeastSquares`. If you don't have Astropy 3.1, this module
    will fail to import. Note that by default, this implementation of
    `bls_parallel_pfind` doesn't use the `.autoperiod()` function from
    `BoxLeastSquares` but uses the same auto frequency-grid generation as the
    functions in `periodbase.kbls`. If you want to use Astropy's implementation,
    set the value of `autofreq` kwarg to 'astropy'. The generated period array
    will then be broken up into chunks and sent to the individual workers.

    NOTE: the combined BLS spectrum produced by this function is not identical
    to that produced by running BLS in one shot for the entire frequency
    space. There are differences on the order of 1.0e-3 or so in the respective
    peak values, but peaks appear at the same frequencies for both methods. This
    is likely due to different aliasing caused by smaller chunks of the
    frequency space used by the parallel workers in this function. When in
    doubt, confirm results for this parallel implementation by comparing to
    those from the serial implementation above.

    In particular, when you want to get reliable estimates of the SNR, transit
    depth, duration, etc. that Astropy's BLS gives you, rerun `bls_serial_pfind`
    with `startp`, and `endp` close to the best period you want to characterize
    the transit at. The dict returned from that function contains a `blsmodel`
    key, which is the generated model from Astropy's BLS. Use the
    `.compute_stats()` method to calculate the required stats.

    Parameters
    ----------

    times,mags,errs : np.array
        The magnitude/flux time-series to search for transits.

    magsarefluxes : bool
        If the input measurement values in `mags` and `errs` are in fluxes, set
        this to True.

    startp,endp : float
        The minimum and maximum periods to consider for the transit search.

    stepsize : float
        The step-size in frequency to use when constructing a frequency grid for
        the period search.

    mintransitduration,maxtransitduration : float
        The minimum and maximum transitdurations (in units of phase) to consider
        for the transit search.

    ndurations : int
        The number of transit durations to use in the period-search.

    autofreq : bool or str
        If this is True, the values of `stepsize` and `nphasebins` will be
        ignored, and these, along with a frequency-grid, will be determined
        based on the following relations::

            nphasebins = int(ceil(2.0/mintransitduration))
            if nphasebins > 3000:
                nphasebins = 3000

            stepsize = 0.25*mintransitduration/(times.max()-times.min())

            minfreq = 1.0/endp
            maxfreq = 1.0/startp
            nfreq = int(ceil((maxfreq - minfreq)/stepsize))

        If this is False, you must set `startp`, `endp`, and `stepsize` as
        appropriate.

        If this is str == 'astropy', will use the
        `astropy.stats.BoxLeastSquares.autoperiod()` function to calculate the
        frequency grid instead of the kbls method.

    blsobjective : {'likelihood','snr'}
        Sets the type of objective to optimize in the `BoxLeastSquares.power()`
        function.

    blsmethod : {'fast','slow'}
        Sets the type of method to use in the `BoxLeastSquares.power()`
        function.

    blsoversample : {'likelihood','snr'}
        Sets the `oversample` kwarg for the `BoxLeastSquares.power()` function.

    blsmintransits : int
        Sets the `min_n_transits` kwarg for the `BoxLeastSquares.autoperiod()`
        function.

    blsfreqfactor : float
        Sets the `frequency_factor` kwarg for the `BoxLeastSquares.autoperiod()`
        function.

    periodepsilon : float
        The fractional difference between successive values of 'best' periods
        when sorting by periodogram power to consider them as separate periods
        (as opposed to part of the same periodogram peak). This is used to avoid
        broad peaks in the periodogram and make sure the 'best' periods returned
        are all actually independent.

    nbestpeaks : int
        The number of 'best' peaks to return from the periodogram results,
        starting from the global maximum of the periodogram peak values.

    sigclip : float or int or sequence of two floats/ints or None
        If a single float or int, a symmetric sigma-clip will be performed using
        the number provided as the sigma-multiplier to cut out from the input
        time-series.

        If a list of two ints/floats is provided, the function will perform an
        'asymmetric' sigma-clip. The first element in this list is the sigma
        value to use for fainter flux/mag values; the second element in this
        list is the sigma value to use for brighter flux/mag values. For
        example, `sigclip=[10., 3.]`, will sigclip out greater than 10-sigma
        dimmings and greater than 3-sigma brightenings. Here the meaning of
        "dimming" and "brightening" is set by *physics* (not the magnitude
        system), which is why the `magsarefluxes` kwarg must be correctly set.

        If `sigclip` is None, no sigma-clipping will be performed, and the
        time-series (with non-finite elems removed) will be passed through to
        the output.

    endp_timebase_check : bool
        If True, will check if the ``endp`` value is larger than the time-base
        of the observations. If it is, will change the ``endp`` value such that
        it is half of the time-base. If False, will allow an ``endp`` larger
        than the time-base of the observations.

    verbose : bool
        If this is True, will indicate progress and details about the frequency
        grid used for the period search.

    nworkers : int or None
        The number of parallel workers to launch for period-search. If None,
        nworkers = NCPUS.

    Returns
    -------

    dict
        This function returns a dict, referred to as an `lspinfo` dict in other
        astrobase functions that operate on periodogram results. This is a
        standardized format across all astrobase period-finders, and is of the
        form below::

            {'bestperiod': the best period value in the periodogram,
             'bestlspval': the periodogram peak associated with the best period,
             'nbestpeaks': the input value of nbestpeaks,
             'nbestlspvals': nbestpeaks-size list of best period peak values,
             'nbestperiods': nbestpeaks-size list of best periods,
             'lspvals': the full array of periodogram powers,
             'frequencies': the full array of frequencies considered,
             'periods': the full array of periods considered,
             'durations': the array of durations used to run BLS,
             'blsresult': Astropy BLS result object (BoxLeastSquaresResult),
             'blsmodel': Astropy BLS BoxLeastSquares object used for work,
             'stepsize': the actual stepsize used,
             'nfreq': the actual nfreq used,
             'durations': the durations array used,
             'mintransitduration': the input mintransitduration,
             'maxtransitduration': the input maxtransitdurations,
             'method':'bls' -> the name of the period-finder method,
             'kwargs':{ dict of all of the input kwargs for record-keeping}}

    '''

    # get rid of nans first and sigclip
    stimes, smags, serrs = sigclip_magseries(times,
                                             mags,
                                             errs,
                                             magsarefluxes=magsarefluxes,
                                             sigclip=sigclip)

    # make sure there are enough points to calculate a spectrum
    if len(stimes) > 9 and len(smags) > 9 and len(serrs) > 9:

        # if we're setting up everything automatically
        if isinstance(autofreq, bool) and autofreq:

            # use heuristic to figure out best timestep
            stepsize = 0.25 * mintransitduration / (stimes.max() -
                                                    stimes.min())

            # now figure out the frequencies to use
            minfreq = 1.0 / endp
            maxfreq = 1.0 / startp
            nfreq = int(npceil((maxfreq - minfreq) / stepsize))

            # say what we're using
            if verbose:
                LOGINFO('min P: %s, max P: %s, nfreq: %s, '
                        'minfreq: %s, maxfreq: %s' %
                        (startp, endp, nfreq, minfreq, maxfreq))
                LOGINFO('autofreq = True: using AUTOMATIC values for '
                        'freq stepsize: %s, ndurations: %s, '
                        'min transit duration: %s, max transit duration: %s' %
                        (stepsize, ndurations, mintransitduration,
                         maxtransitduration))

            use_autoperiod = False

        elif isinstance(autofreq, bool) and not autofreq:

            minfreq = 1.0 / endp
            maxfreq = 1.0 / startp
            nfreq = int(npceil((maxfreq - minfreq) / stepsize))

            # say what we're using
            if verbose:
                LOGINFO('min P: %s, max P: %s, nfreq: %s, '
                        'minfreq: %s, maxfreq: %s' %
                        (startp, endp, nfreq, minfreq, maxfreq))
                LOGINFO('autofreq = False: using PROVIDED values for '
                        'freq stepsize: %s, ndurations: %s, '
                        'min transit duration: %s, max transit duration: %s' %
                        (stepsize, ndurations, mintransitduration,
                         maxtransitduration))

            use_autoperiod = False

        elif isinstance(autofreq, str) and autofreq == 'astropy':

            use_autoperiod = True
            minfreq = 1.0 / endp
            maxfreq = 1.0 / startp

        else:

            LOGERROR("unknown autofreq kwarg encountered. can't continue...")
            return None

        # check the minimum frequency
        if ((minfreq < (1.0 / (stimes.max() - stimes.min())))
                and endp_timebase_check):

            LOGWARNING('the requested max P = %.3f is larger than '
                       'the time base of the observations = %.3f, '
                       ' will make minfreq = 2 x 1/timebase' %
                       (endp, stimes.max() - stimes.min()))
            minfreq = 2.0 / (stimes.max() - stimes.min())
            LOGWARNING('new minfreq: %s, maxfreq: %s' % (minfreq, maxfreq))

        #############################
        ## NOW RUN BLS IN PARALLEL ##
        #############################

        # fix number of CPUs if needed
        if not nworkers or nworkers > NCPUS:
            nworkers = NCPUS
            if verbose:
                LOGINFO('using %s workers...' % nworkers)

        # check if autoperiod is True and get the correct period-grid
        if use_autoperiod:

            # astropy's BLS requires durations in units of time
            durations = nplinspace(mintransitduration * startp,
                                   maxtransitduration * startp, ndurations)

            # set up the correct units for the BLS model
            if magsarefluxes:

                blsmodel = BoxLeastSquares(stimes * u.day,
                                           smags * u.dimensionless_unscaled,
                                           dy=serrs * u.dimensionless_unscaled)

            else:

                blsmodel = BoxLeastSquares(stimes * u.day,
                                           smags * u.mag,
                                           dy=serrs * u.mag)

            periods = nparray(
                blsmodel.autoperiod(durations * u.day,
                                    minimum_period=startp,
                                    maximum_period=endp,
                                    minimum_n_transit=blsmintransits,
                                    frequency_factor=blsfreqfactor))

            frequencies = 1.0 / periods
            nfreq = frequencies.size

            if verbose:
                LOGINFO("autofreq = 'astropy', used .autoperiod() with "
                        "minimum_n_transit = %s, freq_factor = %s "
                        "to generate the frequency grid" %
                        (blsmintransits, blsfreqfactor))
                LOGINFO('stepsize = %s, nfreq = %s, minfreq = %.5f, '
                        'maxfreq = %.5f, ndurations = %s' %
                        (abs(frequencies[1] - frequencies[0]), nfreq, 1.0 /
                         periods.max(), 1.0 / periods.min(), durations.size))

            del blsmodel
            del durations

        # otherwise, use kbls method
        else:

            frequencies = minfreq + nparange(nfreq) * stepsize

        # break up the tasks into chunks
        csrem = int(fmod(nfreq, nworkers))
        csint = int(float(nfreq / nworkers))
        chunk_minfreqs, chunk_nfreqs = [], []

        for x in range(nworkers):

            this_minfreqs = frequencies[x * csint]

            # handle usual nfreqs
            if x < (nworkers - 1):
                this_nfreqs = frequencies[x * csint:x * csint + csint].size
            else:
                this_nfreqs = frequencies[x * csint:x * csint + csint +
                                          csrem].size

            chunk_minfreqs.append(this_minfreqs)
            chunk_nfreqs.append(this_nfreqs)

        # populate the tasks list
        #
        # task[0] = times
        # task[1] = mags
        # task[2] = errs
        # task[3] = magsarefluxes

        # task[4] = minfreq
        # task[5] = nfreq
        # task[6] = stepsize

        # task[7] = nphasebins
        # task[8] = mintransitduration
        # task[9] = maxtransitduration

        # task[10] = blsobjective
        # task[11] = blsmethod
        # task[12] = blsoversample

        # populate the tasks list
        tasks = [(stimes, smags, serrs, magsarefluxes, chunk_minf, chunk_nf,
                  stepsize, ndurations, mintransitduration, maxtransitduration,
                  blsobjective, blsmethod, blsoversample)
                 for (chunk_minf,
                      chunk_nf) in zip(chunk_minfreqs, chunk_nfreqs)]

        if verbose:
            for ind, task in enumerate(tasks):
                LOGINFO('worker %s: minfreq = %.6f, nfreqs = %s' %
                        (ind + 1, task[4], task[5]))
            LOGINFO('running...')

        # return tasks

        # start the pool
        pool = Pool(nworkers)
        results = pool.map(_parallel_bls_worker, tasks)

        pool.close()
        pool.join()
        del pool

        # now concatenate the output lsp arrays
        lsp = npconcatenate([x['power'] for x in results])
        periods = 1.0 / frequencies

        # find the nbestpeaks for the periodogram: 1. sort the lsp array
        # by highest value first 2. go down the values until we find
        # five values that are separated by at least periodepsilon in
        # period
        # make sure to get only the finite peaks in the periodogram
        # this is needed because BLS may produce infs for some peaks
        finitepeakind = npisfinite(lsp)
        finlsp = lsp[finitepeakind]
        finperiods = periods[finitepeakind]

        # make sure that finlsp has finite values before we work on it
        try:

            bestperiodind = npargmax(finlsp)

        except ValueError:

            LOGERROR('no finite periodogram values '
                     'for this mag series, skipping...')

            return {
                'bestperiod': npnan,
                'bestlspval': npnan,
                'nbestpeaks': nbestpeaks,
                'nbestinds': None,
                'nbestlspvals': None,
                'nbestperiods': None,
                'lspvals': None,
                'periods': None,
                'durations': None,
                'method': 'bls',
                'blsresult': None,
                'blsmodel': None,
                'kwargs': {
                    'startp': startp,
                    'endp': endp,
                    'stepsize': stepsize,
                    'mintransitduration': mintransitduration,
                    'maxtransitduration': maxtransitduration,
                    'ndurations': ndurations,
                    'blsobjective': blsobjective,
                    'blsmethod': blsmethod,
                    'blsoversample': blsoversample,
                    'autofreq': autofreq,
                    'periodepsilon': periodepsilon,
                    'nbestpeaks': nbestpeaks,
                    'sigclip': sigclip,
                    'magsarefluxes': magsarefluxes
                }
            }

        sortedlspind = npargsort(finlsp)[::-1]
        sortedlspperiods = finperiods[sortedlspind]
        sortedlspvals = finlsp[sortedlspind]

        # now get the nbestpeaks
        nbestperiods, nbestlspvals, nbestinds, peakcount = ([
            finperiods[bestperiodind]
        ], [finlsp[bestperiodind]], [bestperiodind], 1)
        prevperiod = sortedlspperiods[0]

        # find the best nbestpeaks in the lsp and their periods
        for period, lspval, ind in zip(sortedlspperiods, sortedlspvals,
                                       sortedlspind):

            if peakcount == nbestpeaks:
                break
            perioddiff = abs(period - prevperiod)
            bestperiodsdiff = [abs(period - x) for x in nbestperiods]

            # this ensures that this period is different from the last
            # period and from all the other existing best periods by
            # periodepsilon to make sure we jump to an entire different
            # peak in the periodogram
            if (perioddiff > (periodepsilon * prevperiod)
                    and all(x > (periodepsilon * period)
                            for x in bestperiodsdiff)):
                nbestperiods.append(period)
                nbestlspvals.append(lspval)
                nbestinds.append(ind)
                peakcount = peakcount + 1

            prevperiod = period

        # generate the return dict
        resultdict = {
            'bestperiod': finperiods[bestperiodind],
            'bestlspval': finlsp[bestperiodind],
            'nbestpeaks': nbestpeaks,
            'nbestinds': nbestinds,
            'nbestlspvals': nbestlspvals,
            'nbestperiods': nbestperiods,
            'lspvals': lsp,
            'frequencies': frequencies,
            'periods': periods,
            'durations': [x['durations'] for x in results],
            'blsresult': [x['blsresult'] for x in results],
            'blsmodel': [x['blsmodel'] for x in results],
            'stepsize': stepsize,
            'nfreq': nfreq,
            'mintransitduration': mintransitduration,
            'maxtransitduration': maxtransitduration,
            'method': 'bls',
            'kwargs': {
                'startp': startp,
                'endp': endp,
                'stepsize': stepsize,
                'mintransitduration': mintransitduration,
                'maxtransitduration': maxtransitduration,
                'ndurations': ndurations,
                'blsobjective': blsobjective,
                'blsmethod': blsmethod,
                'blsoversample': blsoversample,
                'autofreq': autofreq,
                'periodepsilon': periodepsilon,
                'nbestpeaks': nbestpeaks,
                'sigclip': sigclip,
                'magsarefluxes': magsarefluxes
            }
        }

        return resultdict

    else:

        LOGERROR('no good detections for these times and mags, skipping...')
        return {
            'bestperiod': npnan,
            'bestlspval': npnan,
            'nbestinds': None,
            'nbestpeaks': nbestpeaks,
            'nbestlspvals': None,
            'nbestperiods': None,
            'lspvals': None,
            'periods': None,
            'durations': None,
            'blsresult': None,
            'blsmodel': None,
            'stepsize': stepsize,
            'nfreq': None,
            'nphasebins': None,
            'mintransitduration': mintransitduration,
            'maxtransitduration': maxtransitduration,
            'method': 'bls',
            'kwargs': {
                'startp': startp,
                'endp': endp,
                'stepsize': stepsize,
                'mintransitduration': mintransitduration,
                'maxtransitduration': maxtransitduration,
                'ndurations': ndurations,
                'blsobjective': blsobjective,
                'blsmethod': blsmethod,
                'blsoversample': blsoversample,
                'autofreq': autofreq,
                'periodepsilon': periodepsilon,
                'nbestpeaks': nbestpeaks,
                'sigclip': sigclip,
                'magsarefluxes': magsarefluxes
            }
        }
コード例 #16
0
ファイル: abls.py プロジェクト: JinbiaoJi/astrobase
def bls_serial_pfind(
        times,
        mags,
        errs,
        magsarefluxes=False,
        startp=0.1,  # search from 0.1 d to...
        endp=100.0,  # ... 100.0 d -- don't search full timebase
        stepsize=5.0e-4,
        mintransitduration=0.01,  # minimum transit length in phase
        maxtransitduration=0.4,  # maximum transit length in phase
        ndurations=100,
        autofreq=True,  # figure out f0, nf, and df automatically
        blsobjective='likelihood',
        blsmethod='fast',
        blsoversample=10,
        blsmintransits=3,
        blsfreqfactor=10.0,
        periodepsilon=0.1,
        nbestpeaks=5,
        sigclip=10.0,
        endp_timebase_check=True,
        verbose=True,
        raiseonfail=False):
    '''Runs the Box Least Squares Fitting Search for transit-shaped signals.

    Based on the version of BLS in Astropy 3.1:
    `astropy.stats.BoxLeastSquares`. If you don't have Astropy 3.1, this module
    will fail to import. Note that by default, this implementation of
    `bls_serial_pfind` doesn't use the `.autoperiod()` function from
    `BoxLeastSquares` but uses the same auto frequency-grid generation as the
    functions in `periodbase.kbls`. If you want to use Astropy's implementation,
    set the value of `autofreq` kwarg to 'astropy'.

    The dict returned from this function contains a `blsmodel` key, which is the
    generated model from Astropy's BLS. Use the `.compute_stats()` method to
    calculate the required stats like SNR, depth, duration, etc.

    Parameters
    ----------

    times,mags,errs : np.array
        The magnitude/flux time-series to search for transits.

    magsarefluxes : bool
        If the input measurement values in `mags` and `errs` are in fluxes, set
        this to True.

    startp,endp : float
        The minimum and maximum periods to consider for the transit search.

    stepsize : float
        The step-size in frequency to use when constructing a frequency grid for
        the period search.

    mintransitduration,maxtransitduration : float
        The minimum and maximum transitdurations (in units of phase) to consider
        for the transit search.

    ndurations : int
        The number of transit durations to use in the period-search.

    autofreq : bool or str
        If this is True, the values of `stepsize` and `nphasebins` will be
        ignored, and these, along with a frequency-grid, will be determined
        based on the following relations::

            nphasebins = int(ceil(2.0/mintransitduration))
            if nphasebins > 3000:
                nphasebins = 3000

            stepsize = 0.25*mintransitduration/(times.max()-times.min())

            minfreq = 1.0/endp
            maxfreq = 1.0/startp
            nfreq = int(ceil((maxfreq - minfreq)/stepsize))

        If this is False, you must set `startp`, `endp`, and `stepsize` as
        appropriate.

        If this is str == 'astropy', will use the
        `astropy.stats.BoxLeastSquares.autoperiod()` function to calculate the
        frequency grid instead of the kbls method.

    blsobjective : {'likelihood','snr'}
        Sets the type of objective to optimize in the `BoxLeastSquares.power()`
        function.

    blsmethod : {'fast','slow'}
        Sets the type of method to use in the `BoxLeastSquares.power()`
        function.

    blsoversample : {'likelihood','snr'}
        Sets the `oversample` kwarg for the `BoxLeastSquares.power()` function.

    blsmintransits : int
        Sets the `min_n_transits` kwarg for the `BoxLeastSquares.autoperiod()`
        function.

    blsfreqfactor : float
        Sets the `frequency_factor` kwarg for the `BoxLeastSquares.autperiod()`
        function.

    periodepsilon : float
        The fractional difference between successive values of 'best' periods
        when sorting by periodogram power to consider them as separate periods
        (as opposed to part of the same periodogram peak). This is used to avoid
        broad peaks in the periodogram and make sure the 'best' periods returned
        are all actually independent.

    nbestpeaks : int
        The number of 'best' peaks to return from the periodogram results,
        starting from the global maximum of the periodogram peak values.

    sigclip : float or int or sequence of two floats/ints or None
        If a single float or int, a symmetric sigma-clip will be performed using
        the number provided as the sigma-multiplier to cut out from the input
        time-series.

        If a list of two ints/floats is provided, the function will perform an
        'asymmetric' sigma-clip. The first element in this list is the sigma
        value to use for fainter flux/mag values; the second element in this
        list is the sigma value to use for brighter flux/mag values. For
        example, `sigclip=[10., 3.]`, will sigclip out greater than 10-sigma
        dimmings and greater than 3-sigma brightenings. Here the meaning of
        "dimming" and "brightening" is set by *physics* (not the magnitude
        system), which is why the `magsarefluxes` kwarg must be correctly set.

        If `sigclip` is None, no sigma-clipping will be performed, and the
        time-series (with non-finite elems removed) will be passed through to
        the output.

    endp_timebase_check : bool
        If True, will check if the ``endp`` value is larger than the time-base
        of the observations. If it is, will change the ``endp`` value such that
        it is half of the time-base. If False, will allow an ``endp`` larger
        than the time-base of the observations.

    verbose : bool
        If this is True, will indicate progress and details about the frequency
        grid used for the period search.

    raiseonfail : bool
        If True, raises an exception if something goes wrong. Otherwise, returns
        None.

    Returns
    -------

    dict
        This function returns a dict, referred to as an `lspinfo` dict in other
        astrobase functions that operate on periodogram results. This is a
        standardized format across all astrobase period-finders, and is of the
        form below::

            {'bestperiod': the best period value in the periodogram,
             'bestlspval': the periodogram peak associated with the best period,
             'nbestpeaks': the input value of nbestpeaks,
             'nbestlspvals': nbestpeaks-size list of best period peak values,
             'nbestperiods': nbestpeaks-size list of best periods,
             'lspvals': the full array of periodogram powers,
             'frequencies': the full array of frequencies considered,
             'periods': the full array of periods considered,
             'durations': the array of durations used to run BLS,
             'blsresult': Astropy BLS result object (BoxLeastSquaresResult),
             'blsmodel': Astropy BLS BoxLeastSquares object used for work,
             'stepsize': the actual stepsize used,
             'nfreq': the actual nfreq used,
             'durations': the durations array used,
             'mintransitduration': the input mintransitduration,
             'maxtransitduration': the input maxtransitdurations,
             'method':'bls' -> the name of the period-finder method,
             'kwargs':{ dict of all of the input kwargs for record-keeping}}

    '''

    # get rid of nans first and sigclip
    stimes, smags, serrs = sigclip_magseries(times,
                                             mags,
                                             errs,
                                             magsarefluxes=magsarefluxes,
                                             sigclip=sigclip)

    # make sure there are enough points to calculate a spectrum
    if len(stimes) > 9 and len(smags) > 9 and len(serrs) > 9:

        # if we're setting up everything automatically
        if isinstance(autofreq, bool) and autofreq:

            # use heuristic to figure out best timestep
            stepsize = 0.25 * mintransitduration / (stimes.max() -
                                                    stimes.min())

            # now figure out the frequencies to use
            minfreq = 1.0 / endp
            maxfreq = 1.0 / startp
            nfreq = int(npceil((maxfreq - minfreq) / stepsize))

            # say what we're using
            if verbose:
                LOGINFO('min P: %s, max P: %s, nfreq: %s, '
                        'minfreq: %s, maxfreq: %s' %
                        (startp, endp, nfreq, minfreq, maxfreq))
                LOGINFO('autofreq = True: using AUTOMATIC values for '
                        'freq stepsize: %s, ndurations: %s, '
                        'min transit duration: %s, max transit duration: %s' %
                        (stepsize, ndurations, mintransitduration,
                         maxtransitduration))

            use_autoperiod = False

        elif isinstance(autofreq, bool) and not autofreq:

            minfreq = 1.0 / endp
            maxfreq = 1.0 / startp
            nfreq = int(npceil((maxfreq - minfreq) / stepsize))

            # say what we're using
            if verbose:
                LOGINFO('min P: %s, max P: %s, nfreq: %s, '
                        'minfreq: %s, maxfreq: %s' %
                        (startp, endp, nfreq, minfreq, maxfreq))
                LOGINFO('autofreq = False: using PROVIDED values for '
                        'freq stepsize: %s, ndurations: %s, '
                        'min transit duration: %s, max transit duration: %s' %
                        (stepsize, ndurations, mintransitduration,
                         maxtransitduration))

            use_autoperiod = False

        elif isinstance(autofreq, str) and autofreq == 'astropy':

            use_autoperiod = True
            minfreq = 1.0 / endp
            maxfreq = 1.0 / startp

        else:

            LOGERROR("unknown autofreq kwarg encountered. can't continue...")
            return None

        # check the minimum frequency
        if ((minfreq < (1.0 / (stimes.max() - stimes.min())))
                and endp_timebase_check):

            LOGWARNING('the requested max P = %.3f is larger than '
                       'the time base of the observations = %.3f, '
                       ' will make minfreq = 2 x 1/timebase' %
                       (endp, stimes.max() - stimes.min()))
            minfreq = 2.0 / (stimes.max() - stimes.min())
            LOGWARNING('new minfreq: %s, maxfreq: %s' % (minfreq, maxfreq))

        # run BLS
        try:

            # astropy's BLS requires durations in units of time
            durations = nplinspace(mintransitduration * startp,
                                   maxtransitduration * startp, ndurations)

            # set up the correct units for the BLS model
            if magsarefluxes:

                blsmodel = BoxLeastSquares(stimes * u.day,
                                           smags * u.dimensionless_unscaled,
                                           dy=serrs * u.dimensionless_unscaled)

            else:

                blsmodel = BoxLeastSquares(stimes * u.day,
                                           smags * u.mag,
                                           dy=serrs * u.mag)

            # use autoperiod if requested
            if use_autoperiod:
                periods = nparray(
                    blsmodel.autoperiod(durations,
                                        minimum_period=startp,
                                        maximum_period=endp,
                                        minimum_n_transit=blsmintransits,
                                        frequency_factor=blsfreqfactor))
                nfreq = periods.size

                if verbose:
                    LOGINFO("autofreq = 'astropy', used .autoperiod() with "
                            "minimum_n_transit = %s, freq_factor = %s "
                            "to generate the frequency grid" %
                            (blsmintransits, blsfreqfactor))
                    LOGINFO(
                        'stepsize = %.5f, nfreq = %s, minfreq = %.5f, '
                        'maxfreq = %.5f, ndurations = %s' %
                        (abs(1.0 / periods[1] - 1.0 / periods[0]), nfreq, 1.0 /
                         periods.max(), 1.0 / periods.min(), durations.size))

            # otherwise, use kbls method
            else:
                frequencies = minfreq + nparange(nfreq) * stepsize
                periods = 1.0 / frequencies

            if nfreq > 5.0e5:
                if verbose:
                    LOGWARNING('more than 5.0e5 frequencies to go through; '
                               'this will take a while. '
                               'you might want to use the '
                               'abls.bls_parallel_pfind function instead')

            # run the periodogram
            blsresult = blsmodel.power(periods * u.day,
                                       durations * u.day,
                                       objective=blsobjective,
                                       method=blsmethod,
                                       oversample=blsoversample)

            # get the peak values
            lsp = nparray(blsresult.power)

            # find the nbestpeaks for the periodogram: 1. sort the lsp array
            # by highest value first 2. go down the values until we find
            # five values that are separated by at least periodepsilon in
            # period
            # make sure to get only the finite peaks in the periodogram
            # this is needed because BLS may produce infs for some peaks
            finitepeakind = npisfinite(lsp)
            finlsp = lsp[finitepeakind]
            finperiods = periods[finitepeakind]

            # make sure that finlsp has finite values before we work on it
            try:

                bestperiodind = npargmax(finlsp)

            except ValueError:

                LOGERROR('no finite periodogram values '
                         'for this mag series, skipping...')

                return {
                    'bestperiod': npnan,
                    'bestlspval': npnan,
                    'nbestpeaks': nbestpeaks,
                    'nbestinds': None,
                    'nbestlspvals': None,
                    'nbestperiods': None,
                    'lspvals': None,
                    'periods': None,
                    'durations': None,
                    'method': 'bls',
                    'blsresult': None,
                    'blsmodel': None,
                    'kwargs': {
                        'startp': startp,
                        'endp': endp,
                        'stepsize': stepsize,
                        'mintransitduration': mintransitduration,
                        'maxtransitduration': maxtransitduration,
                        'ndurations': ndurations,
                        'blsobjective': blsobjective,
                        'blsmethod': blsmethod,
                        'blsoversample': blsoversample,
                        'blsntransits': blsmintransits,
                        'blsfreqfactor': blsfreqfactor,
                        'autofreq': autofreq,
                        'periodepsilon': periodepsilon,
                        'nbestpeaks': nbestpeaks,
                        'sigclip': sigclip,
                        'magsarefluxes': magsarefluxes
                    }
                }

            sortedlspind = npargsort(finlsp)[::-1]
            sortedlspperiods = finperiods[sortedlspind]
            sortedlspvals = finlsp[sortedlspind]

            # now get the nbestpeaks
            nbestperiods, nbestlspvals, nbestinds, peakcount = ([
                finperiods[bestperiodind]
            ], [finlsp[bestperiodind]], [bestperiodind], 1)
            prevperiod = sortedlspperiods[0]

            # find the best nbestpeaks in the lsp and their periods
            for period, lspval, ind in zip(sortedlspperiods, sortedlspvals,
                                           sortedlspind):

                if peakcount == nbestpeaks:
                    break
                perioddiff = abs(period - prevperiod)
                bestperiodsdiff = [abs(period - x) for x in nbestperiods]

                # print('prevperiod = %s, thisperiod = %s, '
                #       'perioddiff = %s, peakcount = %s' %
                #       (prevperiod, period, perioddiff, peakcount))

                # this ensures that this period is different from the last
                # period and from all the other existing best periods by
                # periodepsilon to make sure we jump to an entire different
                # peak in the periodogram
                if (perioddiff > (periodepsilon * prevperiod)
                        and all(x > (periodepsilon * period)
                                for x in bestperiodsdiff)):
                    nbestperiods.append(period)
                    nbestlspvals.append(lspval)
                    nbestinds.append(ind)
                    peakcount = peakcount + 1

                prevperiod = period

            # generate the return dict
            resultdict = {
                'bestperiod': finperiods[bestperiodind],
                'bestlspval': finlsp[bestperiodind],
                'nbestpeaks': nbestpeaks,
                'nbestinds': nbestinds,
                'nbestlspvals': nbestlspvals,
                'nbestperiods': nbestperiods,
                'lspvals': lsp,
                'frequencies': frequencies,
                'periods': periods,
                'durations': durations,
                'blsresult': blsresult,
                'blsmodel': blsmodel,
                'stepsize': stepsize,
                'nfreq': nfreq,
                'mintransitduration': mintransitduration,
                'maxtransitduration': maxtransitduration,
                'method': 'bls',
                'kwargs': {
                    'startp': startp,
                    'endp': endp,
                    'stepsize': stepsize,
                    'mintransitduration': mintransitduration,
                    'maxtransitduration': maxtransitduration,
                    'ndurations': ndurations,
                    'blsobjective': blsobjective,
                    'blsmethod': blsmethod,
                    'blsoversample': blsoversample,
                    'blsntransits': blsmintransits,
                    'blsfreqfactor': blsfreqfactor,
                    'autofreq': autofreq,
                    'periodepsilon': periodepsilon,
                    'nbestpeaks': nbestpeaks,
                    'sigclip': sigclip,
                    'magsarefluxes': magsarefluxes
                }
            }

            return resultdict

        except Exception as e:

            LOGEXCEPTION('BLS failed!')

            if raiseonfail:
                raise

            return {
                'bestperiod': npnan,
                'bestlspval': npnan,
                'nbestinds': None,
                'nbestpeaks': nbestpeaks,
                'nbestlspvals': None,
                'nbestperiods': None,
                'lspvals': None,
                'periods': None,
                'durations': None,
                'blsresult': None,
                'blsmodel': None,
                'stepsize': stepsize,
                'nfreq': nfreq,
                'mintransitduration': mintransitduration,
                'maxtransitduration': maxtransitduration,
                'method': 'bls',
                'kwargs': {
                    'startp': startp,
                    'endp': endp,
                    'stepsize': stepsize,
                    'mintransitduration': mintransitduration,
                    'maxtransitduration': maxtransitduration,
                    'ndurations': ndurations,
                    'blsobjective': blsobjective,
                    'blsmethod': blsmethod,
                    'blsoversample': blsoversample,
                    'blsntransits': blsmintransits,
                    'blsfreqfactor': blsfreqfactor,
                    'autofreq': autofreq,
                    'periodepsilon': periodepsilon,
                    'nbestpeaks': nbestpeaks,
                    'sigclip': sigclip,
                    'magsarefluxes': magsarefluxes
                }
            }

    else:

        LOGERROR('no good detections for these times and mags, skipping...')
        return {
            'bestperiod': npnan,
            'bestlspval': npnan,
            'nbestinds': None,
            'nbestpeaks': nbestpeaks,
            'nbestlspvals': None,
            'nbestperiods': None,
            'lspvals': None,
            'periods': None,
            'durations': None,
            'blsresult': None,
            'blsmodel': None,
            'stepsize': stepsize,
            'nfreq': None,
            'nphasebins': None,
            'mintransitduration': mintransitduration,
            'maxtransitduration': maxtransitduration,
            'method': 'bls',
            'kwargs': {
                'startp': startp,
                'endp': endp,
                'stepsize': stepsize,
                'mintransitduration': mintransitduration,
                'maxtransitduration': maxtransitduration,
                'ndurations': ndurations,
                'blsobjective': blsobjective,
                'blsmethod': blsmethod,
                'blsoversample': blsoversample,
                'blsntransits': blsmintransits,
                'blsfreqfactor': blsfreqfactor,
                'autofreq': autofreq,
                'periodepsilon': periodepsilon,
                'nbestpeaks': nbestpeaks,
                'sigclip': sigclip,
                'magsarefluxes': magsarefluxes
            }
        }
コード例 #17
0
def find_and_mask_transits(time,
                           flux,
                           flux_err,
                           periods,
                           durations,
                           nplanets=1):
    """
    Iteratively find and mask transits in the flattened light curve.

    Args:
        time (array): The time array.
        flux (array): The flux array. You'll get the best results
            if this is flattened.
        flux_err (array): The array of flux uncertainties.
        periods (array): The array of periods to search over for BLS.
            For example, periods = np.linspace(0.5, 20, 10)
        durations (array): The array of durations to search over for BLS.
            For example, durations = np.linspace(0.05, 0.2, 10)
        nplanets (Optional[int]): The number of planets you'd like to search for.
            This function will interatively find and remove nplanets. Default is 1.

    Returns:
        transit_masks (list): a list of masks that correspond to the in
            transit points of each light curve. To mask out transits do
            time[~transit_masks[index]], etc.
    """

    cum_transit = np.ones(len(time), dtype=bool)
    _time, _flux, _flux_err = time * 1, flux * 1, flux_err * 1

    t0s, durs, porbs = [np.zeros(nplanets) for i in range(3)]
    transit_masks = []
    for i in range(nplanets):
        bls = BoxLeastSquares(t=_time, y=_flux, dy=_flux_err)
        bls.power(periods, durations)

        print("periods")
        periods = bls.autoperiod(durations,
                                 minimum_n_transit=3,
                                 frequency_factor=5.0)
        print("results")
        results = bls.autopower(durations, frequency_factor=5.0)

        # Find the period of the peak
        print("find_period")
        period = results.period[np.argmax(results.power)]

        print("extract")
        # Extract the parameters of the best-fit model
        index = np.argmax(results.power)
        porbs[i] = results.period[index]
        t0s[i] = results.transit_time[index]
        durs[i] = results.duration[index]

        # # Plot the periodogram
        # fig, ax = plt.subplots(1, 1, figsize=(10, 5))
        # ax.plot(results.period, results.power, "k", lw=0.5)
        # ax.set_xlim(results.period.min(), results.period.max())
        # ax.set_xlabel("period [days]")
        # ax.set_ylabel("log likelihood")

        # # Highlight the harmonics of the peak period
        # ax.axvline(period, alpha=0.4, lw=4)
        # for n in range(2, 10):
        #     ax.axvline(n*period, alpha=0.4, lw=1, linestyle="dashed")
        #     ax.axvline(period / n, alpha=0.4, lw=1, linestyle="dashed")
        # plt.show()

        # plt.plot(_time, _flux, ".")
        # plt.xlim(1355, 1360)

        print("mask")
        in_transit = bls.transit_mask(_time, porbs[i], 2 * durs[i], t0s[i])
        transit_masks.append(in_transit)
        _time, _flux, _flux_err = _time[~in_transit], _flux[~in_transit], \
            _flux_err[~in_transit]

    return transit_masks, t0s, durs, porbs
コード例 #18
0
ファイル: giants.py プロジェクト: skgrunblatt/giants
    def validate_transit(self, ticid=None, lc=None, rprs=0.02):
        """Take a closer look at potential transit signals."""
        from .plotting import create_starry_model

        if ticid is not None:
            lc = self.from_eleanor(ticid)[1]
            lc = self._clean_data(lc)
        elif lc is None:
            lc = self.lc

        model = BoxLeastSquares(lc.time, lc.flux)
        results = model.autopower(0.16)
        period = results.period[np.argmax(results.power)]
        t0 = results.transit_time[np.argmax(results.power)]
        if rprs is None:
            depth = results.depth[np.argmax(results.power)]
            rprs = depth**2

        # create the model
        model_flux = create_starry_model(
            lc.time, period=period, t0=t0, rprs=rprs) - 1
        model_lc = lk.LightCurve(time=lc.time, flux=model_flux)

        fig, ax = plt.subplots(3, 1, figsize=(12, 14))
        fig.patch.set_facecolor('white')
        '''
        Plot unfolded transit
        ---------------------
        '''
        lc.scatter(ax=ax[0], c='k', label='Corrected Flux')
        model_lc.plot(ax=ax[0], c='r', lw=2, label='Transit Model')
        ax[0].set_ylim([-.002, .002])
        ax[0].set_xlim([lc.time[0], lc.time[-1]])
        '''
        Plot folded transit
        -------------------
        '''
        lc.fold(period, t0).scatter(ax=ax[1],
                                    c='k',
                                    label=f'P={period:.3f}, t0={t0}')
        lc.fold(period, t0).bin(binsize=7).plot(ax=ax[1],
                                                c='b',
                                                label='binned',
                                                lw=2)
        model_lc.fold(period, t0).plot(ax=ax[1],
                                       c='r',
                                       lw=2,
                                       label="transit Model")
        ax[1].set_xlim([-0.5, .5])
        ax[1].set_ylim([-.002, .002])
        '''
        Zoom folded transit
        -------------------
        '''
        lc.fold(period, t0).scatter(ax=ax[2],
                                    c='k',
                                    label=f'folded at {period:.3f} days')
        lc.fold(period, t0).bin(binsize=7).plot(ax=ax[2],
                                                c='b',
                                                label='binned',
                                                lw=2)
        model_lc.fold(period, t0).plot(ax=ax[2],
                                       c='r',
                                       lw=2,
                                       label="transit Model")
        ax[2].set_xlim([-0.1, .1])
        ax[2].set_ylim([-.002, .002])

        ax[0].set_title(f'{ticid}', fontsize=14)

        plt.show()
コード例 #19
0
ファイル: strago.py プロジェクト: astrofelipe/Strago
#Full lightcurve
plot = figure(plot_height=200,
              plot_width=1000,
              title='Curva de luz',
              x_range=[np.nanmin(t), np.nanmax(t)])

plot.xaxis.axis_label = 'Tiempo (dias)'
plot.yaxis.axis_label = 'Flujo'

plot.circle('t', 'f', source=src, size=1)
#plot.line('t', 'trn', source=ndata, line_width=1, color='lime')

#BLS
print('Calculando período...')
durations = np.linspace(0.05, 0.2, 60)
model = BLS(t, f)
result = model.autopower(durations, frequency_factor=2.0)
idx = np.argmax(result.power)
per = result.period[idx] if args.period is None else args.period

pgram = figure(width=1000,
               height=200,
               x_range=[0, 20],
               title='Periodograma (BLS)')
pgram.xaxis.axis_label = 'Periodo'
pgram.yaxis.axis_label = 'Potencia'
freqs = 1 / np.arange(1 / 30., 1 / 30. + 50000 * 1e-4, 1e-4)

#blsda = ColumnDataSource(data=dict(per=freqs, pow=blsre[0]))
#pgram.line('per', 'pow', source=blsda)
print('Done!')