def aov_theta(times, mags, errs, frequency,<EOL>binsize=<NUM_LIT>, minbin=<NUM_LIT:9>):

period = <NUM_LIT:1.0>/frequency<EOL>fold_time = times[<NUM_LIT:0>]<EOL>phased = phase_magseries(times,<EOL>mags,<EOL>period,<EOL>fold_time,<EOL>wrap=False,<EOL>sort=True)<EOL>phases = phased['<STR_LIT>']<EOL>pmags = phased['<STR_LIT>']<EOL>bins = nparange(<NUM_LIT:0.0>, <NUM_LIT:1.0>, binsize)<EOL>ndets = phases.size<EOL>binnedphaseinds = npdigitize(phases, bins)<EOL>bin_s1_tops = []<EOL>bin_s2_tops = []<EOL>binndets = []<EOL>goodbins = <NUM_LIT:0><EOL>all_xbar = npmedian(pmags)<EOL>for x in npunique(binnedphaseinds):<EOL><INDENT>thisbin_inds = binnedphaseinds == x<EOL>thisbin_mags = pmags[thisbin_inds]<EOL>if thisbin_mags.size > minbin:<EOL><INDENT>thisbin_ndet = thisbin_mags.size<EOL>thisbin_xbar = npmedian(thisbin_mags)<EOL>thisbin_s1_top = (<EOL>thisbin_ndet *<EOL>(thisbin_xbar - all_xbar) *<EOL>(thisbin_xbar - all_xbar)<EOL>)<EOL>thisbin_s2_top = npsum((thisbin_mags - all_xbar) *<EOL>(thisbin_mags - all_xbar))<EOL>bin_s1_tops.append(thisbin_s1_top)<EOL>bin_s2_tops.append(thisbin_s2_top)<EOL>binndets.append(thisbin_ndet)<EOL>goodbins = goodbins + <NUM_LIT:1><EOL><DEDENT><DEDENT>bin_s1_tops = nparray(bin_s1_tops)<EOL>bin_s2_tops = nparray(bin_s2_tops)<EOL>binndets = nparray(binndets)<EOL>s1 = npsum(bin_s1_tops)/(goodbins - <NUM_LIT:1.0>)<EOL>s2 = npsum(bin_s2_tops)/(ndets - goodbins)<EOL>theta_aov = s1/s2<EOL>return theta_aov<EOL>

Calculates the Schwarzenberg-Czerny AoV statistic at a test frequency.

    Parameters
    ----------

    times,mags,errs : np.array
        The input time-series and associated errors.

    frequency : float
        The test frequency to calculate the theta statistic at.

    binsize : float
        The phase bin size to use.

    minbin : int
        The minimum number of items in a phase bin to consider in the
        calculation of the statistic.

    Returns
    -------

    theta_aov : float
        The value of the AoV statistic at the specified `frequency`.


times, mags, errs, frequency, binsize, minbin = task<EOL>try:<EOL><INDENT>theta = aov_theta(times, mags, errs, frequency,<EOL>binsize=binsize, minbin=minbin)<EOL>return theta<EOL><DEDENT>except Exception as e:<EOL><INDENT>return npnan<EOL><DEDENT>

This is a parallel worker for the function below.

    Parameters
    ----------

    task : tuple
        This is of the form below::

            task[0] = times
            task[1] = mags
            task[2] = errs
            task[3] = frequency
            task[4] = binsize
            task[5] = minbin

    Returns
    -------

    theta_aov : float
        The theta value at the specified frequency. nan if the calculation
        fails.


<EOL>stimes, smags, serrs = sigclip_magseries(times,<EOL>mags,<EOL>errs,<EOL>magsarefluxes=magsarefluxes,<EOL>sigclip=sigclip)<EOL>if len(stimes) > <NUM_LIT:9> and len(smags) > <NUM_LIT:9> and len(serrs) > <NUM_LIT:9>:<EOL><INDENT>if startp:<EOL><INDENT>endf = <NUM_LIT:1.0>/startp<EOL><DEDENT>else:<EOL><INDENT>endf = <NUM_LIT:1.0>/<NUM_LIT:0.1><EOL><DEDENT>if endp:<EOL><INDENT>startf = <NUM_LIT:1.0>/endp<EOL><DEDENT>else:<EOL><INDENT>startf = <NUM_LIT:1.0>/(stimes.max() - stimes.min())<EOL><DEDENT>if not autofreq:<EOL><INDENT>frequencies = nparange(startf, endf, stepsize)<EOL>if verbose:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>' %<EOL>(frequencies.size, <NUM_LIT:1.0>/endf, <NUM_LIT:1.0>/startf)<EOL>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>frequencies = get_frequency_grid(stimes,<EOL>minfreq=startf,<EOL>maxfreq=endf)<EOL>if verbose:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(frequencies.size,<EOL><NUM_LIT:1.0>/frequencies.max(),<EOL><NUM_LIT:1.0>/frequencies.min())<EOL>)<EOL><DEDENT><DEDENT>if (not nworkers) or (nworkers > NCPUS):<EOL><INDENT>nworkers = NCPUS<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % nworkers)<EOL><DEDENT><DEDENT>pool = Pool(nworkers)<EOL>if normalize:<EOL><INDENT>nmags = (smags - npmedian(smags))/npstd(smags)<EOL><DEDENT>else:<EOL><INDENT>nmags = smags<EOL><DEDENT>tasks = [(stimes, nmags, serrs, x, phasebinsize, mindetperbin)<EOL>for x in frequencies]<EOL>lsp = pool.map(_aov_worker, tasks)<EOL>pool.close()<EOL>pool.join()<EOL>del pool<EOL>lsp = nparray(lsp)<EOL>periods = <NUM_LIT:1.0>/frequencies<EOL>finitepeakind = npisfinite(lsp)<EOL>finlsp = lsp[finitepeakind]<EOL>finperiods = periods[finitepeakind]<EOL>try:<EOL><INDENT>bestperiodind = npargmax(finlsp)<EOL><DEDENT>except ValueError:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':normalize,<EOL>'<STR_LIT>':phasebinsize,<EOL>'<STR_LIT>':mindetperbin,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip}}<EOL><DEDENT>sortedlspind = npargsort(finlsp)[::-<NUM_LIT:1>]<EOL>sortedlspperiods = finperiods[sortedlspind]<EOL>sortedlspvals = finlsp[sortedlspind]<EOL>nbestperiods, nbestlspvals, peakcount = (<EOL>[finperiods[bestperiodind]],<EOL>[finlsp[bestperiodind]],<EOL><NUM_LIT:1><EOL>)<EOL>prevperiod = sortedlspperiods[<NUM_LIT:0>]<EOL>for period, lspval in zip(sortedlspperiods, sortedlspvals):<EOL><INDENT>if peakcount == nbestpeaks:<EOL><INDENT>break<EOL><DEDENT>perioddiff = abs(period - prevperiod)<EOL>bestperiodsdiff = [abs(period - x) for x in nbestperiods]<EOL>if (perioddiff > (periodepsilon*prevperiod) and<EOL>all(x > (periodepsilon*period) for x in bestperiodsdiff)):<EOL><INDENT>nbestperiods.append(period)<EOL>nbestlspvals.append(lspval)<EOL>peakcount = peakcount + <NUM_LIT:1><EOL><DEDENT>prevperiod = period<EOL><DEDENT>return {'<STR_LIT>':finperiods[bestperiodind],<EOL>'<STR_LIT>':finlsp[bestperiodind],<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':nbestlspvals,<EOL>'<STR_LIT>':nbestperiods,<EOL>'<STR_LIT>':lsp,<EOL>'<STR_LIT>':periods,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':normalize,<EOL>'<STR_LIT>':phasebinsize,<EOL>'<STR_LIT>':mindetperbin,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip}}<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':normalize,<EOL>'<STR_LIT>':phasebinsize,<EOL>'<STR_LIT>':mindetperbin,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip}}<EOL><DEDENT>

This runs a parallelized Analysis-of-Variance (AoV) period search.

    NOTE: `normalize = True` here as recommended by Schwarzenberg-Czerny 1996,
    i.e. mags will be normalized to zero and rescaled so their variance = 1.0.

    Parameters
    ----------

    times,mags,errs : np.array
        The mag/flux time-series with associated measurement errors to run the
        period-finding on.

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

    startp,endp : float or None
        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.

    autofreq : bool
        If this is True, the value of `stepsize` will be ignored and the
        :py:func:`astrobase.periodbase.get_frequency_grid` function will be used
        to generate a frequency grid based on `startp`, and `endp`. If these are
        None as well, `startp` will be set to 0.1 and `endp` will be set to
        `times.max() - times.min()`.

    normalize : bool
        This sets if the input time-series is normalized to 0.0 and rescaled
        such that its variance = 1.0. This is the recommended procedure by
        Schwarzenberg-Czerny 1996.

    phasebinsize : float
        The bin size in phase to use when calculating the AoV theta statistic at
        a test frequency.

    mindetperbin : int
        The minimum number of elements in a phase bin to consider it valid when
        calculating the AoV theta statistic at a test frequency.

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

    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.

    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.

    nworkers : int
        The number of parallel workers to use when calculating the periodogram.

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

    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,
             'periods': the full array of periods considered,
             'method':'aov' -> the name of the period-finder method,
             'kwargs':{ dict of all of the input kwargs for record-keeping}}


from scipy.stats import f<EOL>frequencies = <NUM_LIT:1.0>/lspinfo['<STR_LIT>']<EOL>M = independent_freq_count(frequencies,<EOL>times,<EOL>conservative=conservative_nfreq_eff)<EOL>if peakvals is None:<EOL><INDENT>peakvals = lspinfo['<STR_LIT>']<EOL><DEDENT>nphasebins = nparange(<NUM_LIT:0.0>, <NUM_LIT:1.0>, lspinfo['<STR_LIT>']['<STR_LIT>']).size<EOL>ndet = times.size<EOL>false_alarm_probs = []<EOL>for peakval in peakvals:<EOL><INDENT>prob_xval = peakval<EOL>prob_exceeds_val = f.cdf(prob_xval,<EOL>nphasebins - <NUM_LIT:1.0>,<EOL>ndet - nphasebins)<EOL>false_alarm_probs.append(<NUM_LIT:1.0> - (<NUM_LIT:1.0> - prob_exceeds_val)**M)<EOL><DEDENT>if inplace:<EOL><INDENT>lspinfo['<STR_LIT>'] = false_alarm_probs<EOL><DEDENT>return false_alarm_probs<EOL>

