Ejemplo n.º 1
0
def inject_signal(time, ap_mag, inj_dict):

    # mags to flux
    f_x0 = 1e4
    m_x0 = 10
    ap_flux = f_x0 * 10**(-0.4 * (ap_mag - m_x0))
    ap_flux /= np.nanmedian(ap_flux)

    # ignore the times near the edges of orbits for TLS.
    time, flux = moe.mask_orbit_start_and_end(time,
                                              ap_flux,
                                              raise_expectation_error=False)

    # initialize model to inject: 90 degrees, LD coeffs for 5000 K dwarf star
    # in TESS band (Claret 2018) no eccentricity, random phase, b=0, stellar
    # density set to 1.5x solar.  Eq (30) Winn 2010 to get a/Rstar.
    params = batman.TransitParams()

    density_sun = 3 * u.Msun / (4 * np.pi * u.Rsun**3)
    density_star = 1.5 * density_sun
    a_by_rstar = ((c.G * (inj_dict['period'] * u.day)**2 / (3 * np.pi) *
                   density_star)**(1 / 3)).cgs.value

    params.inc = 90.
    q1, q2 = 0.4, 0.2
    params.ecc = 0
    params.limb_dark = "quadratic"
    params.u = [q1, q2]
    w = np.random.uniform(low=np.rad2deg(-np.pi), high=np.rad2deg(np.pi))
    params.w = w
    params.per = inj_dict['period']
    t0 = np.nanmin(time) + inj_dict['epoch']
    params.t0 = t0
    params.rp = np.sqrt(inj_dict['depth'])
    params.a = a_by_rstar

    exp_time_minutes = 30.
    exp_time_days = exp_time_minutes / (24. * 60)
    ss_factor = 10

    m_toinj = batman.TransitModel(params,
                                  time,
                                  supersample_factor=ss_factor,
                                  exp_time=exp_time_days)

    # calculate light curve and inject
    flux_toinj = m_toinj.light_curve(params)
    inj_flux = flux + (flux_toinj - 1.) * np.nanmedian(flux)

    return time, inj_flux, t0
