def do_period_finding_fitslc(lcpath,
                             fluxap='TFA2',
                             period_min=0.5,
                             outdir=None):

    if not outdir:
        outdir = os.path.dirname(lcpath)
    outfile = os.path.basename(lcpath).replace('.fits',
                                               '_spdm_blsp_checkplot.png')
    outpath = os.path.join(outdir, outfile)
    if os.path.exists(outpath):
        print('found & skipped {}'.format(outpath))
        return

    hdulist = fits.open(lcpath)
    hdr, lc = hdulist[0].header, hdulist[1].data

    times, mags, errs = (lc['TMID_BJD'], lc[fluxap], np.ones_like(lc[fluxap]) *
                         np.nanmedian(lc[fluxap]) / 1000)

    #glsp = periodbase.pgen_lsp(times,mags,errs)
    spdm = periodbase.stellingwerf_pdm(times, mags, errs)
    blsp = periodbase.bls_parallel_pfind(times,
                                         mags,
                                         errs,
                                         startp=period_min,
                                         get_stats=False)

    objectinfo = {}
    keys = ['objectid', 'ra', 'decl', 'pmra', 'pmdecl', 'teff', 'gmag']
    hdrkeys = [
        'Gaia-ID', 'RA[deg]', 'Dec[deg]', 'PM_RA[mas/yr]', 'PM_Dec[mas/year]',
        'teff_val', 'phot_g_mean_mag'
    ]
    for k, hk in zip(keys, hdrkeys):
        if hk in hdr:
            objectinfo[k] = hdr[hk]
        else:
            objectinfo[k] = np.nan

    cp = checkplot.twolsp_checkplot_png(blsp,
                                        spdm,
                                        times,
                                        mags,
                                        errs,
                                        objectinfo=objectinfo,
                                        outfile=outpath,
                                        sigclip=[50., 5.],
                                        plotdpi=100,
                                        phasebin=3e-2,
                                        phasems=6.0,
                                        phasebinms=12.0,
                                        unphasedms=6.0)
    print('did {}'.format(outpath))
def test_bls_parallel():
    '''
    Tests periodbase.bls_parallel_pfind.

    '''
    lcd, msg = hatlc.read_and_filter_sqlitecurve(LCPATH)
    bls = periodbase.bls_parallel_pfind(lcd['rjd'],
                                        lcd['aep_000'],
                                        lcd['aie_000'],
                                        startp=1.0)

    assert isinstance(bls, dict)
    assert_allclose(bls['bestperiod'], 3.08560655)