This returns the analytic false alarm probabilities for periodogram
    peak values.

    FIXME: this doesn't actually work. Fix later.

    The calculation follows that on page 3 of Zechmeister & Kurster (2009)::

        FAP = 1 − [1 − Prob(z > z0)]**M

    where::

        M is the number of independent frequencies
        Prob(z > z0) is the probability of peak with value > z0
        z0 is the peak value we're evaluating

    For AoV and AoV-harmonic, the Prob(z > z0) is described by the F
    distribution, according to:

    - Schwarzenberg-Czerny (1997;
      https://ui.adsabs.harvard.edu/#abs/1997ApJ...489..941S)

    This is given by::

        F( (B-1), (N-B); theta_aov )

    Where::

        N = number of observations
        B = number of phase bins

    This translates to a scipy.stats call to the F distribution CDF::

        x = theta_aov_best
        prob_exceeds_val = scipy.stats.f.cdf(x, (B-1.0), (N-B))

    Which we can then plug into the false alarm prob eqn above with the
    calculation of M.

    Parameters
    ----------

    lspinfo : dict
        The dict returned by the
        :py:func:`~astrobase.periodbase.spdm.aov_periodfind` function.

    times : np.array
        The times for which the periodogram result in ``lspinfo`` was
        calculated.

    conservative_nfreq_eff : bool
        If True, will follow the prescription given in Schwarzenberg-Czerny
        (2003):

        http://adsabs.harvard.edu/abs/2003ASPC..292..383S

        and estimate the effective number of independent frequences M_eff as::

            min(N_obs, N_freq, DELTA_f/delta_f)

    peakvals : sequence or None
        The peak values for which to evaluate the false-alarm probability. If
        None, will calculate this for each of the peak values in the
        ``nbestpeaks`` key of the ``lspinfo`` dict.

    inplace : bool
        If True, puts the results of the FAP calculation into the ``lspinfo``
        dict as a list available as ``lspinfo['falsealarmprob']``.

    Returns
    -------

    list
        The calculated false alarm probabilities for each of the peak values in
        ``peakvals``.


def generalized_lsp_value(times, mags, errs, omega):

one_over_errs2 = <NUM_LIT:1.0>/(errs*errs)<EOL>W = npsum(one_over_errs2)<EOL>wi = one_over_errs2/W<EOL>sin_omegat = npsin(omega*times)<EOL>cos_omegat = npcos(omega*times)<EOL>sin2_omegat = sin_omegat*sin_omegat<EOL>cos2_omegat = cos_omegat*cos_omegat<EOL>sincos_omegat = sin_omegat*cos_omegat<EOL>Y = npsum( wi*mags )<EOL>C = npsum( wi*cos_omegat )<EOL>S = npsum( wi*sin_omegat )<EOL>CpS = npsum( wi*sincos_omegat )<EOL>CpC = npsum( wi*cos2_omegat )<EOL>CS = CpS - C*S<EOL>CC = CpC - C*C<EOL>SS = <NUM_LIT:1> - CpC - S*S  <EOL>tan_omega_tau_top = <NUM_LIT>*CS<EOL>tan_omega_tau_bottom = CC - SS<EOL>tan_omega_tau = tan_omega_tau_top/tan_omega_tau_bottom<EOL>tau = nparctan(tan_omega_tau)/(<NUM_LIT>*omega)<EOL>YpY = npsum( wi*mags*mags)<EOL>YpC = npsum( wi*mags*cos_omegat )<EOL>YpS = npsum( wi*mags*sin_omegat )<EOL>YY = YpY - Y*Y<EOL>YC = YpC - Y*C<EOL>YS = YpS - Y*S<EOL>periodogramvalue = (YC*YC/CC + YS*YS/SS)/YY<EOL>return periodogramvalue<EOL>

Generalized LSP value for a single omega.

    The relations used are::

        P(w) = (1/YY) * (YC*YC/CC + YS*YS/SS)

        where: YC, YS, CC, and SS are all calculated at T

        and where: tan 2omegaT = 2*CS/(CC - SS)

        and where:

        Y = sum( w_i*y_i )
        C = sum( w_i*cos(wT_i) )
        S = sum( w_i*sin(wT_i) )

        YY = sum( w_i*y_i*y_i ) - Y*Y
        YC = sum( w_i*y_i*cos(wT_i) ) - Y*C
        YS = sum( w_i*y_i*sin(wT_i) ) - Y*S

        CpC = sum( w_i*cos(w_T_i)*cos(w_T_i) )
        CC = CpC - C*C
        SS = (1 - CpC) - S*S
        CS = sum( w_i*cos(w_T_i)*sin(w_T_i) ) - C*S

    Parameters
    ----------

    times,mags,errs : np.array
        The time-series to calculate the periodogram value for.

    omega : float
        The frequency to calculate the periodogram value at.

    Returns
    -------

    periodogramvalue : float
        The normalized periodogram at the specified test frequency `omega`.


def generalized_lsp_value_withtau(times, mags, errs, omega):

one_over_errs2 = <NUM_LIT:1.0>/(errs*errs)<EOL>W = npsum(one_over_errs2)<EOL>wi = one_over_errs2/W<EOL>sin_omegat = npsin(omega*times)<EOL>cos_omegat = npcos(omega*times)<EOL>sin2_omegat = sin_omegat*sin_omegat<EOL>cos2_omegat = cos_omegat*cos_omegat<EOL>sincos_omegat = sin_omegat*cos_omegat<EOL>Y = npsum( wi*mags )<EOL>C = npsum( wi*cos_omegat )<EOL>S = npsum( wi*sin_omegat )<EOL>CpS = npsum( wi*sincos_omegat )<EOL>CpC = npsum( wi*cos2_omegat )<EOL>CS = CpS - C*S<EOL>CC = CpC - C*C<EOL>SS = <NUM_LIT:1> - CpC - S*S  <EOL>tan_omega_tau_top = <NUM_LIT>*CS<EOL>tan_omega_tau_bottom = CC - SS<EOL>tan_omega_tau = tan_omega_tau_top/tan_omega_tau_bottom<EOL>tau = nparctan(tan_omega_tau)/(<NUM_LIT>*omega)<EOL>sin_omega_tau = npsin(omega*(times - tau))<EOL>cos_omega_tau = npcos(omega*(times - tau))<EOL>sin2_omega_tau = sin_omega_tau*sin_omega_tau<EOL>cos2_omega_tau = cos_omega_tau*cos_omega_tau<EOL>sincos_omega_tau = sin_omega_tau*cos_omega_tau<EOL>C_tau = npsum(wi*cos_omega_tau)<EOL>S_tau = npsum(wi*sin_omega_tau)<EOL>CpS_tau = npsum( wi*sincos_omega_tau )<EOL>CpC_tau = npsum( wi*cos2_omega_tau )<EOL>CS_tau = CpS_tau - C_tau*S_tau<EOL>CC_tau = CpC_tau - C_tau*C_tau<EOL>SS_tau = <NUM_LIT:1> - CpC_tau - S_tau*S_tau  <EOL>YpY = npsum( wi*mags*mags)<EOL>YpC_tau = npsum( wi*mags*cos_omega_tau )<EOL>YpS_tau = npsum( wi*mags*sin_omega_tau )<EOL>YY = YpY - Y*Y<EOL>YC_tau = YpC_tau - Y*C_tau<EOL>YS_tau = YpS_tau - Y*S_tau<EOL>periodogramvalue = (YC_tau*YC_tau/CC_tau + YS_tau*YS_tau/SS_tau)/YY<EOL>return periodogramvalue<EOL>

Generalized LSP value for a single omega.

    This uses tau to provide an arbitrary time-reference point.

    The relations used are::

        P(w) = (1/YY) * (YC*YC/CC + YS*YS/SS)

        where: YC, YS, CC, and SS are all calculated at T

        and where: tan 2omegaT = 2*CS/(CC - SS)

        and where:

        Y = sum( w_i*y_i )
        C = sum( w_i*cos(wT_i) )
        S = sum( w_i*sin(wT_i) )

        YY = sum( w_i*y_i*y_i ) - Y*Y
        YC = sum( w_i*y_i*cos(wT_i) ) - Y*C
        YS = sum( w_i*y_i*sin(wT_i) ) - Y*S

        CpC = sum( w_i*cos(w_T_i)*cos(w_T_i) )
        CC = CpC - C*C
        SS = (1 - CpC) - S*S
        CS = sum( w_i*cos(w_T_i)*sin(w_T_i) ) - C*S

    Parameters
    ----------

    times,mags,errs : np.array
        The time-series to calculate the periodogram value for.

    omega : float
        The frequency to calculate the periodogram value at.

    Returns
    -------

    periodogramvalue : float
        The normalized periodogram at the specified test frequency `omega`.


def generalized_lsp_value_notau(times, mags, errs, omega):

one_over_errs2 = <NUM_LIT:1.0>/(errs*errs)<EOL>W = npsum(one_over_errs2)<EOL>wi = one_over_errs2/W<EOL>sin_omegat = npsin(omega*times)<EOL>cos_omegat = npcos(omega*times)<EOL>sin2_omegat = sin_omegat*sin_omegat<EOL>cos2_omegat = cos_omegat*cos_omegat<EOL>sincos_omegat = sin_omegat*cos_omegat<EOL>Y = npsum( wi*mags )<EOL>C = npsum( wi*cos_omegat )<EOL>S = npsum( wi*sin_omegat )<EOL>YpY = npsum( wi*mags*mags)<EOL>YpC = npsum( wi*mags*cos_omegat )<EOL>YpS = npsum( wi*mags*sin_omegat )<EOL>CpC = npsum( wi*cos2_omegat )<EOL>CpS = npsum( wi*sincos_omegat )<EOL>YY = YpY - Y*Y<EOL>YC = YpC - Y*C<EOL>YS = YpS - Y*S<EOL>CC = CpC - C*C<EOL>SS = <NUM_LIT:1> - CpC - S*S  <EOL>CS = CpS - C*S<EOL>Domega = CC*SS - CS*CS<EOL>lspval = (SS*YC*YC + CC*YS*YS - <NUM_LIT>*CS*YC*YS)/(YY*Domega)<EOL>return lspval<EOL>

This is the simplified version not using tau.

The relations used are::

    W = sum (1.0/(errs*errs) )
    w_i = (1/W)*(1/(errs*errs))

    Y = sum( w_i*y_i )
    C = sum( w_i*cos(wt_i) )
    S = sum( w_i*sin(wt_i) )

    YY = sum( w_i*y_i*y_i ) - Y*Y
    YC = sum( w_i*y_i*cos(wt_i) ) - Y*C
    YS = sum( w_i*y_i*sin(wt_i) ) - Y*S

    CpC = sum( w_i*cos(w_t_i)*cos(w_t_i) )
    CC = CpC - C*C
    SS = (1 - CpC) - S*S
    CS = sum( w_i*cos(w_t_i)*sin(w_t_i) ) - C*S

    D(omega) = CC*SS - CS*CS
    P(omega) = (SS*YC*YC + CC*YS*YS - 2.0*CS*YC*YS)/(YY*D)

Parameters
----------

times,mags,errs : np.array
    The time-series to calculate the periodogram value for.

omega : float
    The frequency to calculate the periodogram value at.

Returns
-------

periodogramvalue : float
    The normalized periodogram at the specified test frequency `omega`.


def specwindow_lsp_value(times, mags, errs, omega):

norm_times = times - times.min()<EOL>tau = (<EOL>(<NUM_LIT:1.0>/(<NUM_LIT>*omega)) *<EOL>nparctan( npsum(npsin(<NUM_LIT>*omega*norm_times)) /<EOL>npsum(npcos(<NUM_LIT>*omega*norm_times)) )<EOL>)<EOL>lspval_top_cos = (npsum(<NUM_LIT:1.0> * npcos(omega*(norm_times-tau))) *<EOL>npsum(<NUM_LIT:1.0> * npcos(omega*(norm_times-tau))))<EOL>lspval_bot_cos = npsum( (npcos(omega*(norm_times-tau))) *<EOL>(npcos(omega*(norm_times-tau))) )<EOL>lspval_top_sin = (npsum(<NUM_LIT:1.0> * npsin(omega*(norm_times-tau))) *<EOL>npsum(<NUM_LIT:1.0> * npsin(omega*(norm_times-tau))))<EOL>lspval_bot_sin = npsum( (npsin(omega*(norm_times-tau))) *<EOL>(npsin(omega*(norm_times-tau))) )<EOL>lspval = <NUM_LIT:0.5> * ( (lspval_top_cos/lspval_bot_cos) +<EOL>(lspval_top_sin/lspval_bot_sin) )<EOL>return lspval<EOL>

This calculates the peak associated with the spectral window function
    for times and at the specified omega.

    NOTE: this is classical Lomb-Scargle, not the Generalized
    Lomb-Scargle. `mags` and `errs` are silently ignored since we're calculating
    the periodogram of the observing window function. These are kept to present
    a consistent external API so the `pgen_lsp` function below can call this
    transparently.

    Parameters
    ----------

    times,mags,errs : np.array
        The time-series to calculate the periodogram value for.

    omega : float
        The frequency to calculate the periodogram value at.

    Returns
    -------

    periodogramvalue : float
        The normalized periodogram at the specified test frequency `omega`.


try:<EOL><INDENT>return generalized_lsp_value(*task)<EOL><DEDENT>except Exception as e:<EOL><INDENT>return npnan<EOL><DEDENT>

This is a worker to wrap the generalized Lomb-Scargle single-frequency
    function.


try:<EOL><INDENT>return generalized_lsp_value_withtau(*task)<EOL><DEDENT>except Exception as e:<EOL><INDENT>return npnan<EOL><DEDENT>


try:<EOL><INDENT>return specwindow_lsp_value(*task)<EOL><DEDENT>except Exception as e:<EOL><INDENT>return npnan<EOL><DEDENT>


try:<EOL><INDENT>return generalized_lsp_value_notau(*task)<EOL><DEDENT>except Exception as e:<EOL><INDENT>return npnan<EOL><DEDENT>

This is a worker to wrap the generalized Lomb-Scargle single-freq func.

    This version doesn't use tau.


<EOL>stimes, smags, serrs = sigclip_magseries(times,<EOL>mags,<EOL>errs,<EOL>magsarefluxes=magsarefluxes,<EOL>sigclip=sigclip)<EOL>nzind = npnonzero(serrs)<EOL>stimes, smags, serrs = stimes[nzind], smags[nzind], serrs[nzind]<EOL>if len(stimes) > <NUM_LIT:9> and len(smags) > <NUM_LIT:9> and len(serrs) > <NUM_LIT:9>:<EOL><INDENT>if startp:<EOL><INDENT>endf = <NUM_LIT:1.0>/startp<EOL><DEDENT>else:<EOL><INDENT>endf = <NUM_LIT:1.0>/<NUM_LIT:0.1><EOL><DEDENT>if endp:<EOL><INDENT>startf = <NUM_LIT:1.0>/endp<EOL><DEDENT>else:<EOL><INDENT>startf = <NUM_LIT:1.0>/(stimes.max() - stimes.min())<EOL><DEDENT>if not autofreq:<EOL><INDENT>omegas = <NUM_LIT:2>*pi_value*nparange(startf, endf, stepsize)<EOL>if verbose:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>' %<EOL>(omegas.size, <NUM_LIT:1.0>/endf, <NUM_LIT:1.0>/startf)<EOL>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>freqs = get_frequency_grid(stimes,<EOL>minfreq=startf,<EOL>maxfreq=endf)<EOL>omegas = <NUM_LIT:2>*pi_value*freqs<EOL>if verbose:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(omegas.size, <NUM_LIT:1.0>/freqs.max(), <NUM_LIT:1.0>/freqs.min())<EOL>)<EOL><DEDENT><DEDENT>if (not nworkers) or (nworkers > NCPUS):<EOL><INDENT>nworkers = NCPUS<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % nworkers)<EOL><DEDENT><DEDENT>pool = Pool(nworkers)<EOL>tasks = [(stimes, smags, serrs, x) for x in omegas]<EOL>if workchunksize:<EOL><INDENT>lsp = pool.map(glspfunc, tasks, chunksize=workchunksize)<EOL><DEDENT>else:<EOL><INDENT>lsp = pool.map(glspfunc, tasks)<EOL><DEDENT>pool.close()<EOL>pool.join()<EOL>del pool<EOL>lsp = nparray(lsp)<EOL>periods = <NUM_LIT>*pi_value/omegas<EOL>finitepeakind = npisfinite(lsp)<EOL>finlsp = lsp[finitepeakind]<EOL>finperiods = periods[finitepeakind]<EOL>try:<EOL><INDENT>bestperiodind = npargmax(finlsp)<EOL><DEDENT>except ValueError:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':omegas,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip}}<EOL><DEDENT>sortedlspind = npargsort(finlsp)[::-<NUM_LIT:1>]<EOL>sortedlspperiods = finperiods[sortedlspind]<EOL>sortedlspvals = finlsp[sortedlspind]<EOL>nbestperiods, nbestlspvals, peakcount = (<EOL>[finperiods[bestperiodind]],<EOL>[finlsp[bestperiodind]],<EOL><NUM_LIT:1><EOL>)<EOL>prevperiod = sortedlspperiods[<NUM_LIT:0>]<EOL>for period, lspval in zip(sortedlspperiods, sortedlspvals):<EOL><INDENT>if peakcount == nbestpeaks:<EOL><INDENT>break<EOL><DEDENT>perioddiff = abs(period - prevperiod)<EOL>bestperiodsdiff = [abs(period - x) for x in nbestperiods]<EOL>if (perioddiff > (periodepsilon*prevperiod) and<EOL>all(x > (periodepsilon*period) for x in bestperiodsdiff)):<EOL><INDENT>nbestperiods.append(period)<EOL>nbestlspvals.append(lspval)<EOL>peakcount = peakcount + <NUM_LIT:1><EOL><DEDENT>prevperiod = period<EOL><DEDENT>return {'<STR_LIT>':finperiods[bestperiodind],<EOL>'<STR_LIT>':finlsp[bestperiodind],<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':nbestlspvals,<EOL>'<STR_LIT>':nbestperiods,<EOL>'<STR_LIT>':lsp,<EOL>'<STR_LIT>':omegas,<EOL>'<STR_LIT>':periods,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip}}<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip}}<EOL><DEDENT>

This calculates the generalized Lomb-Scargle periodogram.

    Uses the algorithm from Zechmeister and Kurster (2009).

    Parameters
    ----------

    times,mags,errs : np.array
        The mag/flux time-series with associated measurement errors to run the
        period-finding on.

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

    startp,endp : float or None
        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.

    autofreq : bool
        If this is True, the value of `stepsize` will be ignored and the
        :py:func:`astrobase.periodbase.get_frequency_grid` function will be used
        to generate a frequency grid based on `startp`, and `endp`. If these are
        None as well, `startp` will be set to 0.1 and `endp` will be set to
        `times.max() - times.min()`.

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

    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.

    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.

    nworkers : int
        The number of parallel workers to use when calculating the periodogram.

    workchunksize : None or int
        If this is an int, will use chunks of the given size to break up the
        work for the parallel workers. If None, the chunk size is set to 1.

    glspfunc : Python function
        The worker function to use to calculate the periodogram. This can be
        used to make this function calculate the time-series sampling window
        function instead of the time-series measurements' GLS periodogram by
        passing in `_glsp_worker_specwindow` instead of the default
        `_glsp_worker_withtau` function.

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

    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,
             'periods': the full array of periods considered,
             'method':'gls' -> the name of the period-finder method,
             'kwargs':{ dict of all of the input kwargs for record-keeping}}