Ejemplo n.º 2
0
def explore_flux_lightcurves(
    data, ticid, outdir=None, period=None, epoch=None, pipeline=None,
    detrend=False, window_length=None, do_phasefold=0, badtimewindows=None,
    get_lc=False, require_quality_zero=1, forceylim=None, normstitch=True,
    slideclipdict={'window_length':1, 'high':3, 'low':8},
    mask_orbit_edges=False
):
    """
    Given a list of SPOC 2 minute data FITS tables, stitch them across sectors
    and make diagnostic plots.

    Args:

        data (list): from `get_tess_data`, contents [hdulistA[1].data,
            hdulistB[1].data], etc..

        ticid (str): TIC ID.

        pipeline (str): one of ['cdips', 'spoc', 'eleanor', 'cdipspre',
        'kepler', 'qlp'].  This is used to access the flux, provenance, etc.

        outdir (str): diagnostic plots are written here. If None, goes to
        cdips_followup results directory.

    Optional kwargs:

        period, epoch (float): optional

        detrend (bool, or string): 'biweight' or 'pspline' accepted. Default
        parameters assumed for each.

        badtimewindows (list): to manually mask out, [(1656, 1658), (1662,
            1663)], for instance.

        get_lc (bool): if True, returns time and flux arrays.

        require_quality_zero (bool): if True, sets QUALITY==0, throwing out
        lots of data.

        normstitch (bool): normalize flux across sectors s.t. the relative
        amplitude remains fixed.

        slideclipdict (dict): e.g., {'window_length':1, 'high':3, 'low':8} for
        1 day sliding window, exclude +3MAD from median above and -8MAD from
        median below.
    """

    assert isinstance(data, list), 'Expected list of FITStables.'

    if pipeline not in ['spoc', 'kepler', 'qlp', 'cdips']:
        raise NotImplementedError

    if isinstance(epoch, float):
        if epoch < 2450000:
            raise ValueError(f'Expected epoch in BJDTDB. Got epoch={epoch:.6f}.')

    ykey = LCKEYDICT[pipeline]['flux']
    xkey = LCKEYDICT[pipeline]['time']
    qualkey = LCKEYDICT[pipeline]['quality']
    prov = LCKEYDICT[pipeline]['prov']
    inst = LCKEYDICT[pipeline]['inst']

    if outdir is None:
        outdir = os.path.join(RESULTSDIR, 'quicklooklc', f'TIC{ticid}')

    times, fluxs= [], []
    for ix, d in enumerate(data):

        savpath = os.path.join(
            outdir, f'TIC{ticid}_{prov}_{inst}_lightcurve_{str(ix).zfill(2)}.png'
        )
        if detrend:
            savpath = os.path.join(
                outdir, f'TIC{ticid}_{prov}_{inst}_lightcurve_{detrend}_{str(ix).zfill(2)}.png'
            )

        plt.close('all')
        f,ax = plt.subplots(figsize=(16*2,4*1.5))

        if require_quality_zero:
            okkey = 0 if pipeline in 'spoc,kepler,qlp'.split(',') else 'G'
            sel = (d[qualkey] == okkey) & (d[ykey] > 0)
            print(42*'.')
            print('WRN!: omitting all non-zero quality flags. throws out good data!')
            print(42*'.')
        else:
            sel = (d[ykey] > 0)
        if badtimewindows is not None:
            for w in badtimewindows:
                sel &= ~(
                    (d[xkey] > w[0])
                    &
                    (d[xkey] < w[1])
                )

        # correct time column to BJD_TDB
        x_offset = LCKEYDICT[pipeline]['time_offset']
        x_obs = d[xkey][sel] + x_offset

        # get the median-normalized flux
        y_obs = d[ykey][sel]
        if pipeline == 'cdips':
            y_obs, _ = _given_mag_get_flux(y_obs, y_obs*1e-3)
        y_obs /= np.nanmedian(y_obs)

        if mask_orbit_edges:
            x_obs, y_obs, _ = moe.mask_orbit_start_and_end(
                x_obs, y_obs, raise_expectation_error=False, orbitgap=0.7,
                orbitpadding=12/(24),
                return_inds=True
            )

        # slide clip -- remove outliers with windowed stdevn removal
        if isinstance(slideclipdict, dict):
            y_obs = slide_clip(x_obs, y_obs, slideclipdict['window_length'],
                               low=slideclipdict['low'],
                               high=slideclipdict['high'], method='mad',
                               center='median')


        if detrend:
            ax.scatter(x_obs, y_obs, c='k', s=4, zorder=2)

            # # default pspline detrending
            if detrend=='pspline':
                y_obs, y_trend = dtr.detrend_flux(x_obs, y_obs)
                x_trend = deepcopy(x_obs)

            # in some cases, might prefer the biweight
            elif detrend == 'biweight':
                y_obs, y_trend = dtr.detrend_flux(x_obs, y_obs,
                                                  method='biweight', cval=5,
                                                  window_length=0.5,
                                                  break_tolerance=0.5)
                x_trend = deepcopy(x_obs)

            elif detrend == 'minimal':
                y_obs, y_trend = dtr.detrend_flux(x_obs, y_obs,
                                                  method='biweight', cval=2,
                                                  window_length=3.5,
                                                  break_tolerance=0.5)
                x_trend = deepcopy(x_obs)

            elif detrend == 'median':
                y_obs, y_trend = dtr.detrend_flux(x_obs, y_obs,
                                                  method='median',
                                                  window_length=0.6,
                                                  break_tolerance=0.5,
                                                  edge_cutoff=0.)
                x_trend = deepcopy(x_obs)

            elif detrend == 'best':
                from cdips.lcproc.find_planets import run_periodograms_and_detrend
                dtr_dict = {'method':'best', 'break_tolerance':0.5, 'window_length':0.5}
                lsp_options = {'period_min':0.1, 'period_max':20}

                # r = [source_id, ls_period, ls_fap, ls_amplitude, tls_period, tls_sde,
                #      tls_t0, tls_depth, tls_duration, tls_distinct_transit_count,
                #      tls_odd_even, dtr_method]

                r, search_time, search_flux, dtr_stages_dict = run_periodograms_and_detrend(
                    ticid, x_obs, y_obs, dtr_dict,
                    period_min=lsp_options['period_min'],
                    period_max=lsp_options['period_max'], dtr_method='best',
                    return_extras=True,
                    magisflux=True
                )
                y_trend, x_trend, dtr_method = (
                    dtr_stages_dict['trend_flux'],
                    dtr_stages_dict['trend_time'],
                    dtr_stages_dict['dtr_method_used']
                )
                x_obs, y_obs = deepcopy(search_time), deepcopy(search_flux)
                print(f'TIC{ticid} TLS results')
                print(f'dtr_method_used: {dtr_method}')
                print(r)

            else:
                raise NotImplementedError

        if detrend:
            ax.plot(x_trend, y_trend, c='r', lw=0.5, zorder=3)
        else:
            ax.scatter(x_obs, y_obs, c='k', s=4, zorder=2)

        times.append( x_obs )
        fluxs.append( y_obs )

        ax.set_xlabel('time [bjdtdb]')
        ax.set_ylabel(ykey)
        ylim = ax.get_ylim()

        ax.set_title(ix)

        if detrend:
            _ylim = _get_ylim(y_trend)
        else:
            _ylim = _get_ylim(y_obs)

        ax.set_ylim(_ylim)
        if isinstance(forceylim, list) or isinstance(forceylim, tuple):
            ax.set_ylim(forceylim)

        if not epoch is None:
            tra_times = epoch + np.arange(-1000,1000,1)*period

            xlim = ax.get_xlim()
            ylim = ax.get_ylim()

            ax.set_ylim((min(ylim), max(ylim)))
            ax.vlines(tra_times, min(ylim), max(ylim), color='orangered',
                      linestyle='--', zorder=-2, lw=0.5, alpha=0.3)
            ax.set_ylim((min(ylim), max(ylim)))
            ax.set_xlim(xlim)

        f.savefig(savpath, dpi=300, bbox_inches='tight')
        print('made {}'.format(savpath))

    if normstitch:
        times, fluxs, _ = lcu.stitch_light_curves(
            times, fluxs, fluxs, magsarefluxes=True, normstitch=True
        )
    else:
        times = np.hstack(np.array(times).flatten())
        fluxs = np.hstack(np.array(fluxs).flatten())

    # NOTE: this call is deprecated
    stimes, smags, _ = lcmath.sigclip_magseries(
        times, fluxs, np.ones_like(fluxs), sigclip=[20,20], iterative=True,
        magsarefluxes=True
    )

    savpath = os.path.join(
        outdir, f'TIC{ticid}_{prov}_{inst}_lightcurve_{str(ykey).zfill(2)}_allsector.png'
    )
    if detrend:
        savpath = os.path.join(
            outdir, f'TIC{ticid}_{prov}_{inst}_lightcurve_{detrend}_{str(ykey).zfill(2)}_allsector.png'
        )

    plt.close('all')
    f,ax = plt.subplots(figsize=(16,4))

    ax.scatter(stimes, smags, c='k', s=1)

    if not epoch is None:
        tra_times = epoch + np.arange(-1000,1000,1)*period

        xlim = ax.get_xlim()
        ylim = ax.get_ylim()

        ax.set_ylim((min(ylim), max(ylim)))
        ax.vlines(tra_times, min(ylim), max(ylim), color='orangered',
                  linestyle='--', zorder=-2, lw=0.5, alpha=0.3)
        ax.set_ylim((min(ylim), max(ylim)))
        ax.set_xlim(xlim)

    ax.set_xlabel('time [bjdtdb]')
    ax.set_ylabel('relative '+ykey)

    ax.set_title(ix)

    f.savefig(savpath, dpi=400, bbox_inches='tight')
    print('made {}'.format(savpath))

    csvpath = savpath.replace('.png','_sigclipped.csv')
    pd.DataFrame({
        'time': stimes, 'flux': smags,
    }).to_csv(csvpath, index=False)
    print(f'made {csvpath}')


    if do_phasefold:

        assert (
            isinstance(period, (float,int)) and isinstance(epoch, (float,int))
        )

        #
        # ax: primary transit
        #
        if inst == 'kepler':
            phasebin = 1e-3
        elif inst == 'tess':
            phasebin = 5e-3
        minbinelems = 2
        plotxlims = [(-0.5, 0.5), (-0.05,0.05)]
        xlimstrs = ['xwide','xnarrow']
        plotylim = [0.9, 1.08]#None #[0.9,1.1]
        do_vlines = False

        for plotxlim, xstr in zip(plotxlims, xlimstrs):

            plt.close('all')
            fig, ax = plt.subplots(figsize=(4,3))

            # use times and fluxs, instead of the sigma clipped thing.
            _make_phased_magseries_plot(ax, 0, times, fluxs,
                                        np.ones_like(fluxs)/1e4, period, epoch,
                                        True, True, phasebin, minbinelems,
                                        plotxlim, '', xliminsetmode=False,
                                        magsarefluxes=True, phasems=0.8,
                                        phasebinms=4.0, verbose=True)
            if isinstance(plotylim, (list, tuple)):
                ax.set_ylim(plotylim)
            else:
                plotylim = _get_ylim(fluxs)
                ax.set_ylim(plotylim)

            if do_vlines:
                ax.vlines(1/6, min(plotylim), max(plotylim), color='orangered',
                          linestyle='--', zorder=-2, lw=1, alpha=0.8)
                ax.set_ylim(plotylim)

            dstr = detrend if detrend else ''
            savpath = os.path.join(
                outdir, f'TIC{ticid}_{prov}_{inst}_lightcurve_{dstr}_{ykey}_{xstr}_allsector_phasefold.png'
            )

            fig.savefig(savpath, dpi=400, bbox_inches='tight')
            print(f'made {savpath}')

        csvpath = savpath.replace('png','csv')
        pd.DataFrame({
            'time': times, 'flux': fluxs
        }).to_csv(csvpath, index=False)
        print(f'made {csvpath}')

    if get_lc:
        return times, fluxs