Beispiel #3
0
def _periodicity_analysis(hatid,
                          times,
                          mags,
                          errs,
                          normlcd,
                          varperiod=None,
                          isresidual=False):
    '''
    Given times, magnitudes, and errors, run Phase Dispersion Minimization and
    Box Least Squares, then write the phase-folded LCs, periodograms, and
    header data to a checkplot pickle.
    Typically, in 03_EB_processing.py, mags will be (data+injected planet), or
    (data + injected planet - EB model).

    Args:
        hatid (str): HAT-XXX-XXXXXXX
        times (np.array): times of measurement (typically RJD)
        mags (np.array): measured magnitudes at observing times
        errs (np.array): measured error on mags
        normlcd: lightcurve dictionary from early reading / astrobase parsing
    Keyword Args:
        varperiod (float, default None): EB period, used to set upper and lower
        bounds of frequency search.
        isresidual (bool, default False): if `mags` is from residuals, use
        this. It will do a denser frequency search, at >~2x the EB period.
    Returns:
        nothing
    '''
    #TODO: fix args, add docs

    if not varperiod:
        #injection has happened
        smallest_p = 0.5
        cpwritepre = '../data/detachedEBs/injs/checkplot-inj-'
    elif isinstance(varperiod, float) and isresidual:
        smallest_p = varperiod * 2. + 0.1
        cpwritepre = '../data/detachedEBs/injres/checkplot-injresiduals-'
    else:
        raise ValueError('smallest_p never properly assigned')

    biggest_p = min((times[-1] - times[0]) / 2.01, 100.)

    print('\nStellingwerf...\n')
    spdmp = periodbase.stellingwerf_pdm(
        times,
        mags,
        errs,
        autofreq=True,
        startp=smallest_p,
        endp=biggest_p,
        normalize=False,
        stepsize=1.0e-5,
        phasebinsize=0.03,
        mindetperbin=9,
        nbestpeaks=5,
        periodepsilon=0.1,  # 0.1days
        sigclip=None,  # no sigma clipping
        nworkers=None)

    varinfo = {
        'objectisvar': True,
        'vartags': None,
        'varisperiodic': True,
        'varperiod': spdmp['bestperiod'],
        'varepoch': None
    }

    print('\nBLS...\n')
    blsp = periodbase.bls_parallel_pfind(times,
                                         mags,
                                         errs,
                                         startp=smallest_p,
                                         endp=biggest_p,
                                         stepsize=1.0e-5,
                                         mintransitduration=0.01,
                                         maxtransitduration=0.6,
                                         nphasebins=200,
                                         autofreq=False,
                                         nbestpeaks=5,
                                         periodepsilon=0.1,
                                         nworkers=None,
                                         sigclip=None)

    lspinfolist = [spdmp, blsp]
    cp = checkplot.checkplot_pickle(lspinfolist,
                                    times,
                                    mags,
                                    errs,
                                    nperiodstouse=3,
                                    objectinfo=normlcd['objectinfo'],
                                    varinfo=varinfo,
                                    findercmap='gray_r',
                                    normto='globalmedian',
                                    normmingap=4.,
                                    outfile=cpwritepre + hatid + '.pkl.gz',
                                    sigclip=[10., -3.],
                                    varepoch='min',
                                    phasewrap=True,
                                    phasesort=True,
                                    phasebin=0.002,
                                    plotxlim=[-0.6, 0.6],
                                    plotdpi=150,
                                    returndict=False,
                                    pickleprotocol=3,
                                    greenhighlight=False,
                                    xgridlines=[-0.5, 0., 0.5])

    #since we don't have easy checkplot_pickle to png written yet, use twolsp_checkplot_png
    #TODO: remove any png writing once happy with output
    if not varperiod:
        injpath = '../data/detachedEBs/plots/3_checkplot-inj-'
    elif isinstance(varperiod, float) and isresidual:
        injpath = '../data/detachedEBs/plots/5_checkplot-injresiduals-'
    else:
        raise ValueError('injpath never properly assigned')

    checkplot.twolsp_checkplot_png(spdmp,
                                   blsp,
                                   times,
                                   mags,
                                   errs,
                                   objectinfo=normlcd['objectinfo'],
                                   findercmap='gray_r',
                                   normto='globalmedian',
                                   normmingap=4.,
                                   outfile=injpath + hatid + '.png',
                                   sigclip=[10., -3.],
                                   varepoch='min',
                                   phasewrap=True,
                                   phasesort=True,
                                   phasebin=0.002,
                                   plotxlim=[-0.6, 0.6],
                                   plotdpi=150)
    plt.close('all')