<EOL>lspres = pgen_lsp(<EOL>times,<EOL>mags,<EOL>errs,<EOL>magsarefluxes=magsarefluxes,<EOL>startp=startp,<EOL>endp=endp,<EOL>autofreq=autofreq,<EOL>nbestpeaks=nbestpeaks,<EOL>periodepsilon=periodepsilon,<EOL>stepsize=stepsize,<EOL>nworkers=nworkers,<EOL>sigclip=sigclip,<EOL>glspfunc=glspfunc,<EOL>verbose=verbose<EOL>)<EOL>lspres['<STR_LIT>'] = '<STR_LIT>'<EOL>if lspres['<STR_LIT>'] is not None:<EOL><INDENT>lspmax = npnanmax(lspres['<STR_LIT>'])<EOL>if npisfinite(lspmax):<EOL><INDENT>lspres['<STR_LIT>'] = lspres['<STR_LIT>']/lspmax<EOL>lspres['<STR_LIT>'] = [<EOL>x/lspmax for x in lspres['<STR_LIT>']<EOL>]<EOL>lspres['<STR_LIT>'] = lspres['<STR_LIT>']/lspmax<EOL><DEDENT><DEDENT>return lspres<EOL>

This calculates the spectral window function.

    Wraps the `pgen_lsp` function above to use the specific worker for
    calculating the window-function.

    Parameters
    ----------

    times,mags,errs : np.array
        The mag/flux time-series with associated measurement errors to run the
        period-finding on.

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

    startp,endp : float or None
        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.

    autofreq : bool
        If this is True, the value of `stepsize` will be ignored and the
        :py:func:`astrobase.periodbase.get_frequency_grid` function will be used
        to generate a frequency grid based on `startp`, and `endp`. If these are
        None as well, `startp` will be set to 0.1 and `endp` will be set to
        `times.max() - times.min()`.

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

    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.

    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.

    nworkers : int
        The number of parallel workers to use when calculating the periodogram.

    glspfunc : Python function
        The worker function to use to calculate the periodogram. This is used to
        used to make the `pgen_lsp` function calculate the time-series sampling
        window function instead of the time-series measurements' GLS periodogram
        by passing in `_glsp_worker_specwindow` instead of the default
        `_glsp_worker` function.

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

    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,
             'periods': the full array of periods considered,
             'method':'win' -> the name of the period-finder method,
             'kwargs':{ dict of all of the input kwargs for record-keeping}}