Ejemplo n.º 3
0
def get_toi1937_lightcurve():
    """
    Create the stitched CDIPS FFI light curve for TOI 1937. (Starting from the
    raw light curves, and the PCA eigenvectors previously made for this
    sector). Note: the main execution of this PCA detrending happens on
    phtess2.

    A few notes:
        * 3 eigenvectors were used, plus the background light BGV timeseries.
        * a +/-12 hour orbit edge mask was used (to avoid what looked like
        scattered light)
        * the output can be checked at
        /results/quicklook_lcs/5489726768531119616_allvar_report.pdf
    """

    picklepath = os.path.join(PHOTDIR,
                              'toi1937_merged_stitched_s7s9_lc_20201130.pkl')

    if not os.path.exists(picklepath):

        # Use the CDIPS IRM2 light curves as starting base.
        # 5489726768531119616_s09_llc.fits
        lcpaths = glob(os.path.join(PHOTDIR, '*_s??_llc.fits'))
        assert len(lcpaths) == 2

        infodicts = [
            {
                'SECTOR': 7,
                'CAMERA': 3,
                'CCD': 4,
                'PROJID': 1527
            },
            {
                'SECTOR': 9,
                'CAMERA': 3,
                'CCD': 3,
                'PROJID': 1558
            },
        ]

        ##########################################
        # next ~45 lines pinched from cdips.drivers.do_allvariable_report_making
        ##########################################
        #
        # detrend systematics. each light curve yields tuples of:
        #   primaryhdr, data, ap, dtrvecs, eigenvecs, smooth_eigenvecs
        #
        dtr_infos = []
        for lcpath, infodict in zip(lcpaths, infodicts):
            dtr_info = dtr.detrend_systematics(lcpath,
                                               infodict=infodict,
                                               max_n_comp=3)
            dtr_infos.append(dtr_info)

        #
        # stitch all available light curves
        #
        ap = dtr_infos[0][2]
        timelist = [d[1]['TMID_BJD'] for d in dtr_infos]
        maglist = [d[1][f'PCA{ap}'] for d in dtr_infos]
        magerrlist = [d[1][f'IRE{ap}'] for d in dtr_infos]

        extravecdict = {}
        extravecdict[f'IRM{ap}'] = [d[1][f'IRM{ap}'] for d in dtr_infos]
        for i in range(0, 7):
            extravecdict[f'CBV{i}'] = [d[3][i, :] for d in dtr_infos]

        time, flux, fluxerr, vec_dict = lcu.stitch_light_curves(
            timelist, maglist, magerrlist, extravecdict)

        #
        # mask orbit edges
        #
        s_time, s_flux, inds = moe.mask_orbit_start_and_end(
            time,
            flux,
            raise_expectation_error=False,
            orbitgap=0.7,
            orbitpadding=12 / 24,
            return_inds=True)
        s_fluxerr = fluxerr[inds]

        #
        # save output
        #

        ap = dtr_infos[0][2]
        lcdict = {
            'source_id': np.int64(5489726768531119616),
            'E_BpmRp': 0.1343,
            'ap': ap,
            'TMID_BJD': time,
            f'IRM{ap}': vec_dict[f'IRM{ap}'],
            f'PCA{ap}': flux,
            f'IRE{ap}': fluxerr,
            'STIME': s_time.astype(np.float64),
            f'SPCA{ap}': s_flux.astype(np.float64),
            f'SPCAE{ap}': s_fluxerr.astype(np.float64),
            'dtr_infos': dtr_infos,
            'vec_dict': vec_dict,
            'tess_texp': np.nanmedian(np.diff(s_time))
        }

        with open(picklepath, 'wb') as f:
            pickle.dump(lcdict, f)

        #
        # verify output
        #
        from cdips.plotting.allvar_report import make_allvar_report
        plotdir = os.path.join(RESULTSDIR, 'quicklook_lcs')
        outd = make_allvar_report(lcdict, plotdir)

    with open(picklepath, 'rb') as f:
        print(f'Found {picklepath}: loading it!')
        lcdict = pickle.load(f)

    return (lcdict['STIME'].astype(np.float64) - 2457000,
            lcdict['SPCA2'].astype(np.float64),
            lcdict['SPCAE2'].astype(np.float64), lcdict['tess_texp'])