Beispiel #4
0
def periodicity_analysis(out, DSP_lim=None, field_id=None, DEBiL_write=False):
    '''
    Given a specified field (e.g., G199), previous steps have created
    data/HATpipe/blsanalsums/cuts for that field and neighbors (imposing cuts
    on DSP_lim, Ntra_min, and NTV). They've also downloaded the appropriate
    LCs.
    Now rerun the periodicity analysis for these LCs (Box-Least-Squares and
    Stellingwerf Phase Dispersion Minimization), and make eb_checkplots for
    subsequent looking-at ("visual inspection").

    Args:
       DEBiL_write (bool): whether to write a "name and best BLS period" file
           (in basically all use cases, not necessary).
    '''
    assert type(field_id) == str
    print('\nBeginning periodicity analysis...\n\n')

    # File name format: HAT-199-0025234-V0-DR0-hatlc.sqlite.gz
    field_name = 'G' + field_id  # e.g., 'G081'
    LC_read_path = '../data/LCs/' + field_name + '/'  # where sqlitecurves already exist
    tail_str = '-V0-DR0-hatlc.sqlite.gz'
    # paths for LCs and EB checkplots
    LC_write_path = '../data/LCs_cut/' + field_name + '_' + str(DSP_lim)
    CP_write_path = '../data/CPs_cut/' + field_name + '_' + str(DSP_lim)

    for outpath in [
            LC_write_path, LC_write_path + '/periodcut',
            LC_write_path + '/onedaycut', LC_write_path + '/shortcoveragecut',
            CP_write_path, CP_write_path + '/periodcut',
            CP_write_path + '/onedaycut', CP_write_path + '/shortcoveragecut'
    ]:

        if not os.path.isdir(outpath):
            os.makedirs(outpath)

    for ix, hatid in enumerate(out.index):
        if np.all(out.ix[hatid]['has_sqlc']):
            LC_cut_path = LC_write_path + '/' + hatid + tail_str
            LC_periodcut_path = LC_write_path + '/periodcut/' + hatid + tail_str
            LC_onedaycut_path = LC_write_path + '/onedaycut/' + hatid + tail_str
            LC_shortcoveragecut_path = LC_write_path + '/shortcoveragecut/' + hatid + tail_str
            CP_cut_path = CP_write_path + '/' + hatid + '.png'
            CP_periodcut_path = CP_write_path + '/periodcut/' + hatid + '.png'
            CP_onedaycut_path = CP_write_path + '/onedaycut/' + hatid + '.png'
            CP_shortcoveragecut_path = CP_write_path + '/shortcoveragecut/' + hatid + '.png'

            if (not os.path.exists(CP_cut_path)) \
            and (not os.path.exists(CP_periodcut_path)) \
            and (not os.path.exists(CP_onedaycut_path)) \
            and (not os.path.exists(CP_shortcoveragecut_path)):
                # Get sqlitecurve data.
                obj_path = LC_read_path + hatid + tail_str
                lcd, msg = hatlc.read_and_filter_sqlitecurve(obj_path)
                # Make sure all observations are at the same zero-point.
                normlcd = hatlc.normalize_lcdict(lcd)
                # Select recommended EPD aperture with 'G' flag. (Alternate
                # approach: take the smallest aperture to minimize crowding).
                ap = next(iter(lcd['lcbestaperture']['ap']))
                times = normlcd['rjd'][normlcd['aiq_' + ap] == 'G']
                mags = normlcd['aep_' + ap][normlcd['aiq_' + ap] == 'G']
                errs = normlcd['aie_' + ap][normlcd['aiq_' + ap] == 'G']

                # Period analysis: Stellingwerf phase dispersion minimization
                # and rerun Box-Least-Squares. Range of interesting periods:
                # 0.5days-100days. BLS can only search for periods < half the
                # light curve observing baseline. (N.b. 100d signals are
                # basically always going to be stellar rotation)
                smallest_p = 0.5
                biggest_p = min((times[-1] - times[0]) / 2.01, 100.)

                print('\nStellingwerf...\n')
                spdmp = periodbase.stellingwerf_pdm(
                    times,
                    mags,
                    errs,
                    autofreq=True,
                    startp=smallest_p,
                    endp=biggest_p,
                    normalize=False,
                    stepsize=1.0e-4,
                    phasebinsize=0.05,
                    mindetperbin=9,
                    nbestpeaks=5,
                    periodepsilon=0.1,  # 0.1days
                    sigclip=None,  # no sigma clipping
                    nworkers=None)

                print('\nBLS...\n')
                blsp = periodbase.bls_parallel_pfind(
                    times,
                    mags,
                    errs,
                    startp=smallest_p,
                    endp=biggest_p,  # don't search full timebase
                    stepsize=1.0e-5,
                    mintransitduration=0.01,  # minimum transit length in phase
                    maxtransitduration=0.7,  # maximum transit length in phase
                    nphasebins=200,
                    autofreq=False,  # figure out f0, nf, and df automatically
                    nbestpeaks=5,
                    periodepsilon=0.1,  # 0.1
                    nworkers=None,
                    sigclip=None)

                # Make and save checkplot to be looked at.
                cp = plotbase.make_eb_checkplot(
                    spdmp,
                    blsp,
                    times,
                    mags,
                    errs,
                    objectinfo=normlcd['objectinfo'],
                    findercmap='gray_r',
                    normto='globalmedian',
                    normmingap=4.0,
                    outfile=CP_cut_path,
                    sigclip=None,
                    varepoch='min',
                    phasewrap=True,
                    phasesort=True,
                    phasebin=0.002,
                    plotxlim=[-0.6, 0.6])

                # Copy LCs with DSP>DSP_lim to /data/LCs_cut/G???_??/
                if not os.path.exists(LC_cut_path):
                    copyfile(obj_path, LC_cut_path)
                    print('Copying {} -> {}\n'.format(obj_path, LC_cut_path))

                #### CUTS ####
                maxperiod = 30.  # days
                bestperiods = spdmp['nbestperiods'] + blsp['nbestperiods']
                best3periods = spdmp['nbestperiods'][:3]+\
                        blsp['nbestperiods'][:3]
                bparr, b3parr = np.array(bestperiods), np.array(best3periods)

                minperiod = 0.5002  # days; else this harmonic of 1d happens
                proxto1d_s, proxto1d_m, proxto1d_b = 0.01, 0.015, 0.02  # days
                bestbls, bestspdm = blsp['bestperiod'], spdmp['bestperiod']

                mindayscoverage = 3.
                cadence = 4.  # minutes
                minnumpoints = mindayscoverage * 24 * 60 / cadence

                # (If 5 of the 6 best peaks are above max period (30 days)), OR
                # (If all of the SPDM peaks are above max period and the BLS
                # peaks are not, and all the BLS peaks less than the max period
                # are within 0.1days separate from e/other) OR
                # (The same, with BLS/SPDM switched), OR
                # (The difference between all SPDM is <0.1day and the
                # difference between all BLS is <0.1day)
                #
                # [n.b. latter broad-peak behavior happens b/c of stellar rotn]
                sb3parr = np.sort(b3parr)
                spdmn = np.array(spdmp['nbestperiods'][:3])
                blsn = np.array(blsp['nbestperiods'][:3])
                ps = 0.2  # peak_separation, days
                b3pint = b3parr[(b3parr < maxperiod) & (
                    b3parr > 2 * minperiod)]  # interesting periods

                if npall(sb3parr[1:] > maxperiod) \
                   or \
                   ((npall(spdmn>maxperiod) and not npall(blsn>maxperiod)) and
                   npall(abs(npdiff(blsn[blsn<maxperiod]))<ps)) \
                   or \
                   ((npall(blsn>maxperiod) and not npall(spdmn>maxperiod)) and
                   npall(abs(npdiff(spdmn[spdmn<maxperiod]))<ps)) \
                   or \
                   (npall(abs(npdiff(spdmn))<ps) and
                   npall(abs(npdiff(blsn))<ps)):

                    os.rename(LC_cut_path, LC_periodcut_path)
                    os.rename(CP_cut_path, CP_periodcut_path)

                # All 6 best peaks below max period (and above 1d) are within
                # 0.02days of a multiple of 1, OR
                # Both the BLS and SPDM max peak are within 0.015d of a
                # multiple of 1, OR
                # At least one of the best BLS&SPDM peaks are within 0.015d of one,
                # and of the remaining peaks > 1day, the rest are within 0.03days of
                # multiples of one.
                elif (npall(npisclose(npminimum(\
                    b3pint%1., abs((b3pint%1.)-1.)), 0., atol=proxto1d_b)))\
                    or \
                    ((npisclose(npminimum(\
                    bestbls%1., abs((bestbls%1.)-1.)), 0., atol=proxto1d_m))
                    and (npisclose(npminimum(\
                    bestspdm%1., abs((bestspdm%1.)-1.)), 0., atol=proxto1d_m)))\
                    or \
                    (\
                    (npisclose(abs(bestbls-1.), 0., atol=proxto1d_m) or
                    npisclose(abs(bestspdm-1.), 0., atol=proxto1d_m)) and
                    (npall(npisclose(npminimum(\
                    b3pint%1., abs((b3pint%1.)-1.)), 0., atol=proxto1d_m*2.)))\
                    ):

                    os.rename(LC_cut_path, LC_onedaycut_path)
                    os.rename(CP_cut_path, CP_onedaycut_path)

                # If there is not enough coverage. "Enough" means 3 days of
                # observations (at 4 minute cadence).
                elif len(mags) < minnumpoints:
                    os.rename(LC_cut_path, LC_shortcoveragecut_path)
                    os.rename(CP_cut_path, CP_shortcoveragecut_path)

        else:
            print('{:d}: {:s} or LC counterpart exists; continue.'.\
                    format(ix, CP_cut_path))
            continue

    print('\nDone with periodicity analysis for {:s}.\n\n'.format(field_name))

    if DEBiL_write:
        # Write DEBiL "input list" of HAT-IDs and periods.
        write_path = '../data/DEBiL_heads/' + field + '_DSP' + str(
            DSP_lim) + '.txt'
        if not os.path.exists(write_path):
            f_id = open(write_path, 'wb+')
            data = np.array([out.index, out['PERIOD']])
            np.savetxt(f_id, data.T, fmt=['%15s', '%.6f'])
            f_id.close()