return (<NUM_LIT:1.0> - peakval)**((times.size - <NUM_LIT>)/<NUM_LIT>)<EOL>

This calculates the probability that periodogram values exceed the given
    peak value.

    This is from page 3 of Zechmeister and Kurster (2009)::

        Prob(p > p_best) = (1 − p_best)**((N−3)/2)

    where::

        p_best is the peak value in consideration
        N is the number of times

    Note that this is for the default normalization of the periodogram,
    e.g. P_normalized = P(omega), such that P represents the sample variance
    (see Table 1).

    Parameters
    ----------

    lspvals : np.array
        The periodogram power value array.

    peakval : float
        A single peak value to calculate the probability for.

    Returns
    -------

    prob: float
        The probability value.


frequencies = <NUM_LIT:1.0>/lspinfo['<STR_LIT>']<EOL>M = independent_freq_count(frequencies,<EOL>times,<EOL>conservative=conservative_nfreq_eff)<EOL>if peakvals is None:<EOL><INDENT>peakvals = lspinfo['<STR_LIT>']<EOL><DEDENT>prob_exceed_vals = [<EOL>probability_peak_exceeds_value(times, p) for p in peakvals<EOL>]<EOL>false_alarm_probs = [<EOL><NUM_LIT:1.0> - (<NUM_LIT:1.0> - prob_exc)**M for prob_exc in prob_exceed_vals<EOL>]<EOL>if inplace:<EOL><INDENT>lspinfo['<STR_LIT>'] = false_alarm_probs<EOL><DEDENT>return false_alarm_probs<EOL>

This returns the analytic false alarm probabilities for periodogram
    peak values.

    The calculation follows that on page 3 of Zechmeister & Kurster (2009)::

        FAP = 1 − [1 − Prob(z > z0)]**M

    where::

        M is the number of independent frequencies
        Prob(z > z0) is the probability of peak with value > z0
        z0 is the peak value we're evaluating

    Parameters
    ----------

    lspinfo : dict
        The dict returned by the :py:func:`~astrobase.periodbase.zgls.pgen_lsp`
        function.

    times : np.array
        The times for which the periodogram result in ``lspinfo`` was
        calculated.

    conservative_nfreq_eff : bool
        If True, will follow the prescription given in Schwarzenberg-Czerny
        (2003):

        http://adsabs.harvard.edu/abs/2003ASPC..292..383S

        and estimate the effective number of independent frequences M_eff as::

            min(N_obs, N_freq, DELTA_f/delta_f)

    peakvals : sequence or None
        The peak values for which to evaluate the false-alarm probability. If
        None, will calculate this for each of the peak values in the
        ``nbestpeaks`` key of the ``lspinfo`` dict.

    inplace : bool
        If True, puts the results of the FAP calculation into the ``lspinfo``
        dict as a list available as ``lspinfo['falsealarmprob']``.

    Returns
    -------

    list
        The calculated false alarm probabilities for each of the peak values in
        ``peakvals``.


workarr_u = npones(times.size)<EOL>workarr_v = npones(times.size)<EOL>blsresult = eebls(times, mags,<EOL>workarr_u, workarr_v,<EOL>nfreq, freqmin, stepsize,<EOL>nbins, minduration, maxduration)<EOL>return {'<STR_LIT>':blsresult[<NUM_LIT:0>],<EOL>'<STR_LIT>':blsresult[<NUM_LIT:1>],<EOL>'<STR_LIT>':blsresult[<NUM_LIT:2>],<EOL>'<STR_LIT>':blsresult[<NUM_LIT:3>],<EOL>'<STR_LIT>':blsresult[<NUM_LIT:4>],<EOL>'<STR_LIT>':blsresult[<NUM_LIT:5>],<EOL>'<STR_LIT>':blsresult[<NUM_LIT:6>]}<EOL>

This runs the pyeebls.eebls function using the given inputs.

    Parameters
    ----------

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

    nfreq : int
        The number of frequencies to use when searching for transits.

    freqmin : float
        The minimum frequency of the period-search -> max period that will be
        used for the search.

    stepsize : float
        The step-size in frequency to use to generate a frequency-grid.

    nbins : int
        The number of phase bins to use.

    minduration : float
        The minimum fractional transit duration that will be considered.

    maxduration : float
        The maximum fractional transit duration that will be considered.

    Returns
    -------

    dict
        Returns a dict of the form::

            {
                'power':           the periodogram power array,
                'bestperiod':      the best period found,
                'bestpower':       the highest peak of the periodogram power,
                'transdepth':      transit depth found by eebls.f,
                'transduration':   transit duration found by eebls.f,
                'transingressbin': transit ingress bin found by eebls.f,
                'transegressbin':  transit egress bin found by eebls.f,
            }


try:<EOL><INDENT>return _bls_runner(*task)<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>' % repr(task[<NUM_LIT:2>:]))<EOL>return {<EOL>'<STR_LIT>':nparray([npnan for x in range(task[<NUM_LIT:2>])]),<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan<EOL>}<EOL><DEDENT>

This wraps the BLS function for the parallel driver below.

Parameters
----------

tasks : tuple
    This is of the form::

        task[0] = times
        task[1] = mags
        task[2] = nfreq
        task[3] = freqmin
        task[4] = stepsize
        task[5] = nbins
        task[6] = minduration
        task[7] = maxduration

Returns
-------

dict
    Returns a dict of the form::

        {
            'power':           the periodogram power array,
            'bestperiod':      the best period found,
            'bestpower':       the highest peak of the periodogram power,
            'transdepth':      transit depth found by eebls.f,
            'transduration':   transit duration found by eebls.f,
            'transingressbin': transit ingress bin found by eebls.f,
            'transegressbin':  transit egress bin found by eebls.f,
        }


def bls_serial_pfind(<EOL>times, mags, errs,<EOL>magsarefluxes=False,<EOL>startp=<NUM_LIT:0.1>,  <EOL>endp=<NUM_LIT>,  <EOL>stepsize=<NUM_LIT>,<EOL>mintransitduration=<NUM_LIT>,  <EOL>maxtransitduration=<NUM_LIT>,   <EOL>nphasebins=<NUM_LIT:200>,<EOL>autofreq=True,  <EOL>periodepsilon=<NUM_LIT:0.1>,<EOL>nbestpeaks=<NUM_LIT:5>,<EOL>sigclip=<NUM_LIT>,<EOL>verbose=True,<EOL>get_stats=True,<EOL>):

<EOL>stimes, smags, serrs = sigclip_magseries(times,<EOL>mags,<EOL>errs,<EOL>magsarefluxes=magsarefluxes,<EOL>sigclip=sigclip)<EOL>if len(stimes) > <NUM_LIT:9> and len(smags) > <NUM_LIT:9> and len(serrs) > <NUM_LIT:9>:<EOL><INDENT>if autofreq:<EOL><INDENT>nphasebins = int(npceil(<NUM_LIT>/mintransitduration))<EOL>if nphasebins > <NUM_LIT>:<EOL><INDENT>nphasebins = <NUM_LIT><EOL><DEDENT>stepsize = <NUM_LIT>*mintransitduration/(stimes.max()-stimes.min())<EOL>minfreq = <NUM_LIT:1.0>/endp<EOL>maxfreq = <NUM_LIT:1.0>/startp<EOL>nfreq = int(npceil((maxfreq - minfreq)/stepsize))<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' % (startp, endp, nfreq,<EOL>minfreq, maxfreq))<EOL>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(stepsize, nphasebins,<EOL>mintransitduration, maxtransitduration))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>minfreq = <NUM_LIT:1.0>/endp<EOL>maxfreq = <NUM_LIT:1.0>/startp<EOL>nfreq = int(npceil((maxfreq - minfreq)/stepsize))<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' % (startp, endp, nfreq,<EOL>minfreq, maxfreq))<EOL>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(stepsize, nphasebins,<EOL>mintransitduration, maxtransitduration))<EOL><DEDENT><DEDENT>if nfreq > <NUM_LIT>:<EOL><INDENT>if verbose:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT><DEDENT>if minfreq < (<NUM_LIT:1.0>/(stimes.max() - stimes.min())):<EOL><INDENT>if verbose:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (endp, stimes.max() - stimes.min()))<EOL><DEDENT>minfreq = <NUM_LIT>/(stimes.max() - stimes.min())<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' %<EOL>(minfreq, maxfreq))<EOL><DEDENT><DEDENT>try:<EOL><INDENT>blsresult = _bls_runner(stimes,<EOL>smags,<EOL>nfreq,<EOL>minfreq,<EOL>stepsize,<EOL>nphasebins,<EOL>mintransitduration,<EOL>maxtransitduration)<EOL>frequencies = minfreq + nparange(nfreq)*stepsize<EOL>periods = <NUM_LIT:1.0>/frequencies<EOL>lsp = blsresult['<STR_LIT>']<EOL>finitepeakind = npisfinite(lsp)<EOL>finlsp = lsp[finitepeakind]<EOL>finperiods = periods[finitepeakind]<EOL>try:<EOL><INDENT>bestperiodind = npargmax(finlsp)<EOL><DEDENT>except ValueError:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':magsarefluxes}}<EOL><DEDENT>sortedlspind = npargsort(finlsp)[::-<NUM_LIT:1>]<EOL>sortedlspperiods = finperiods[sortedlspind]<EOL>sortedlspvals = finlsp[sortedlspind]<EOL>nbestperiods, nbestlspvals, peakcount = (<EOL>[finperiods[bestperiodind]],<EOL>[finlsp[bestperiodind]],<EOL><NUM_LIT:1><EOL>)<EOL>prevperiod = sortedlspperiods[<NUM_LIT:0>]<EOL>for period, lspval in zip(sortedlspperiods, sortedlspvals):<EOL><INDENT>if peakcount == nbestpeaks:<EOL><INDENT>break<EOL><DEDENT>perioddiff = abs(period - prevperiod)<EOL>bestperiodsdiff = [abs(period - x) for x in nbestperiods]<EOL>if (perioddiff > (periodepsilon*prevperiod) and<EOL>all(x > (periodepsilon*period)<EOL>for x in bestperiodsdiff)):<EOL><INDENT>nbestperiods.append(period)<EOL>nbestlspvals.append(lspval)<EOL>peakcount = peakcount + <NUM_LIT:1><EOL><DEDENT>prevperiod = period<EOL><DEDENT>resultdict = {<EOL>'<STR_LIT>':finperiods[bestperiodind],<EOL>'<STR_LIT>':finlsp[bestperiodind],<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':nbestlspvals,<EOL>'<STR_LIT>':nbestperiods,<EOL>'<STR_LIT>':lsp,<EOL>'<STR_LIT>':frequencies,<EOL>'<STR_LIT>':periods,<EOL>'<STR_LIT>':blsresult,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':nfreq,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':magsarefluxes}<EOL>}<EOL>if get_stats:<EOL><INDENT>resultdict['<STR_LIT>'] = []<EOL>for bp in nbestperiods:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO("<STR_LIT>" % bp)<EOL><DEDENT>this_pstats = bls_stats_singleperiod(<EOL>times, mags, errs, bp,<EOL>magsarefluxes=resultdict['<STR_LIT>']['<STR_LIT>'],<EOL>sigclip=resultdict['<STR_LIT>']['<STR_LIT>'],<EOL>nphasebins=resultdict['<STR_LIT>'],<EOL>mintransitduration=resultdict['<STR_LIT>'],<EOL>maxtransitduration=resultdict['<STR_LIT>'],<EOL>verbose=verbose,<EOL>)<EOL>resultdict['<STR_LIT>'].append(this_pstats)<EOL><DEDENT><DEDENT>return resultdict<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':nfreq,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':magsarefluxes}}<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':magsarefluxes}}<EOL><DEDENT>