Ejemplo n.º 4
0
def get_clean_ptfo_data(binsize=120 * 5):
    """
    get data. mask orbit edges... quality cut and remove weird end points. bin to 10 minutes, to
    speed fitting (which is linear in time).
    """

    d = get_ptfo_data(cdips=0, spoc=1)[0]

    time = d.TIME
    flux = d.PDCSAP_FLUX
    flux_err = d.PDCSAP_FLUX_ERR

    N_i = len(time)  # initial

    quality = d.QUALITY
    time, flux, flux_err = (time[quality == 0], flux[quality == 0],
                            flux_err[quality == 0])

    N_ii = len(time)  # after quality cut

    time, flux, sel = mask_orbit_start_and_end(time,
                                               flux,
                                               orbitgap=0.5,
                                               expected_norbits=2,
                                               orbitpadding=6 / (24),
                                               raise_expectation_error=True,
                                               return_inds=True)
    flux_err = flux_err[sel]

    N_iii = len(time)  # after orbit edge masking

    # 2457000 + 1488.3 = 2458488.3
    sel = (time < 1488.3)

    x_obs = time[sel]

    time_offset = 1468.2
    x_obs -= time_offset
    # reverse offset: 2457000 + 1468.2 = 2458468.2

    N_iv = len(x_obs)  # after dropping end of orbit 20

    y_obs = (flux[sel] / np.nanmedian(flux[sel])) - 1
    y_err = flux_err[sel] / np.nanmedian(flux[sel])

    print(42 * '-')
    print('N initial: {}'.format(N_i))
    print('N after quality cut: {}'.format(N_ii))
    print('N after quality cut + orbit edge masking: {}'.format(N_iii))
    print(
        'N after quality cut + orbit edge masking + dropping end of orbit 20: {}'
        .format(N_iv))
    print(42 * '-')

    if isinstance(binsize, int):
        bd = time_bin_magseries_with_errs(x_obs,
                                          y_obs,
                                          y_err,
                                          binsize=binsize,
                                          minbinelems=5)
        x_obs = bd['binnedtimes']
        y_obs = bd['binnedmags']

        # assume errors scale as sqrt(N)
        original_cadence = 120
        y_err = bd['binnederrs'] / (binsize / original_cadence)**(1 / 2)

    assert len(x_obs) == len(y_obs) == len(y_err)

    return (x_obs.astype(np.float64), y_obs.astype(np.float64),
            y_err.astype(np.float64))