Runs the Box Least Squares Fitting Search for transit-shaped signals.

    Based on eebls.f from Kovacs et al. 2002 and python-bls from Foreman-Mackey
    et al. 2015. This is the serial version (which is good enough in most cases
    because BLS in Fortran is fairly fast). If nfreq > 5e5, this will take a
    while.

    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.

    nphasebins : int
        The number of phase bins to use in the period search.

    autofreq : bool
        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))

    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.

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

    get_stats : bool
        If True, runs :py:func:`.bls_stats_singleperiod` for each of the best
        periods in the output and injects the output into the output dict so you
        only have to run this function to get the periods and their stats.

    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,
             'stats': BLS stats for each best period,
             'lspvals': the full array of periodogram powers,
             'frequencies': the full array of frequencies considered,
             'periods': the full array of periods considered,
             'blsresult': the result dict from the eebls.f wrapper function,
             'stepsize': the actual stepsize used,
             'nfreq': the actual nfreq used,
             'nphasebins': the actual nphasebins 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}}


def bls_parallel_pfind(<EOL>times, mags, errs,<EOL>magsarefluxes=False,<EOL>startp=<NUM_LIT:0.1>,  <EOL>endp=<NUM_LIT>,  <EOL>stepsize=<NUM_LIT>,<EOL>mintransitduration=<NUM_LIT>,  <EOL>maxtransitduration=<NUM_LIT>,   <EOL>nphasebins=<NUM_LIT:200>,<EOL>autofreq=True,  <EOL>nbestpeaks=<NUM_LIT:5>,<EOL>periodepsilon=<NUM_LIT:0.1>,  <EOL>sigclip=<NUM_LIT>,<EOL>verbose=True,<EOL>nworkers=None,<EOL>get_stats=True,<EOL>):

<EOL>stimes, smags, serrs = sigclip_magseries(times,<EOL>mags,<EOL>errs,<EOL>magsarefluxes=magsarefluxes,<EOL>sigclip=sigclip)<EOL>if len(stimes) > <NUM_LIT:9> and len(smags) > <NUM_LIT:9> and len(serrs) > <NUM_LIT:9>:<EOL><INDENT>if autofreq:<EOL><INDENT>nphasebins = int(npceil(<NUM_LIT>/mintransitduration))<EOL>if nphasebins > <NUM_LIT>:<EOL><INDENT>nphasebins = <NUM_LIT><EOL><DEDENT>stepsize = <NUM_LIT>*mintransitduration/(stimes.max()-stimes.min())<EOL>minfreq = <NUM_LIT:1.0>/endp<EOL>maxfreq = <NUM_LIT:1.0>/startp<EOL>nfreq = int(npceil((maxfreq - minfreq)/stepsize))<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' % (startp, endp, nfreq,<EOL>minfreq, maxfreq))<EOL>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(stepsize, nphasebins,<EOL>mintransitduration, maxtransitduration))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>minfreq = <NUM_LIT:1.0>/endp<EOL>maxfreq = <NUM_LIT:1.0>/startp<EOL>nfreq = int(npceil((maxfreq - minfreq)/stepsize))<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' % (startp, endp, nfreq,<EOL>minfreq, maxfreq))<EOL>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(stepsize, nphasebins,<EOL>mintransitduration, maxtransitduration))<EOL><DEDENT><DEDENT>if minfreq < (<NUM_LIT:1.0>/(stimes.max() - stimes.min())):<EOL><INDENT>minfreq = <NUM_LIT>/(stimes.max() - stimes.min())<EOL>if verbose:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (endp, stimes.max() - stimes.min()))<EOL>LOGINFO('<STR_LIT>' %<EOL>(minfreq, maxfreq))<EOL><DEDENT><DEDENT>if not nworkers or nworkers > NCPUS:<EOL><INDENT>nworkers = NCPUS<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % nworkers)<EOL><DEDENT><DEDENT>frequencies = minfreq + nparange(nfreq)*stepsize<EOL>csrem = int(fmod(nfreq, nworkers))<EOL>csint = int(float(nfreq/nworkers))<EOL>chunk_minfreqs, chunk_nfreqs = [], []<EOL>for x in range(nworkers):<EOL><INDENT>this_minfreqs = frequencies[x*csint]<EOL>if x < (nworkers - <NUM_LIT:1>):<EOL><INDENT>this_nfreqs = frequencies[x*csint:x*csint+csint].size<EOL><DEDENT>else:<EOL><INDENT>this_nfreqs = frequencies[x*csint:x*csint+csint+csrem].size<EOL><DEDENT>chunk_minfreqs.append(this_minfreqs)<EOL>chunk_nfreqs.append(this_nfreqs)<EOL><DEDENT>tasks = [(stimes, smags,<EOL>chunk_minf, chunk_nf,<EOL>stepsize, nphasebins,<EOL>mintransitduration, maxtransitduration)<EOL>for (chunk_nf, chunk_minf)<EOL>in zip(chunk_minfreqs, chunk_nfreqs)]<EOL>if verbose:<EOL><INDENT>for ind, task in enumerate(tasks):<EOL><INDENT>LOGINFO('<STR_LIT>' %<EOL>(ind+<NUM_LIT:1>, task[<NUM_LIT:3>], task[<NUM_LIT:2>]))<EOL><DEDENT>LOGINFO('<STR_LIT>')<EOL><DEDENT>pool = Pool(nworkers)<EOL>results = pool.map(_parallel_bls_worker, tasks)<EOL>pool.close()<EOL>pool.join()<EOL>del pool<EOL>lsp = npconcatenate([x['<STR_LIT>'] for x in results])<EOL>periods = <NUM_LIT:1.0>/frequencies<EOL>finitepeakind = npisfinite(lsp)<EOL>finlsp = lsp[finitepeakind]<EOL>finperiods = periods[finitepeakind]<EOL>try:<EOL><INDENT>bestperiodind = npargmax(finlsp)<EOL><DEDENT>except ValueError:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':magsarefluxes}}<EOL><DEDENT>sortedlspind = npargsort(finlsp)[::-<NUM_LIT:1>]<EOL>sortedlspperiods = finperiods[sortedlspind]<EOL>sortedlspvals = finlsp[sortedlspind]<EOL>nbestperiods, nbestlspvals, peakcount = (<EOL>[finperiods[bestperiodind]],<EOL>[finlsp[bestperiodind]],<EOL><NUM_LIT:1><EOL>)<EOL>prevperiod = sortedlspperiods[<NUM_LIT:0>]<EOL>for period, lspval in zip(sortedlspperiods, sortedlspvals):<EOL><INDENT>if peakcount == nbestpeaks:<EOL><INDENT>break<EOL><DEDENT>perioddiff = abs(period - prevperiod)<EOL>bestperiodsdiff = [abs(period - x) for x in nbestperiods]<EOL>if (perioddiff > (periodepsilon*prevperiod) and<EOL>all(x > (periodepsilon*period) for x in bestperiodsdiff)):<EOL><INDENT>nbestperiods.append(period)<EOL>nbestlspvals.append(lspval)<EOL>peakcount = peakcount + <NUM_LIT:1><EOL><DEDENT>prevperiod = period<EOL><DEDENT>resultdict = {<EOL>'<STR_LIT>':finperiods[bestperiodind],<EOL>'<STR_LIT>':finlsp[bestperiodind],<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':nbestlspvals,<EOL>'<STR_LIT>':nbestperiods,<EOL>'<STR_LIT>':lsp,<EOL>'<STR_LIT>':frequencies,<EOL>'<STR_LIT>':periods,<EOL>'<STR_LIT>':results,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':nfreq,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':magsarefluxes}<EOL>}<EOL>if get_stats:<EOL><INDENT>resultdict['<STR_LIT>'] = []<EOL>for bp in nbestperiods.copy():<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO("<STR_LIT>" % bp)<EOL><DEDENT>this_pstats = bls_stats_singleperiod(<EOL>times, mags, errs, bp,<EOL>magsarefluxes=resultdict['<STR_LIT>']['<STR_LIT>'],<EOL>sigclip=resultdict['<STR_LIT>']['<STR_LIT>'],<EOL>nphasebins=resultdict['<STR_LIT>'],<EOL>mintransitduration=resultdict['<STR_LIT>'],<EOL>maxtransitduration=resultdict['<STR_LIT>'],<EOL>verbose=verbose,<EOL>)<EOL>resultdict['<STR_LIT>'].append(this_pstats)<EOL><DEDENT><DEDENT>return resultdict<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return {'<STR_LIT>':npnan,<EOL>'<STR_LIT>':npnan,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':{'<STR_LIT>':startp,<EOL>'<STR_LIT>':endp,<EOL>'<STR_LIT>':stepsize,<EOL>'<STR_LIT>':mintransitduration,<EOL>'<STR_LIT>':maxtransitduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':autofreq,<EOL>'<STR_LIT>':periodepsilon,<EOL>'<STR_LIT>':nbestpeaks,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':magsarefluxes}}<EOL><DEDENT>

Runs the Box Least Squares Fitting Search for transit-shaped signals.

    Based on eebls.f from Kovacs et al. 2002 and python-bls from Foreman-Mackey
    et al. 2015. Breaks up the full frequency space into chunks and passes them
    to parallel BLS 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.

    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.

    nphasebins : int
        The number of phase bins to use in the period search.

    autofreq : bool
        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))

    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.

    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.

    get_stats : bool
        If True, runs :py:func:`.bls_stats_singleperiod` for each of the best
        periods in the output and injects the output into the output dict so you
        only have to run this function to get the periods and their stats.

    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,
             'stats': list of stats dicts returned for each best period,
             'lspvals': the full array of periodogram powers,
             'frequencies': the full array of frequencies considered,
             'periods': the full array of periods considered,
             'blsresult': list of result dicts from eebls.f wrapper functions,
             'stepsize': the actual stepsize used,
             'nfreq': the actual nfreq used,
             'nphasebins': the actual nphasebins 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}}


try:<EOL><INDENT>me_epochbin = int((thistransegressbin +<EOL>thistransingressbin)/<NUM_LIT>)<EOL>me_phases = (<EOL>(stimes - stimes.min())/thisbestperiod -<EOL>npfloor((stimes - stimes.min())/thisbestperiod)<EOL>)<EOL>me_phases_sortind = npargsort(me_phases)<EOL>me_sorted_phases = me_phases[me_phases_sortind]<EOL>me_sorted_times = stimes[me_phases_sortind]<EOL>me_bins = nplinspace(<NUM_LIT:0.0>, <NUM_LIT:1.0>, thisnphasebins)<EOL>me_bininds = npdigitize(me_sorted_phases, me_bins)<EOL>me_centertransit_ind = me_bininds == me_epochbin<EOL>me_centertransit_phase = (<EOL>npmedian(me_sorted_phases[me_centertransit_ind])<EOL>)<EOL>me_centertransit_timeloc = npwhere(<EOL>npabs(me_sorted_phases - me_centertransit_phase) ==<EOL>npmin(npabs(me_sorted_phases - me_centertransit_phase))<EOL>)<EOL>me_centertransit_time = me_sorted_times[<EOL>me_centertransit_timeloc<EOL>]<EOL>if me_centertransit_time.size > <NUM_LIT:1>:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(thisbestperiod, repr(me_centertransit_time)))<EOL><DEDENT>thisminepoch = me_centertransit_time[<NUM_LIT:0>]<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL>savfit = savgol_fit_magseries(stimes, smags, serrs,<EOL>thisbestperiod,<EOL>magsarefluxes=magsarefluxes,<EOL>verbose=verbose,<EOL>sigclip=None)<EOL>thisminepoch = savfit['<STR_LIT>']['<STR_LIT>']<EOL><DEDENT>if isinstance(thisminepoch, npndarray):<EOL><INDENT>if verbose:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% repr(thisminepoch))<EOL><DEDENT>thisminepoch = thisminepoch[<NUM_LIT:0>]<EOL><DEDENT>transitparams = [<EOL>thisbestperiod,<EOL>thisminepoch,<EOL>thistransdepth,<EOL>thistransduration,<EOL>ingressdurationfraction*thistransduration<EOL>]<EOL>modelfit = traptransit_fit_magseries(<EOL>stimes,<EOL>smags,<EOL>serrs,<EOL>transitparams,<EOL>sigclip=None,<EOL>magsarefluxes=magsarefluxes,<EOL>verbose=verbose<EOL>)<EOL>if modelfit and modelfit['<STR_LIT>']['<STR_LIT>'] is not None:<EOL><INDENT>fitparams = modelfit['<STR_LIT>']['<STR_LIT>']<EOL>fiterrs = modelfit['<STR_LIT>']['<STR_LIT>']<EOL>modelmags, actualmags, modelphase = (<EOL>modelfit['<STR_LIT>']['<STR_LIT>'],<EOL>modelfit['<STR_LIT>']['<STR_LIT>'],<EOL>modelfit['<STR_LIT>']['<STR_LIT>']<EOL>)<EOL>subtractedmags = actualmags - modelmags<EOL>subtractedrms = npstd(subtractedmags)<EOL>fit_period, fit_epoch, fit_depth, fit_duration, fit_ingress_dur = (<EOL>fitparams<EOL>)<EOL>npts_in_transit = modelfit['<STR_LIT>']['<STR_LIT>']<EOL>transit_snr = (<EOL>npsqrt(npts_in_transit) * npabs(fit_depth/subtractedrms)<EOL>)<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(fit_period, fit_epoch))<EOL>LOGINFO('<STR_LIT>' % npts_in_transit)<EOL>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(fit_depth,<EOL>fit_duration,<EOL>transit_snr))<EOL><DEDENT>return {'<STR_LIT>':fit_period,<EOL>'<STR_LIT>':fit_epoch,<EOL>'<STR_LIT>':transit_snr,<EOL>'<STR_LIT>':fit_depth,<EOL>'<STR_LIT>':fit_duration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':thistransingressbin,<EOL>'<STR_LIT>':thistransegressbin,<EOL>'<STR_LIT>':npts_in_transit,<EOL>'<STR_LIT>':modelmags,<EOL>'<STR_LIT>':subtractedmags,<EOL>'<STR_LIT>':actualmags,<EOL>'<STR_LIT>':modelphase,<EOL>'<STR_LIT>':fitparams,<EOL>'<STR_LIT>':fiterrs,<EOL>'<STR_LIT>':modelfit}<EOL><DEDENT>else:<EOL><INDENT>phased_magseries = phase_magseries_with_errs(stimes,<EOL>smags,<EOL>serrs,<EOL>thisbestperiod,<EOL>thisminepoch,<EOL>wrap=False,<EOL>sort=True)<EOL>tphase = phased_magseries['<STR_LIT>']<EOL>tmags = phased_magseries['<STR_LIT>']<EOL>transitphase = thistransduration/<NUM_LIT><EOL>transitindices = ((tphase < transitphase) |<EOL>(tphase > (<NUM_LIT:1.0> - transitphase)))<EOL>blsmodel = npfull_like(tmags, npmedian(tmags))<EOL>if magsarefluxes:<EOL><INDENT>blsmodel[transitindices] = (<EOL>blsmodel[transitindices] - thistransdepth<EOL>)<EOL><DEDENT>else:<EOL><INDENT>blsmodel[transitindices] = (<EOL>blsmodel[transitindices] - thistransdepth<EOL>)<EOL><DEDENT>subtractedmags = tmags - blsmodel<EOL>subtractedrms = npstd(subtractedmags)<EOL>npts_in_transit = len(tmags[transitindices])<EOL>thissnr = (<EOL>npsqrt(npts_in_transit) * npabs(thistransdepth/subtractedrms)<EOL>)<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(thisbestperiod, thisminepoch))<EOL>LOGINFO('<STR_LIT>' % (<NUM_LIT:1.0> -<EOL>transitphase,<EOL><NUM_LIT:1.0>))<EOL>LOGINFO('<STR_LIT>' % (<NUM_LIT:0.0>,<EOL>transitphase))<EOL>LOGINFO('<STR_LIT>' % tmags[transitindices].size)<EOL>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(thistransdepth,<EOL>thistransduration,<EOL>thissnr))<EOL><DEDENT>return {'<STR_LIT>':thisbestperiod,<EOL>'<STR_LIT>':thisminepoch,<EOL>'<STR_LIT>':thissnr,<EOL>'<STR_LIT>':thistransdepth,<EOL>'<STR_LIT>':thistransduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':thistransingressbin,<EOL>'<STR_LIT>':thistransegressbin,<EOL>'<STR_LIT>':blsmodel,<EOL>'<STR_LIT>':subtractedmags,<EOL>'<STR_LIT>':tmags,<EOL>'<STR_LIT>':tphase}<EOL><DEDENT>


<EOL>stimes, smags, serrs = sigclip_magseries(times,<EOL>mags,<EOL>errs,<EOL>magsarefluxes=magsarefluxes,<EOL>sigclip=sigclip)<EOL>if len(stimes) > <NUM_LIT:9> and len(smags) > <NUM_LIT:9> and len(serrs) > <NUM_LIT:9>:<EOL><INDENT>startp = period - perioddeltapercent*period/<NUM_LIT><EOL>if startp < <NUM_LIT:0>:<EOL><INDENT>startp = period<EOL><DEDENT>endp = period + perioddeltapercent*period/<NUM_LIT><EOL>blsres = bls_serial_pfind(stimes, smags, serrs,<EOL>verbose=verbose,<EOL>startp=startp,<EOL>endp=endp,<EOL>nphasebins=nphasebins,<EOL>mintransitduration=mintransitduration,<EOL>maxtransitduration=maxtransitduration,<EOL>magsarefluxes=magsarefluxes,<EOL>get_stats=False,<EOL>sigclip=None)<EOL>if (not blsres or<EOL>'<STR_LIT>' not in blsres or<EOL>blsres['<STR_LIT>'] is None):<EOL><INDENT>LOGERROR("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" % period)<EOL>return None<EOL><DEDENT>thistransdepth = blsres['<STR_LIT>']['<STR_LIT>']<EOL>thistransduration = blsres['<STR_LIT>']['<STR_LIT>']<EOL>thisbestperiod = blsres['<STR_LIT>']<EOL>thistransingressbin = blsres['<STR_LIT>']['<STR_LIT>']<EOL>thistransegressbin = blsres['<STR_LIT>']['<STR_LIT>']<EOL>thisnphasebins = nphasebins<EOL>stats = _get_bls_stats(stimes,<EOL>smags,<EOL>serrs,<EOL>thistransdepth,<EOL>thistransduration,<EOL>ingressdurationfraction,<EOL>nphasebins,<EOL>thistransingressbin,<EOL>thistransegressbin,<EOL>thisbestperiod,<EOL>thisnphasebins,<EOL>magsarefluxes=magsarefluxes,<EOL>verbose=verbose)<EOL>return stats<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return None<EOL><DEDENT>