Ejemplo n.º 5
0
def clean_rotationsignal_tess_singlesector_light_curve(time,
                                                       mag,
                                                       magisflux=False,
                                                       dtr_dict=None,
                                                       lsp_dict=None,
                                                       maskorbitedge=True,
                                                       lsp_options={
                                                           'period_min': 0.1,
                                                           'period_max': 20
                                                       },
                                                       verbose=True):
    """
    The goal of this function is to remove a stellar rotation signal from a
    single TESS light curve (ideally one without severe insturmental
    systematics) while preserving transits.

    "Cleaning" by default is taken to mean the sequence of mask_orbit_edge ->
    slide_clip -> detrend -> slide_clip.  "Detrend" can mean any of the Wotan
    flatteners, Notch, or LOCOR. "slide_clip" means apply windowed
    sigma-clipping removal.

    Args:
        time, mag (np.ndarray): time and magnitude (or flux) vectors

        magisflux (bool): True if the "mag" vector is a flux already

        dtr_dict (optional dict): dictionary containing arguments passed to
        Wotan, Notch, or LOCOR. Relevant keys should include:

            'dtr_method' (str): one of: ['best', 'notch', 'locor', 'pspline',
            'biweight', 'none']

            'break_tolerance' (float): number of days past which a segment of
            light curve is considered a "new segment".

            'window_length' (float): length of sliding window in days

        lsp_dict (optional dict): dictionary containing Lomb Scargle
        periodogram information, which is used in the "best" method for
        choosing between LOCOR or Notch detrending.  If this is not passed,
        it'll be constructed here after the mask_orbit_edge -> slide_clip
        steps.

        lsp_options: contains keys period_min and period_max, used for the
        internal Lomb Scargle periodogram search.

        maskorbitedge (bool): whether to apply the initial "mask_orbit_edge"
        step. Probably would only want to be false if you had already done it
        elsewhere.

    Returns:
        search_time, search_flux, dtr_stages_dict (np.ndarrays and dict): light
            curve ready for TLS or BLS style periodograms; and a dictionary of
            the different processing stages (see comments for details of
            `dtr_stages_dict` contents).
    """

    dtr_method = _get_detrending_method(dtr_dict)

    #
    # convert mag to flux and median-normalize
    #
    if magisflux:
        flux = mag
    else:
        f_x0 = 1e4
        m_x0 = 10
        flux = f_x0 * 10**(-0.4 * (mag - m_x0))

    flux /= np.nanmedian(flux)

    #
    # ignore the times near the edges of orbits for TLS.
    #
    if maskorbitedge:
        _time, _flux = moe.mask_orbit_start_and_end(
            time, flux, raise_expectation_error=False, verbose=verbose)
    else:
        _time, _flux = time, flux

    #
    # sliding sigma clip asymmetric [20,3]*MAD, about median. use a 3-day
    # window, to give ~100 to 150 data points. mostly to avoid big flares.
    #
    clip_window = 3
    clipped_flux = slide_clip(_time,
                              _flux,
                              window_length=clip_window,
                              low=20,
                              high=3,
                              method='mad',
                              center='median')
    sel0 = ~np.isnan(clipped_flux)

    #
    # for "best" or LOCOR detrending, you need to know the stellar rotation
    # period.  so, if it hasn't already been run, run the LS periodogram here.
    # in `lsp_dict`, cache the LS peak period, amplitude, and FAP.
    #
    if (not isinstance(lsp_dict, dict)) and (dtr_method in ['locor', 'best']):

        period_min = lsp_options['period_min']
        period_max = lsp_options['period_max']

        ls = LombScargle(_time[sel0], clipped_flux[sel0],
                         clipped_flux[sel0] * 1e-3)
        freq, power = ls.autopower(minimum_frequency=1 / period_max,
                                   maximum_frequency=1 / period_min)
        ls_fap = ls.false_alarm_probability(power.max())
        best_freq = freq[np.argmax(power)]
        ls_period = 1 / best_freq
        theta = ls.model_parameters(best_freq)
        ls_amplitude = theta[1]

        lsp_dict = {}
        lsp_dict['ls_period'] = ls_period
        lsp_dict['ls_amplitude'] = np.abs(ls_amplitude)
        lsp_dict['ls_fap'] = ls_fap

    if not isinstance(dtr_dict, dict):
        dtr_dict = {}
        dtr_dict['method'] = dtr_method

    #
    # apply the detrending call based on the method given
    #

    dtr_method_used = dtr_method

    if dtr_method in ['pspline', 'biweight', 'none']:

        if 'break_tolerance' not in dtr_dict:
            dtr_dict['break_tolerance'] = None
        if 'window_length' not in dtr_dict:
            dtr_dict['window_length'] = None

        flat_flux, trend_flux = detrend_flux(
            _time[sel0],
            clipped_flux[sel0],
            break_tolerance=dtr_dict['break_tolerance'],
            method=dtr_dict['method'],
            cval=None,
            window_length=dtr_dict['window_length'],
            edge_cutoff=None)

    elif dtr_method == 'notch':

        flat_flux, trend_flux, notch = _run_notch(_time[sel0],
                                                  clipped_flux[sel0],
                                                  dtr_dict,
                                                  verbose=verbose)

    elif dtr_method == 'locor':

        flat_flux, trend_flux, notch = _run_locor(_time[sel0],
                                                  clipped_flux[sel0], dtr_dict,
                                                  lsp_dict)

    elif dtr_method == 'best':

        # for stars with Prot < 1 day, use LOCOR.  for stars with Prot > 1 day,
        # use Notch.  (or pspline?).
        PERIOD_CUTOFF = 1.0

        if lsp_dict['ls_period'] > PERIOD_CUTOFF:
            flat_flux, trend_flux, notch = _run_notch(_time[sel0],
                                                      clipped_flux[sel0],
                                                      dtr_dict,
                                                      verbose=verbose)
            dtr_method_used += '-notch'
        elif (lsp_dict['ls_period'] < PERIOD_CUTOFF
              and lsp_dict['ls_period'] > 0):
            flat_flux, trend_flux, notch = _run_locor(_time[sel0],
                                                      clipped_flux[sel0],
                                                      dtr_dict, lsp_dict)
            dtr_method_used += '-locor'
        else:
            raise NotImplementedError(f"Got LS period {lsp_dict['ls_period']}")

    #
    # re-apply sliding sigma clip asymmetric [20,3]*MAD, about median, after
    # detrending.
    #
    clip_window = 3
    clipped_flat_flux = slide_clip(_time[sel0],
                                   flat_flux,
                                   window_length=clip_window,
                                   low=20,
                                   high=3,
                                   method='mad',
                                   center='median')
    sel1 = ~np.isnan(clipped_flat_flux)

    search_flux = clipped_flat_flux[sel1]
    search_time = _time[sel0][sel1]

    dtr_stages_dict = {
        # non-nan indices from clipped_flux
        'sel0': sel0,
        # non-nan indices from clipped_flat_flux
        'sel1': sel1,
        # after initial window sigma_clip on flux, what is left?
        'clipped_flux': clipped_flux,
        # after detrending, what is left?
        'flat_flux': flat_flux,
        # after window sigma_clip on flat_flux, what is left?
        'clipped_flat_flux': clipped_flat_flux,
        # what does the detrending algorithm give as the "trend"?
        'trend_flux': trend_flux,
        'trend_time': _time[sel0],
        # what method was used? if "best", gives "best-notch" or "best-locor"
        'dtr_method_used': dtr_method_used,
        # times and fluxes used
        'search_time': search_time,
        'search_flux': search_flux
    }
    if isinstance(lsp_dict, dict):
        # in most cases, cache the LS period, amplitude, and FAP
        dtr_stages_dict['lsp_dict'] = lsp_dict

    return search_time, search_flux, dtr_stages_dict
Ejemplo n.º 6
0
def plot_phase(fpath,
               ax,
               ind,
               s=3,
               alpha=0.3,
               lctype='IRM2',
               periodogramtype=None,
               peakindex=0,
               plot_bin_phase=False,
               overwritecsv=1):

    outsavpath = os.path.join(
        OUTDIR,
        'quilt_s6_s7_' + os.path.basename(fpath).replace('.fits', '.csv'))

    if os.path.exists(outsavpath) and not overwritecsv:
        df = pd.read_csv(outsavpath)
        phase = nparr(df['phase'])
        phz_flux = nparr(df['phz_flux'])
        period = nparr(df['period'])[0]

    else:
        #
        # get data. fpath here is a fits LC file. apply the periodogram requested.
        #
        time = iu.get_data_keyword(fpath, 'TMID_BJD', ext=1)
        mag = iu.get_data_keyword(fpath, lctype, ext=1)

        f_x0 = 1e4
        m_x0 = 10
        flux = f_x0 * 10**(-0.4 * (mag - m_x0))
        flux /= np.nanmedian(flux)

        time, flux = moe.mask_orbit_start_and_end(time, flux)

        # fit out long term trend (light detrending) with median filter of 5 days.
        if 'IRM' in lctype:
            ngroups, groups = lcmath.find_lc_timegroups(time, mingap=0.5)
            assert ngroups == 2

            windowsize = 48 * 5 + 1  # 5 days
            tg_smooth_flux = []
            for group in groups:

                #
                # fit out arbitrary order legendre series
                # p(x) = c_0*L_0(x) + c_1*L_1(x) + c_2*L_2(x) + ... + c_n*L_n(x)
                #
                legendredeg = 2
                p = Legendre.fit(time[group], flux[group], legendredeg)
                coeffs = p.coef
                fit_flux = p(time[group])

                tg_smooth_flux.append(flux[group] / fit_flux)

            flux = np.concatenate(tg_smooth_flux)

        if periodogramtype == 'tls':
            period_min, period_max = 0.5, 5
            tlsp = periodbase.tls_parallel_pfind(
                time,
                flux,
                1e-3 * flux,
                magsarefluxes=True,
                tls_rstar_min=0.1,
                tls_rstar_max=10,
                tls_mstar_min=0.1,
                tls_mstar_max=5.0,
                tls_oversample=8,
                tls_mintransits=1,
                tls_transit_template='default',
                nbestpeaks=5,
                sigclip=None,
                nworkers=52)

            period = tlsp['nbestperiods'][peakindex]
            t0 = tlsp['tlsresult']['T0']
            if peakindex == 1:
                t0 += period / 2

        elif periodogramtype == 'gls':
            period_min, period_max = 0.1, 5
            ls = LombScargle(time, flux, flux * 1e-3)
            freq, power = ls.autopower(minimum_frequency=1 / period_max,
                                       maximum_frequency=1 / period_min,
                                       samples_per_peak=20)
            period = 1 / freq[np.argmax(power)]
            t0 = time[np.argmin(flux)]

        else:
            raise NotImplementedError(
                'got {}, not imlemented'.format(periodogramtype))

        #
        # phase data
        #
        phzd = phase_magseries(time, flux, period, t0, wrap=True, sort=True)

        phase = phzd['phase']
        phz_flux = phzd['mags']

    #
    # plot data
    #
    ax.scatter(phase,
               phz_flux,
               c='k',
               alpha=alpha,
               zorder=3,
               s=s,
               rasterized=True,
               linewidths=0)

    ax.text(0.88,
            0.03,
            '{:.2f}d'.format(period),
            transform=ax.transAxes,
            ha='right',
            va='bottom')

    ax.text(0.04,
            0.06,
            '{}'.format(ind),
            transform=ax.transAxes,
            ha='left',
            va='bottom')

    if overwritecsv:
        outdf = pd.DataFrame({
            'phase': phase,
            'phz_flux': phz_flux,
            'period': np.ones_like(phase) * period
        })
        outdf.to_csv(outsavpath, index=False)

    if plot_bin_phase:

        binphasedlc = phase_bin_magseries(phase,
                                          phz_flux,
                                          binsize=2e-2,
                                          minbinelems=3)
        binplotphase = binphasedlc['binnedphases']
        binplotmags = binphasedlc['binnedmags']

        ax.scatter(binplotphase,
                   binplotmags,
                   c='orange',
                   alpha=alpha,
                   zorder=4,
                   s=s,
                   rasterized=True,
                   linewidths=0)