This calculates the SNR, depth, duration, a refit period, and time of
    center-transit for a single period.

    The equation used for SNR is::

        SNR = (transit model depth / RMS of LC with transit model subtracted)
              * sqrt(number of points in transit)

    NOTE: you should set the kwargs `sigclip`, `nphasebins`,
    `mintransitduration`, `maxtransitduration` to what you used for an initial
    BLS run to detect transits in the input light curve to match those input
    conditions.

    Parameters
    ----------

    times,mags,errs : np.array
        These contain the magnitude/flux time-series and any associated errors.

    period : float
        The period to search around and refit the transits. This will be used to
        calculate the start and end periods of a rerun of BLS to calculate the
        stats.

    magsarefluxes : bool
        Set to True if the input measurements in `mags` are actually fluxes and
        not magnitudes.

    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.

    perioddeltapercent : float
        The fraction of the period provided to use to search around this
        value. This is a percentage. The period range searched will then be::

            [period - (perioddeltapercent/100.0)*period,
             period + (perioddeltapercent/100.0)*period]

    nphasebins : int
        The number of phase bins to use in the BLS run.

    mintransitduration : float
        The minimum transit duration in phase to consider.

    maxtransitduration : float
        The maximum transit duration to consider.

    ingressdurationfraction : float
        The fraction of the transit duration to use to generate an initial value
        of the transit ingress duration for the BLS model refit. This will be
        fit by this function.

    verbose : bool
        If True, will indicate progress and any problems encountered.

    Returns
    -------

    dict
        A dict of the following form is returned::

            {'period': the refit best period,
             'epoch': the refit epoch (i.e. mid-transit time),
             'snr':the SNR of the transit,
             'transitdepth':the depth of the transit,
             'transitduration':the duration of the transit,
             'nphasebins':the input value of nphasebins,
             'transingressbin':the phase bin containing transit ingress,
             'transegressbin':the phase bin containing transit egress,
             'blsmodel':the full BLS model used along with its parameters,
             'subtractedmags':BLS model - phased light curve,
             'phasedmags':the phase light curve,
             'phases': the phase values}


<EOL>if (npeaks and (<NUM_LIT:0> < npeaks < len(blsdict['<STR_LIT>']))):<EOL><INDENT>nperiods = npeaks<EOL><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>len(blsdict['<STR_LIT>']))<EOL><DEDENT>nperiods = len(blsdict['<STR_LIT>'])<EOL><DEDENT>nbestperiods = blsdict['<STR_LIT>'][:nperiods]<EOL>stimes, smags, serrs = sigclip_magseries(times,<EOL>mags,<EOL>errs,<EOL>magsarefluxes=magsarefluxes,<EOL>sigclip=sigclip)<EOL>if len(stimes) > <NUM_LIT:9> and len(smags) > <NUM_LIT:9> and len(serrs) > <NUM_LIT:9>:<EOL><INDENT>nbestsnrs = []<EOL>transitdepth, transitduration = [], []<EOL>nphasebins, transingressbin, transegressbin = [], [], []<EOL>allsubtractedmags = []<EOL>allphasedmags = []<EOL>allphases = []<EOL>allblsmodels = []<EOL>refitperiods = []<EOL>refitepochs = []<EOL>for period in nbestperiods:<EOL><INDENT>startp = period - perioddeltapercent*period/<NUM_LIT><EOL>if startp < <NUM_LIT:0>:<EOL><INDENT>startp = period<EOL><DEDENT>endp = period + perioddeltapercent*period/<NUM_LIT><EOL>if not assumeserialbls:<EOL><INDENT>prevkwargs = blsdict['<STR_LIT>'].copy()<EOL>prevkwargs['<STR_LIT>'] = verbose<EOL>prevkwargs['<STR_LIT>'] = startp<EOL>prevkwargs['<STR_LIT>'] = endp<EOL>prevkwargs['<STR_LIT>'] = None<EOL>blsres = bls_serial_pfind(stimes,<EOL>smags,<EOL>serrs,<EOL>**prevkwargs)<EOL><DEDENT>else:<EOL><INDENT>blsres = blsdict<EOL><DEDENT>thistransdepth = blsres['<STR_LIT>']['<STR_LIT>']<EOL>thistransduration = blsres['<STR_LIT>']['<STR_LIT>']<EOL>thisbestperiod = blsres['<STR_LIT>']<EOL>thistransingressbin = blsres['<STR_LIT>']['<STR_LIT>']<EOL>thistransegressbin = blsres['<STR_LIT>']['<STR_LIT>']<EOL>thisnphasebins = blsdict['<STR_LIT>']['<STR_LIT>']<EOL>stats = _get_bls_stats(stimes,<EOL>smags,<EOL>serrs,<EOL>thistransdepth,<EOL>thistransduration,<EOL>ingressdurationfraction,<EOL>nphasebins,<EOL>thistransingressbin,<EOL>thistransegressbin,<EOL>thisbestperiod,<EOL>thisnphasebins,<EOL>magsarefluxes=magsarefluxes,<EOL>verbose=verbose)<EOL>nbestsnrs.append(stats['<STR_LIT>'])<EOL>transitdepth.append(stats['<STR_LIT>'])<EOL>transitduration.append(stats['<STR_LIT>'])<EOL>transingressbin.append(stats['<STR_LIT>'])<EOL>transegressbin.append(stats['<STR_LIT>'])<EOL>nphasebins.append(stats['<STR_LIT>'])<EOL>refitperiods.append(stats['<STR_LIT>'])<EOL>refitepochs.append(stats['<STR_LIT>'])<EOL>allsubtractedmags.append(stats['<STR_LIT>'])<EOL>allphasedmags.append(stats['<STR_LIT>'])<EOL>allphases.append(stats['<STR_LIT>'])<EOL>allblsmodels.append(stats['<STR_LIT>'])<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>nbestsnrs = None<EOL>transitdepth, transitduration = None, None<EOL>nphasebins, transingressbin, transegressbin = None, None, None<EOL>allsubtractedmags, allphases, allphasedmags = None, None, None<EOL><DEDENT>return {'<STR_LIT>':npeaks,<EOL>'<STR_LIT>':refitperiods,<EOL>'<STR_LIT>':refitepochs,<EOL>'<STR_LIT>':nbestsnrs,<EOL>'<STR_LIT>':transitdepth,<EOL>'<STR_LIT>':transitduration,<EOL>'<STR_LIT>':nphasebins,<EOL>'<STR_LIT>':transingressbin,<EOL>'<STR_LIT>':transegressbin,<EOL>'<STR_LIT>':allblsmodels,<EOL>'<STR_LIT>':allsubtractedmags,<EOL>'<STR_LIT>':allphasedmags,<EOL>'<STR_LIT>':allphases}<EOL>

Calculates the signal to noise ratio for each best peak in the BLS
    periodogram, along with transit depth, duration, and refit period and epoch.

    The following equation is used for SNR::

        SNR = (transit model depth / RMS of LC with transit model subtracted)
              * sqrt(number of points in transit)

    Parameters
    ----------

    blsdict : dict
        This is an lspinfo dict produced by either `bls_parallel_pfind` or
        `bls_serial_pfind` in this module, or by your own BLS function. If you
        provide results in a dict from an external BLS function, make sure this
        matches 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,
             'blsresult': list of result dicts from eebls.f wrapper functions,
             'stepsize': the actual stepsize used,
             'nfreq': the actual nfreq used,
             'nphasebins': the actual nphasebins 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}}

    times,mags,errs : np.array
        These contain the magnitude/flux time-series and any associated errors.

    assumeserialbls : bool
        If this is True, this function will not rerun BLS around each best peak
        in the input lspinfo dict to refit the periods and epochs. This is
        usally required for `bls_parallel_pfind` so set this to False if you use
        results from that function. The parallel method breaks up the frequency
        space into chunks for speed, and the results may not exactly match those
        from a regular BLS run.

    magsarefluxes : bool
        Set to True if the input measurements in `mags` are actually fluxes and
        not magnitudes.

    npeaks : int or None
        This controls how many of the periods in `blsdict['nbestperiods']` to
        find the SNR for. If it's None, then this will calculate the SNR for all
        of them. If it's an integer between 1 and
        `len(blsdict['nbestperiods'])`, will calculate for only the specified
        number of peak periods, starting from the best period.

    perioddeltapercent : float
        The fraction of the period provided to use to search around this
        value. This is a percentage. The period range searched will then be::

            [period - (perioddeltapercent/100.0)*period,
             period + (perioddeltapercent/100.0)*period]

    ingressdurationfraction : float
        The fraction of the transit duration to use to generate an initial value
        of the transit ingress duration for the BLS model refit. This will be
        fit by this function.

    verbose : bool
        If True, will indicate progress and any problems encountered.

    Returns
    -------

    dict
        A dict of the following form is returned::

            {'npeaks: the number of periodogram peaks requested to get SNR for,
             'period': list of refit best periods for each requested peak,
             'epoch': list of refit epochs (i.e. mid-transit times),
             'snr':list of SNRs of the transit for each requested peak,
             'transitdepth':list of depths of the transits,
             'transitduration':list of durations of the transits,
             'nphasebins':the input value of nphasebins,
             'transingressbin':the phase bin containing transit ingress,
             'transegressbin':the phase bin containing transit egress,
             'allblsmodels':the full BLS models used along with its parameters,
             'allsubtractedmags':BLS models - phased light curves,
             'allphasedmags':the phase light curves,
             'allphases': the phase values}


baseline = times.max() - times.min()<EOL>nsamples = times.size<EOL>df = <NUM_LIT:1.> / baseline / samplesperpeak<EOL>if minfreq is not None:<EOL><INDENT>f0 = minfreq<EOL><DEDENT>else:<EOL><INDENT>f0 = <NUM_LIT:0.5> * df<EOL><DEDENT>if maxfreq is not None:<EOL><INDENT>Nf = int(np.ceil((maxfreq - f0) / df))<EOL><DEDENT>else:<EOL><INDENT>Nf = int(<NUM_LIT:0.5> * samplesperpeak * nyquistfactor * nsamples)<EOL><DEDENT>if returnf0dfnf:<EOL><INDENT>return f0, df, Nf, f0 + df * np.arange(Nf)<EOL><DEDENT>else:<EOL><INDENT>return f0 + df * np.arange(Nf)<EOL><DEDENT>

This calculates a frequency grid for the period finding functions in this
    module.

    Based on the autofrequency function in astropy.stats.lombscargle.

    http://docs.astropy.org/en/stable/_modules/astropy/stats/lombscargle/core.html#LombScargle.autofrequency

    Parameters
    ----------

    times : np.array
        The times to use to generate the frequency grid over.

    samplesperpeak : int
        The minimum sample coverage each frequency point in the grid will get.

    nyquistfactor : int
        The multiplier over the Nyquist rate to use.

    minfreq,maxfreq : float or None
        If not None, these will be the limits of the frequency grid generated.

    returnf0dfnf : bool
        If this is True, will return the values of `f0`, `df`, and `Nf`
        generated for this grid.

    Returns
    -------

    np.array
        A grid of frequencies.


def independent_freq_count(frequencies, times, conservative=True):

M = frequencies.ptp()*times.ptp()<EOL>if conservative:<EOL><INDENT>M_eff = min([times.size, frequencies.size, M])<EOL><DEDENT>else:<EOL><INDENT>M_eff = M<EOL><DEDENT>return M_eff<EOL>

This estimates M: the number of independent frequencies in the periodogram.

    This follows the terminology on page 3 of Zechmeister & Kurster (2009)::

        M = DELTA_f / delta_f

    where::

        DELTA_f = freq.max() - freq.min()
        delta_f = 1.0/(times.max() - times.min())

    Parameters
    ----------

    frequencies : np.array
        The frequencies array used for the calculation of the GLS periodogram.

    times : np.array
        The array of input times used for the calculation of the GLS
        periodogram.

    conservative : bool
        If True, will follow the prescription given in Schwarzenberg-Czerny
        (2003):

        http://adsabs.harvard.edu/abs/2003ASPC..292..383S

        and estimate the number of independent frequences as::

            min(N_obs, N_freq, DELTA_f/delta_f)

    Returns
    -------

    M : int
        The number of independent frequencies.


<EOL>if (npeaks and (<NUM_LIT:0> < npeaks < len(lspinfo['<STR_LIT>']))):<EOL><INDENT>nperiods = npeaks<EOL><DEDENT>else:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>len(lspinfo['<STR_LIT>']))<EOL>nperiods = len(lspinfo['<STR_LIT>'])<EOL><DEDENT>nbestperiods = lspinfo['<STR_LIT>'][:nperiods]<EOL>nbestpeaks = lspinfo['<STR_LIT>'][:nperiods]<EOL>stimes, smags, serrs = sigclip_magseries(times,<EOL>mags,<EOL>errs,<EOL>magsarefluxes=magsarefluxes,<EOL>sigclip=sigclip)<EOL>allpeaks = []<EOL>allperiods = []<EOL>allfaps = []<EOL>alltrialbestpeaks = []<EOL>if len(stimes) > <NUM_LIT:9> and len(smags) > <NUM_LIT:9> and len(serrs) > <NUM_LIT:9>:<EOL><INDENT>for ind, period, peak in zip(range(len(nbestperiods)),<EOL>nbestperiods,<EOL>nbestpeaks):<EOL><INDENT>LOGINFO('<STR_LIT>' % (ind+<NUM_LIT:1>, nbootstrap))<EOL>trialbestpeaks = []<EOL>for _trial in range(nbootstrap):<EOL><INDENT>tindex = np.random.randint(<NUM_LIT:0>,<EOL>high=mags.size,<EOL>size=mags.size)<EOL>if '<STR_LIT>' in lspinfo:<EOL><INDENT>kwargs = lspinfo['<STR_LIT>']<EOL>kwargs.update({'<STR_LIT>':magsarefluxes,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':False})<EOL><DEDENT>else:<EOL><INDENT>kwargs = {'<STR_LIT>':magsarefluxes,<EOL>'<STR_LIT>':sigclip,<EOL>'<STR_LIT>':False}<EOL><DEDENT>lspres = LSPMETHODS[lspinfo['<STR_LIT>']](<EOL>times, mags[tindex], errs[tindex],<EOL>**kwargs<EOL>)<EOL>trialbestpeaks.append(lspres['<STR_LIT>'])<EOL><DEDENT>trialbestpeaks = np.array(trialbestpeaks)<EOL>alltrialbestpeaks.append(trialbestpeaks)<EOL>if lspinfo['<STR_LIT>'] != '<STR_LIT>':<EOL><INDENT>falsealarmprob = (<EOL>(<NUM_LIT:1.0> + trialbestpeaks[trialbestpeaks > peak].size) /<EOL>(trialbestpeaks.size + <NUM_LIT:1.0>)<EOL>)<EOL><DEDENT>else:<EOL><INDENT>falsealarmprob = (<EOL>(<NUM_LIT:1.0> + trialbestpeaks[trialbestpeaks < peak].size) /<EOL>(trialbestpeaks.size + <NUM_LIT:1.0>)<EOL>)<EOL><DEDENT>LOGINFO('<STR_LIT>' % (ind+<NUM_LIT:1>,<EOL>period,<EOL>falsealarmprob))<EOL>allpeaks.append(peak)<EOL>allperiods.append(period)<EOL>allfaps.append(falsealarmprob)<EOL><DEDENT>return {'<STR_LIT>':allpeaks,<EOL>'<STR_LIT>':allperiods,<EOL>'<STR_LIT>':allfaps,<EOL>'<STR_LIT>':alltrialbestpeaks}<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return None<EOL><DEDENT>

Calculates the false alarm probabilities of periodogram peaks using
    bootstrap resampling of the magnitude time series.

    The false alarm probability here is defined as::

        (1.0 + sum(trialbestpeaks[i] > peak[j]))/(ntrialbestpeaks + 1)

    for each best periodogram peak j. The index i is for each bootstrap
    trial. This effectively gives us a significance for the peak. Smaller FAP
    means a better chance that the peak is real.

    The basic idea is to get the number of trial best peaks that are larger than
    the current best peak and divide this by the total number of trials. The
    distribution of these trial best peaks is obtained after scrambling the mag
    values and rerunning the specified periodogram method for a bunch of trials.

    `lspinfo` is the output dict from a periodbase periodogram function and MUST
    contain a 'method' key that corresponds to one of the keys in the LSPMETHODS
    dict above. This will let this function know which periodogram function to
    run to generate the bootstrap samples. The lspinfo SHOULD also have a
    'kwargs' key that corresponds to the input keyword arguments for the
    periodogram function as it was run originally, to keep everything the same
    during the bootstrap runs. If this is missing, default values will be used.

    FIXME: this may not be strictly correct; must look more into bootstrap
    significance testing. Also look into if we're doing resampling correctly for
    time series because the samples are not iid. Look into moving block
    bootstrap.

    Parameters
    ----------

    lspinfo : dict
        A dict of period-finder results from one of the period-finders in
        periodbase, or your own functions, provided it's of the form and
        contains at least the keys listed below::

            {'periods': np.array of all periods searched by the period-finder,
             'lspvals': np.array of periodogram power value for each period,
             'bestperiod': a float value that is the period with the highest
                           peak in the periodogram, i.e. the most-likely actual
                           period,
             'method': a three-letter code naming the period-finder used; must
                       be one of the keys in the
                       `astrobase.periodbase.METHODLABELS` dict,
             'nbestperiods': a list of the periods corresponding to periodogram
                             peaks (`nbestlspvals` below) to annotate on the
                             periodogram plot so they can be called out
                             visually,
             'nbestlspvals': a list of the power values associated with
                             periodogram peaks to annotate on the periodogram
                             plot so they can be called out visually; should be
                             the same length as `nbestperiods` above,
             'kwargs': dict of kwargs passed to your own period-finder function}

        If you provide your own function's period-finder results, you should add
        a corresponding key for it to the LSPMETHODS dict above so the bootstrap
        function can use it correctly. Your period-finder function should take
        `times`, `mags`, errs and any extra parameters as kwargs and return a
        dict of the form described above. A small worked example::

            from your_module import your_periodfinder_func
            from astrobase import periodbase

            periodbase.LSPMETHODS['your-finder'] = your_periodfinder_func

            # run a period-finder session
            your_pfresults = your_periodfinder_func(times, mags, errs,
                                                    **extra_kwargs)

            # run bootstrap to find FAP
            falsealarm_info = periodbase.bootstrap_falsealarmprob(
                your_pfresults,
                times, mags, errs,
                nbootstrap=250,
                magsarefluxes=False,
            )

    times,mags,errs : np.arrays
        The magnitude/flux time-series to process along with their associated
        measurement errors.

    nbootstrap : int
        The total number of bootstrap trials to run. This is set to 250 by
        default, but should probably be around 1000 for realistic results.

    magsarefluxes : bool
        If True, indicates the input time-series is fluxes and not mags.

    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.

    npeaks : int or None
        The number of peaks from the list of 'nbestlspvals' in the period-finder
        result dict to run the bootstrap for. If None, all of the peaks in this
        list will have their FAP calculated.

    Returns
    -------

    dict
        Returns a dict of the form::

            {'peaks':allpeaks,
             'periods':allperiods,
             'probabilities':allfaps,
             'alltrialbestpeaks':alltrialbestpeaks}


def make_combined_periodogram(pflist, outfile, addmethods=False):

import matplotlib.pyplot as plt<EOL>for pf in pflist:<EOL><INDENT>if pf['<STR_LIT>'] == '<STR_LIT>':<EOL><INDENT>plt.plot(pf['<STR_LIT>'],<EOL>np.max(pf['<STR_LIT>'])/pf['<STR_LIT>'] - <NUM_LIT:1.0>,<EOL>label='<STR_LIT>' % (pf['<STR_LIT>'], pf['<STR_LIT>']),<EOL>alpha=<NUM_LIT:0.5>)<EOL><DEDENT>else:<EOL><INDENT>plt.plot(pf['<STR_LIT>'],<EOL>pf['<STR_LIT>']/np.max(pf['<STR_LIT>']),<EOL>label='<STR_LIT>' % (pf['<STR_LIT>'], pf['<STR_LIT>']),<EOL>alpha=<NUM_LIT:0.5>)<EOL><DEDENT><DEDENT>plt.xlabel('<STR_LIT>')<EOL>plt.ylabel('<STR_LIT>')<EOL>plt.xscale('<STR_LIT>')<EOL>plt.legend()<EOL>plt.tight_layout()<EOL>plt.savefig(outfile)<EOL>plt.close('<STR_LIT:all>')<EOL>return outfile<EOL>

This just puts all of the period-finders on a single periodogram.

    This will renormalize all of the periodograms so their values lie between 0
    and 1, with values lying closer to 1 being more significant. Periodograms
    that give the same best periods will have their peaks line up together.

    Parameters
    ----------

    pflist : list of dict
        This is a list of result dicts from any of the period-finders in
        periodbase. To use your own period-finders' results here, make sure the
        result dict is of the form and has at least the keys below::

            {'periods': np.array of all periods searched by the period-finder,
             'lspvals': np.array of periodogram power value for each period,
             'bestperiod': a float value that is the period with the highest
                           peak in the periodogram, i.e. the most-likely actual
                           period,
             'method': a three-letter code naming the period-finder used; must
                       be one of the keys in the
                       `astrobase.periodbase.METHODLABELS` dict,
             'nbestperiods': a list of the periods corresponding to periodogram
                             peaks (`nbestlspvals` below) to annotate on the
                             periodogram plot so they can be called out
                             visually,
             'nbestlspvals': a list of the power values associated with
                             periodogram peaks to annotate on the periodogram
                             plot so they can be called out visually; should be
                             the same length as `nbestperiods` above,
             'kwargs': dict of kwargs passed to your own period-finder function}

    outfile : str
        This is the output file to write the output to. NOTE: EPS/PS won't work
        because we use alpha transparency to better distinguish between the
        various periodograms.

    addmethods : bool
        If this is True, will add all of the normalized periodograms together,
        then renormalize them to between 0 and 1. In this way, if all of the
        period-finders agree on something, it'll stand out easily. FIXME:
        implement this kwarg.

    Returns
    -------

    str
        The name of the generated plot file.