<EOL>finind = np.isfinite(times) & np.isfinite(mags) & np.isfinite(errs)<EOL>ftimes, fmags, ferrs = times[finind], mags[finind], errs[finind]<EOL>nzind = np.nonzero(ferrs)<EOL>ftimes, fmags, ferrs = ftimes[nzind], fmags[nzind], ferrs[nzind]<EOL>lightcurve_median = np.median(fmags)<EOL>lightcurve_mad = np.median(np.abs(fmags - lightcurve_median))<EOL>ffit = lcfit.fourier_fit_magseries(ftimes, fmags, ferrs, period,<EOL>fourierorder=fourierorder,<EOL>sigclip=sigclip,<EOL>magsarefluxes=magsarefluxes,<EOL>verbose=verbose)<EOL>fourier_fitcoeffs = ffit['<STR_LIT>']['<STR_LIT>']<EOL>fourier_chisq = ffit['<STR_LIT>']<EOL>fourier_redchisq = ffit['<STR_LIT>']<EOL>if fourier_fitcoeffs is not None:<EOL><INDENT>fourier_modelmags, _, _, fpmags, _ = sinusoidal.fourier_sinusoidal_func(<EOL>[period,<EOL>ffit['<STR_LIT>']['<STR_LIT>'],<EOL>ffit['<STR_LIT>']['<STR_LIT>'][:fourierorder],<EOL>ffit['<STR_LIT>']['<STR_LIT>'][fourierorder:]],<EOL>ftimes,<EOL>fmags,<EOL>ferrs<EOL>)<EOL>fourier_residuals = fourier_modelmags - fpmags<EOL>fourier_residual_median = np.median(fourier_residuals)<EOL>fourier_residual_mad = np.median(np.abs(fourier_residuals -<EOL>fourier_residual_median))<EOL>famplitudes = fourier_fitcoeffs[:fourierorder]<EOL>fphases = fourier_fitcoeffs[fourierorder:]<EOL>famp_combos = combinations(famplitudes,<NUM_LIT:2>)<EOL>famp_cinds = combinations(range(len(famplitudes)),<NUM_LIT:2>)<EOL>fpha_combos = combinations(fphases,<NUM_LIT:2>)<EOL>fpha_cinds = combinations(range(len(fphases)),<NUM_LIT:2>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>initfourieramps = [<NUM_LIT>] + [<NUM_LIT>]*(fourierorder - <NUM_LIT:1>)<EOL>initfourierphas = [<NUM_LIT:0.1>] + [<NUM_LIT:0.1>]*(fourierorder - <NUM_LIT:1>)<EOL>fourier_modelmags, _, _, fpmags, _ = sinusoidal.fourier_sinusoidal_func(<EOL>[period,<EOL>ffit['<STR_LIT>']['<STR_LIT>'],<EOL>initfourieramps,<EOL>initfourierphas],<EOL>ftimes,<EOL>fmags,<EOL>ferrs<EOL>)<EOL>fourier_residuals = fourier_modelmags - fpmags<EOL>fourier_residual_median = np.median(fourier_residuals)<EOL>fourier_residual_mad = np.median(np.abs(fourier_residuals -<EOL>fourier_residual_median))<EOL>famplitudes = initfourieramps<EOL>fphases = initfourierphas<EOL>famp_combos = combinations(famplitudes,<NUM_LIT:2>)<EOL>famp_cinds = combinations(range(len(famplitudes)),<NUM_LIT:2>)<EOL>fpha_combos = combinations(fphases,<NUM_LIT:2>)<EOL>fpha_cinds = combinations(range(len(fphases)),<NUM_LIT:2>)<EOL><DEDENT>fampratios = {}<EOL>fphadiffs = {}<EOL>for ampi, ampc, phai, phac in zip(famp_cinds,<EOL>famp_combos,<EOL>fpha_cinds,<EOL>fpha_combos):<EOL><INDENT>ampratind = '<STR_LIT>' % (ampi[<NUM_LIT:1>]+<NUM_LIT:1>, ampi[<NUM_LIT:0>]+<NUM_LIT:1>)<EOL>amprat = ampc[<NUM_LIT:1>]/ampc[<NUM_LIT:0>]<EOL>phadiffind = '<STR_LIT>' % (phai[<NUM_LIT:1>]+<NUM_LIT:1>, phai[<NUM_LIT:0>]+<NUM_LIT:1>)<EOL>phadiff = phac[<NUM_LIT:1>] - phai[<NUM_LIT:0>]*phac[<NUM_LIT:0>]<EOL>fampratios[ampratind] = amprat<EOL>fphadiffs[phadiffind] = phadiff<EOL><DEDENT>outdict = {<EOL>'<STR_LIT>':fampratios,<EOL>'<STR_LIT>':fphadiffs,<EOL>'<STR_LIT>':fourier_fitcoeffs,<EOL>'<STR_LIT>':fourier_redchisq,<EOL>'<STR_LIT>':fourier_chisq,<EOL>'<STR_LIT>':fourier_residual_median,<EOL>'<STR_LIT>':fourier_residual_mad,<EOL>'<STR_LIT>':fourier_residual_mad/lightcurve_mad<EOL>}<EOL>planetfitparams = [period,<EOL>None,<EOL>transitparams[<NUM_LIT:0>],<EOL>transitparams[<NUM_LIT:1>],<EOL>transitparams[<NUM_LIT:2>]]<EOL>ebfitparams = [period,<EOL>None,<EOL>ebparams[<NUM_LIT:0>],<EOL>ebparams[<NUM_LIT:1>],<EOL>ebparams[<NUM_LIT:2>],<EOL>ebparams[<NUM_LIT:3>]]<EOL>planet_fit = lcfit.traptransit_fit_magseries(ftimes, fmags, ferrs,<EOL>planetfitparams,<EOL>sigclip=sigclip,<EOL>magsarefluxes=magsarefluxes,<EOL>verbose=verbose)<EOL>planetfit_finalparams = planet_fit['<STR_LIT>']['<STR_LIT>']<EOL>planetfit_finalparamerrs = planet_fit['<STR_LIT>']['<STR_LIT>']<EOL>if planetfit_finalparamerrs is None and fitfailure_means_featurenan:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>planetfit_chisq = np.nan<EOL>planetfit_redchisq = np.nan<EOL>planet_residual_median = np.nan<EOL>planet_residual_mad = np.nan<EOL>planet_residual_mad_over_lcmad = np.nan<EOL><DEDENT>else:<EOL><INDENT>planetfit_chisq = planet_fit['<STR_LIT>']<EOL>planetfit_redchisq = planet_fit['<STR_LIT>']<EOL>if planetfit_finalparams is not None:<EOL><INDENT>planet_modelmags, _, _, ppmags, _ = transits.trapezoid_transit_func(<EOL>planetfit_finalparams,<EOL>ftimes,<EOL>fmags,<EOL>ferrs<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>planet_modelmags, _, _, ppmags, _ = transits.trapezoid_transit_func(<EOL>planetfitparams,<EOL>ftimes,<EOL>fmags,<EOL>ferrs<EOL>)<EOL><DEDENT>planet_residuals = planet_modelmags - ppmags<EOL>planet_residual_median = np.median(planet_residuals)<EOL>planet_residual_mad = np.median(np.abs(planet_residuals -<EOL>planet_residual_median))<EOL>planet_residual_mad_over_lcmad = planet_residual_mad/lightcurve_mad<EOL><DEDENT>eb_fit = lcfit.gaussianeb_fit_magseries(ftimes, fmags, ferrs,<EOL>ebfitparams,<EOL>sigclip=sigclip,<EOL>magsarefluxes=magsarefluxes,<EOL>verbose=verbose)<EOL>ebfit_finalparams = eb_fit['<STR_LIT>']['<STR_LIT>']<EOL>ebfit_finalparamerrs = eb_fit['<STR_LIT>']['<STR_LIT>']<EOL>if ebfit_finalparamerrs is None and fitfailure_means_featurenan:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>ebfit_chisq = np.nan<EOL>ebfit_redchisq = np.nan<EOL>eb_residual_median = np.nan<EOL>eb_residual_mad = np.nan<EOL>eb_residual_mad_over_lcmad = np.nan<EOL><DEDENT>else:<EOL><INDENT>ebfit_chisq = eb_fit['<STR_LIT>']<EOL>ebfit_redchisq = eb_fit['<STR_LIT>']<EOL>if ebfit_finalparams is not None:<EOL><INDENT>eb_modelmags, _, _, ebpmags, _ = eclipses.invgauss_eclipses_func(<EOL>ebfit_finalparams,<EOL>ftimes,<EOL>fmags,<EOL>ferrs<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>eb_modelmags, _, _, ebpmags, _ = eclipses.invgauss_eclipses_func(<EOL>ebfitparams,<EOL>ftimes,<EOL>fmags,<EOL>ferrs<EOL>)<EOL><DEDENT>eb_residuals = eb_modelmags - ebpmags<EOL>eb_residual_median = np.median(eb_residuals)<EOL>eb_residual_mad = np.median(np.abs(eb_residuals - eb_residual_median))<EOL>eb_residual_mad_over_lcmad = eb_residual_mad/lightcurve_mad<EOL><DEDENT>ebfitparams[<NUM_LIT:0>] = ebfitparams[<NUM_LIT:0>]*<NUM_LIT><EOL>eb_fitx2 = lcfit.gaussianeb_fit_magseries(ftimes, fmags, ferrs,<EOL>ebfitparams,<EOL>sigclip=sigclip,<EOL>magsarefluxes=magsarefluxes,<EOL>verbose=verbose)<EOL>ebfitx2_finalparams = eb_fitx2['<STR_LIT>']['<STR_LIT>']<EOL>ebfitx2_finalparamerrs = eb_fitx2['<STR_LIT>']['<STR_LIT>']<EOL>if ebfitx2_finalparamerrs is None and fitfailure_means_featurenan:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>ebfitx2_chisq = np.nan<EOL>ebfitx2_redchisq = np.nan<EOL>ebx2_residual_median = np.nan<EOL>ebx2_residual_mad = np.nan<EOL>ebx2_residual_mad_over_lcmad = np.nan<EOL><DEDENT>else:<EOL><INDENT>ebfitx2_chisq = eb_fitx2['<STR_LIT>']<EOL>ebfitx2_redchisq = eb_fitx2['<STR_LIT>']<EOL>if ebfitx2_finalparams is not None:<EOL><INDENT>ebx2_modelmags, _, _, ebx2pmags, _ = (<EOL>eclipses.invgauss_eclipses_func(<EOL>ebfitx2_finalparams,<EOL>ftimes,<EOL>fmags,<EOL>ferrs<EOL>)<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>ebx2_modelmags, _, _, ebx2pmags, _ = (<EOL>eclipses.invgauss_eclipses_func(<EOL>ebfitparams,<EOL>ftimes,<EOL>fmags,<EOL>ferrs<EOL>)<EOL>)<EOL><DEDENT>ebx2_residuals = ebx2_modelmags - ebx2pmags<EOL>ebx2_residual_median = np.median(ebx2_residuals)<EOL>ebx2_residual_mad = np.median(np.abs(ebx2_residuals -<EOL>ebx2_residual_median))<EOL>ebx2_residual_mad_over_lcmad = ebx2_residual_mad/lightcurve_mad<EOL><DEDENT>outdict.update({<EOL>'<STR_LIT>':planetfit_finalparams,<EOL>'<STR_LIT>':planetfit_chisq,<EOL>'<STR_LIT>':planetfit_redchisq,<EOL>'<STR_LIT>':planet_residual_median,<EOL>'<STR_LIT>':planet_residual_mad,<EOL>'<STR_LIT>':(<EOL>planet_residual_mad_over_lcmad,<EOL>),<EOL>'<STR_LIT>':ebfit_finalparams,<EOL>'<STR_LIT>':ebfit_chisq,<EOL>'<STR_LIT>':ebfit_redchisq,<EOL>'<STR_LIT>':eb_residual_median,<EOL>'<STR_LIT>':eb_residual_mad,<EOL>'<STR_LIT>':(<EOL>eb_residual_mad_over_lcmad,<EOL>),<EOL>'<STR_LIT>':ebfitx2_finalparams,<EOL>'<STR_LIT>':ebfitx2_chisq,<EOL>'<STR_LIT>':ebfitx2_redchisq,<EOL>'<STR_LIT>':ebx2_residual_median,<EOL>'<STR_LIT>':ebx2_residual_mad,<EOL>'<STR_LIT>':(<EOL>ebx2_residual_mad_over_lcmad,<EOL>),<EOL>})<EOL>return outdict<EOL>

This calculates various features related to fitting models to light
    curves.

    This function:

    - calculates `R_ij` and `phi_ij` ratios for Fourier fit amplitudes and
      phases.

    - calculates the reduced chi-sq for fourier, EB, and planet transit fits.

    - calculates the reduced chi-sq for fourier, EB, planet transit fits w/2 x
      period.

    Parameters
    ----------

    times,mags,errs : np.array
        The input mag/flux time-series to calculate periodic features for.

    period : float
        The period of variabiity to use to phase the light curve.

    fourierorder : int
        The Fourier order to use to generate sinusoidal function and fit that to
        the phased light curve.

    transitparams : list of floats
        The transit depth, duration, and ingress duration to use to generate a
        trapezoid planet transit model fit to the phased light curve. The period
        used is the one provided in `period`, while the epoch is automatically
        obtained from a spline fit to the phased light curve.

    ebparams : list of floats
        The primary eclipse depth, eclipse duration, the primary-secondary depth
        ratio, and the phase of the secondary eclipse to use to generate an
        eclipsing binary model fit to the phased light curve. The period used is
        the one provided in `period`, while the epoch is automatically obtained
        from a spline fit to the phased light curve.

    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.

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

    fitfailure_means_featurenan : bool
        If the planet, EB and EBx2 fits don't return standard errors because the
        covariance matrix could not be generated, then the fit is suspicious and
        the features calculated can't be trusted. If
        `fitfailure_means_featurenan` is True, then the output features for
        these fits will be set to nan.

    verbose : bool
        If True, will indicate progress while working.

    Returns
    -------

    dict
        A dict of all the features calculated is returned.


<EOL>pfmethodlist = [pgram['<STR_LIT>'] for pgram in pgramlist]<EOL>if '<STR_LIT>' not in pfmethodlist:<EOL><INDENT>finind = np.isfinite(times) & np.isfinite(mags) & np.isfinite(errs)<EOL>ftimes, fmags, ferrs = times[finind], mags[finind], errs[finind]<EOL>nzind = np.nonzero(ferrs)<EOL>ftimes, fmags, ferrs = ftimes[nzind], fmags[nzind], ferrs[nzind]<EOL>sampling_lsp = specwindow_lsp(times, mags, errs,<EOL>startp=sampling_startp,<EOL>endp=sampling_endp,<EOL>sigclip=sigclip,<EOL>verbose=verbose)<EOL><DEDENT>else:<EOL><INDENT>sampling_lsp = pgramlist[pfmethodlist.index('<STR_LIT>')]<EOL><DEDENT>normalized_sampling_lspvals = (<EOL>sampling_lsp['<STR_LIT>']/(np.nanmax(sampling_lsp['<STR_LIT>']) -<EOL>np.nanmin(sampling_lsp['<STR_LIT>']))<EOL>)<EOL>normalized_sampling_periods = sampling_lsp['<STR_LIT>']<EOL>for pfm, pgram in zip(pfmethodlist, pgramlist):<EOL><INDENT>if pfm == '<STR_LIT>':<EOL><INDENT>best_peak_sampling_ratios = []<EOL>close_to_sidereal_flag = []<EOL>periods = pgram['<STR_LIT>']<EOL>peaks = pgram['<STR_LIT>']<EOL>normalized_peaks = (<NUM_LIT:1.0> - peaks)/(np.nanmax(<NUM_LIT:1.0> - peaks) -<EOL>np.nanmin(<NUM_LIT:1.0> - peaks))<EOL>if pgram['<STR_LIT>'] is None:<EOL><INDENT>LOGERROR('<STR_LIT>' % pfm)<EOL>continue<EOL><DEDENT>for bp in pgram['<STR_LIT>']:<EOL><INDENT>if np.isfinite(bp):<EOL><INDENT>thisp_norm_pgrampeak = normalized_peaks[periods == bp]<EOL>thisp_sampling_pgramind = (<EOL>np.abs(normalized_sampling_periods -<EOL>bp) < pdiff_threshold<EOL>)<EOL>thisp_sampling_peaks = normalized_sampling_lspvals[<EOL>thisp_sampling_pgramind<EOL>]<EOL>if thisp_sampling_peaks.size > <NUM_LIT:1>:<EOL><INDENT>thisp_sampling_ratio = (<EOL>thisp_norm_pgrampeak/np.mean(thisp_sampling_peaks)<EOL>)<EOL><DEDENT>elif thisp_sampling_peaks.size == <NUM_LIT:1>:<EOL><INDENT>thisp_sampling_ratio = (<EOL>thisp_norm_pgrampeak/thisp_sampling_peaks<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % bp)<EOL>thisp_sampling_ratio = np.nan<EOL><DEDENT>best_peak_sampling_ratios.append(thisp_sampling_ratio)<EOL>sidereal_a_ratio = (bp - <NUM_LIT>)/bp<EOL>sidereal_b_ratio = (bp - <NUM_LIT>)/bp<EOL>if ((sidereal_a_ratio < sidereal_threshold) or<EOL>(sidereal_b_ratio < sidereal_threshold)):<EOL><INDENT>close_to_sidereal_flag.append(True)<EOL><DEDENT>else:<EOL><INDENT>close_to_sidereal_flag.append(False)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>best_peak_sampling_ratios.append(np.nan)<EOL>close_to_sidereal_flag.append(False)<EOL><DEDENT><DEDENT>pgram['<STR_LIT>'] = best_peak_sampling_ratios<EOL>pgram['<STR_LIT>'] = close_to_sidereal_flag<EOL><DEDENT>elif pfm != '<STR_LIT>':<EOL><INDENT>best_peak_sampling_ratios = []<EOL>close_to_sidereal_flag = []<EOL>periods = pgram['<STR_LIT>']<EOL>peaks = pgram['<STR_LIT>']<EOL>normalized_peaks = peaks/(np.nanmax(peaks) - np.nanmin(peaks))<EOL>if pgram['<STR_LIT>'] is None:<EOL><INDENT>LOGERROR('<STR_LIT>' % pfm)<EOL>continue<EOL><DEDENT>for bp in pgram['<STR_LIT>']:<EOL><INDENT>if np.isfinite(bp):<EOL><INDENT>thisp_norm_pgrampeak = normalized_peaks[periods == bp]<EOL>thisp_sampling_pgramind = (<EOL>np.abs(normalized_sampling_periods -<EOL>bp) < pdiff_threshold<EOL>)<EOL>thisp_sampling_peaks = normalized_sampling_lspvals[<EOL>thisp_sampling_pgramind<EOL>]<EOL>if thisp_sampling_peaks.size > <NUM_LIT:1>:<EOL><INDENT>thisp_sampling_ratio = (<EOL>thisp_norm_pgrampeak/np.mean(thisp_sampling_peaks)<EOL>)<EOL><DEDENT>elif thisp_sampling_peaks.size == <NUM_LIT:1>:<EOL><INDENT>thisp_sampling_ratio = (<EOL>thisp_norm_pgrampeak/thisp_sampling_peaks<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % bp)<EOL>thisp_sampling_ratio = np.nan<EOL><DEDENT>best_peak_sampling_ratios.append(thisp_sampling_ratio)<EOL>sidereal_a_ratio = (bp - <NUM_LIT>)/bp<EOL>sidereal_b_ratio = (bp - <NUM_LIT>)/bp<EOL>if ((sidereal_a_ratio < sidereal_threshold) or<EOL>(sidereal_b_ratio < sidereal_threshold)):<EOL><INDENT>close_to_sidereal_flag.append(True)<EOL><DEDENT>else:<EOL><INDENT>close_to_sidereal_flag.append(False)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>best_peak_sampling_ratios.append(np.nan)<EOL>close_to_sidereal_flag.append(False)<EOL><DEDENT><DEDENT>pgram['<STR_LIT>'] = best_peak_sampling_ratios<EOL>pgram['<STR_LIT>'] = close_to_sidereal_flag<EOL><DEDENT><DEDENT>all_bestperiods = np.concatenate(<EOL>[x['<STR_LIT>']<EOL>for x in pgramlist if<EOL>(x['<STR_LIT>'] != '<STR_LIT>' and x['<STR_LIT>'] is not None)]<EOL>)<EOL>all_bestperiod_diffs = np.array(<EOL>[abs(a-b) for a,b in combinations(all_bestperiods,<NUM_LIT:2>)]<EOL>)<EOL>all_sampling_ratios = np.concatenate(<EOL>[x['<STR_LIT>']<EOL>for x in pgramlist if<EOL>(x['<STR_LIT>'] != '<STR_LIT>' and x['<STR_LIT>'] is not None)]<EOL>)<EOL>all_sidereal_flags = np.concatenate(<EOL>[x['<STR_LIT>']<EOL>for x in pgramlist if<EOL>(x['<STR_LIT>'] != '<STR_LIT>' and x['<STR_LIT>'] is not None)]<EOL>)<EOL>bestperiods_n_abovesampling = (<EOL>all_sampling_ratios[all_sampling_ratios ><EOL>sampling_peak_multiplier]<EOL>).size<EOL>bestperiods_n_sidereal = all_sidereal_flags.sum()<EOL>bestperiods_diffn_threshold = (<EOL>all_bestperiod_diffs < pdiff_threshold<EOL>).size<EOL>resdict = {<EOL>'<STR_LIT>':bestperiods_n_abovesampling,<EOL>'<STR_LIT>':bestperiods_n_sidereal,<EOL>'<STR_LIT>':bestperiods_diffn_threshold<EOL>}<EOL>return resdict<EOL>

This calculates various periodogram features (for each periodogram).

    The following features are obtained:

    - For all best periods from all periodogram methods in `pgramlist`,
      calculates the number of these with peaks that are at least
      `sampling_peak_multiplier` x time-sampling periodogram peak at the same
      period. This indicates how likely the `pgramlist` periodogram peaks are to
      being real as opposed to just being caused by time-sampling
      window-function of the observations.

    - For all best periods from all periodogram methods in `pgramlist`,
      calculates the number of best periods which are consistent with a sidereal
      day (1.0027379 and 0.9972696), likely indicating that they're not real.

    - For all best periods from all periodogram methods in `pgramlist`,
      calculates the number of cross-wise period differences for all of these
      that fall below the `pdiff_threshold` value. If this is high, most of the
      period-finders in `pgramlist` agree on their best period results, so it's
      likely the periods found are real.

    Parameters
    ----------

    pgramlist : list of dicts
        This is a list of dicts returned by any of the periodfinding methods in
        :py:mod:`astrobase.periodbase`. This can also be obtained from the
        resulting pickle from the :py:func:astrobase.lcproc.periodsearch.run_pf`
        function. It's a good idea to make `pgramlist` a list of periodogram
        lists from all magnitude columns in the input light curve to test
        periodic variability across all magnitude columns (e.g. period diffs
        between EPD and TFA mags)

    times,mags,errs : np.array
        The input flux/mag time-series to use to calculate features. These are
        used to recalculate the time-sampling L-S periodogram (using
        :py:func:`astrobase.periodbase.zgls.specwindow_lsp`) if one is not
        present in pgramlist. If it's present, these can all be set to None.

    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.

    pdiff_threshold : float
        This is the max difference between periods to consider them the same.

    sidereal_threshold : float
        This is the max difference between any of the 'best' periods and the
        sidereal day periods to consider them the same.

    sampling_peak_multiplier : float
        This is the minimum multiplicative factor of a 'best' period's
        normalized periodogram peak over the sampling periodogram peak at the
        same period required to accept the 'best' period as possibly real.

    sampling_startp, sampling_endp : float
        If the `pgramlist` doesn't have a time-sampling Lomb-Scargle
        periodogram, it will be obtained automatically. Use these kwargs to
        control the minimum and maximum period interval to be searched when
        generating this periodogram.

    verbose : bool
        If True, will indicate progress and report errors.

    Returns
    -------

    dict
        Returns a dict with all of the periodogram features calculated.


<EOL>finind = np.isfinite(times) & np.isfinite(mags) & np.isfinite(errs)<EOL>ftimes, fmags, ferrs = times[finind], mags[finind], errs[finind]<EOL>nzind = np.nonzero(ferrs)<EOL>ftimes, fmags, ferrs = ftimes[nzind], fmags[nzind], ferrs[nzind]<EOL>if ftimes.size > <NUM_LIT>:<EOL><INDENT>lightcurve_median = np.median(fmags)<EOL>lightcurve_mad = np.median(np.abs(fmags - lightcurve_median))<EOL>p2p_unphasedlc = lightcurve_ptp_measures(ftimes, fmags, ferrs)<EOL>inveta_unphasedlc = <NUM_LIT:1.0>/p2p_unphasedlc['<STR_LIT>']<EOL>phasedlc = lcmath.phase_magseries_with_errs(ftimes, fmags, ferrs,<EOL>period, ftimes.min(),<EOL>wrap=False)<EOL>phase = phasedlc['<STR_LIT>']<EOL>pmags = phasedlc['<STR_LIT>']<EOL>perrs = phasedlc['<STR_LIT>']<EOL>ptp_bestperiod = lightcurve_ptp_measures(phase,pmags,perrs)<EOL>phasedlc = lcmath.phase_magseries_with_errs(ftimes, fmags, ferrs,<EOL>period*<NUM_LIT>, ftimes.min(),<EOL>wrap=False)<EOL>phasex2 = phasedlc['<STR_LIT>']<EOL>pmagsx2 = phasedlc['<STR_LIT>']<EOL>perrsx2 = phasedlc['<STR_LIT>']<EOL>ptp_bestperiodx2 = lightcurve_ptp_measures(phasex2,pmagsx2,perrsx2)<EOL>inveta_bestperiod = <NUM_LIT:1.0>/ptp_bestperiod['<STR_LIT>']<EOL>inveta_bestperiodx2 = <NUM_LIT:1.0>/ptp_bestperiodx2['<STR_LIT>']<EOL>inveta_ratio_phased_unphased = inveta_bestperiod/inveta_unphasedlc<EOL>inveta_ratio_phasedx2_unphased = inveta_bestperiodx2/inveta_unphasedlc<EOL>phasedx2_maxval_ind = argrelmax(pmagsx2, order=<NUM_LIT:10>)<EOL>if phasedx2_maxval_ind[<NUM_LIT:0>].size > <NUM_LIT:1>:<EOL><INDENT>phasedx2_magdiff_maxval = (<EOL>np.max(np.abs(np.diff(pmagsx2[phasedx2_maxval_ind[<NUM_LIT:0>]])))<EOL>)<EOL><DEDENT>else:<EOL><INDENT>phasedx2_magdiff_maxval = np.nan<EOL><DEDENT>phasedx2_minval_ind = argrelmin(pmagsx2, order=<NUM_LIT:10>)<EOL>if phasedx2_minval_ind[<NUM_LIT:0>].size > <NUM_LIT:1>:<EOL><INDENT>phasedx2_magdiff_minval = (<EOL>np.max(np.abs(np.diff(pmagsx2[phasedx2_minval_ind[<NUM_LIT:0>]])))<EOL>)<EOL><DEDENT>else:<EOL><INDENT>phasedx2_magdiff_minval = np.nan<EOL><DEDENT>phased_magdiff = np.diff(pmags)<EOL>phased_magdiff_median = np.median(phased_magdiff)<EOL>phased_magdiff_mad = np.median(np.abs(phased_magdiff -<EOL>phased_magdiff_median))<EOL>phasedx2_magdiff = np.diff(pmagsx2)<EOL>phasedx2_magdiff_median = np.median(phasedx2_magdiff)<EOL>phasedx2_magdiff_mad = np.median(np.abs(phasedx2_magdiff -<EOL>phasedx2_magdiff_median))<EOL>phased_magdiffmad_unphased_mad_ratio = phased_magdiff_mad/lightcurve_mad<EOL>phasedx2_magdiffmad_unphased_mad_ratio = (<EOL>phasedx2_magdiff_mad/lightcurve_mad<EOL>)<EOL>phasedx2_slopes = np.diff(pmagsx2)/np.diff(phasex2)<EOL>phasedx2_slope_percentiles = np.ravel(np.nanpercentile(phasedx2_slopes,<EOL>[<NUM_LIT>,<NUM_LIT>]))<EOL>phasedx2_slope_10percentile = phasedx2_slope_percentiles[<NUM_LIT:0>]<EOL>phasedx2_slope_90percentile = phasedx2_slope_percentiles[<NUM_LIT:1>]<EOL>if ((nbrtimes is not None) and<EOL>(nbrmags is not None) and<EOL>(nbrerrs is not None)):<EOL><INDENT>nfinind = (np.isfinite(nbrtimes) &<EOL>np.isfinite(nbrmags) &<EOL>np.isfinite(nbrerrs))<EOL>nftimes, nfmags, nferrs = (nbrtimes[nfinind],<EOL>nbrmags[nfinind],<EOL>nbrerrs[nfinind])<EOL>nnzind = np.nonzero(nferrs)<EOL>nftimes, nfmags, nferrs = (nftimes[nnzind],<EOL>nfmags[nnzind],<EOL>nferrs[nnzind])<EOL>if nftimes.size > <NUM_LIT>:<EOL><INDENT>nphasedlc = lcmath.phase_magseries_with_errs(<EOL>nftimes, nfmags, nferrs,<EOL>period, ftimes.min(),<EOL>wrap=False<EOL>)<EOL>norm_pmags = pmags - np.median(pmags)<EOL>norm_npmags = nphasedlc['<STR_LIT>'] - np.median(nphasedlc['<STR_LIT>'])<EOL>phabinned_objectlc = lcmath.phase_bin_magseries(phase,<EOL>norm_pmags,<EOL>minbinelems=<NUM_LIT:1>)<EOL>phabinned_nbrlc = lcmath.phase_bin_magseries(nphasedlc['<STR_LIT>'],<EOL>norm_npmags,<EOL>minbinelems=<NUM_LIT:1>)<EOL>absdiffs = []<EOL>for pha, phamag in zip(phabinned_objectlc['<STR_LIT>'],<EOL>phabinned_objectlc['<STR_LIT>']):<EOL><INDENT>try:<EOL><INDENT>phadiffs = np.abs(pha - phabinned_nbrlc['<STR_LIT>'])<EOL>minphadiffind = np.where(<EOL>(phadiffs < <NUM_LIT>) &<EOL>(phadiffs == np.min(phadiffs))<EOL>)<EOL>absmagdiff = np.abs(<EOL>phamag - phabinned_nbrlc['<STR_LIT>'][<EOL>minphadiffind<EOL>]<EOL>)<EOL>if absmagdiff.size > <NUM_LIT:0>:<EOL><INDENT>absdiffs.append(absmagdiff.min())<EOL><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>continue<EOL><DEDENT><DEDENT>if len(absdiffs) > <NUM_LIT:0>:<EOL><INDENT>sum_nbr_phasedlc_magdiff = sum(absdiffs)<EOL><DEDENT>else:<EOL><INDENT>sum_nbr_phasedlc_magdiff = np.nan<EOL><DEDENT><DEDENT>else:<EOL><INDENT>sum_nbr_phasedlc_magdiff = np.nan<EOL><DEDENT><DEDENT>else:<EOL><INDENT>sum_nbr_phasedlc_magdiff = np.nan<EOL><DEDENT>return {<EOL>'<STR_LIT>':inveta_unphasedlc,<EOL>'<STR_LIT>':inveta_bestperiod,<EOL>'<STR_LIT>':inveta_bestperiodx2,<EOL>'<STR_LIT>':inveta_ratio_phased_unphased,<EOL>'<STR_LIT>':inveta_ratio_phasedx2_unphased,<EOL>'<STR_LIT>':phasedx2_magdiff_maxval,<EOL>'<STR_LIT>':phasedx2_magdiff_minval,<EOL>'<STR_LIT>':(<EOL>phased_magdiffmad_unphased_mad_ratio<EOL>),<EOL>'<STR_LIT>':(<EOL>phasedx2_magdiffmad_unphased_mad_ratio<EOL>),<EOL>'<STR_LIT>':phasedx2_slope_10percentile,<EOL>'<STR_LIT>':phasedx2_slope_90percentile,<EOL>'<STR_LIT>':sum_nbr_phasedlc_magdiff,<EOL>}<EOL><DEDENT>else:<EOL><INDENT>return {<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>}<EOL><DEDENT>

This calculates various phased LC features for the object.

    Some of the features calculated here come from:

    Kim, D.-W., Protopapas, P., Bailer-Jones, C. A. L., et al. 2014, Astronomy
    and Astrophysics, 566, A43, and references therein (especially Richards, et
    al. 2011).

    Parameters
    ----------

    times,mags,errs : np.array
        The input mag/flux time-series to calculate the phased LC features for.

    period : float
        The period used to phase the input mag/flux time-series.

    nbrtimes,nbrmags,nbrerrs : np.array or None
        If `nbrtimes`, `nbrmags`, and `nbrerrs` are all provided, they should be
        ndarrays with `times`, `mags`, `errs` of this object's closest neighbor
        (close within some small number x FWHM of telescope to check for
        blending). This function will then also calculate extra features based
        on the neighbor's phased LC using the `period` provided for the target
        object.

    Returns
    -------

    dict
        Returns a dict with phased LC features.


retdict = {'<STR_LIT>': np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan}<EOL>if ('<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>']) and<EOL>'<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>'])):<EOL><INDENT>retdict['<STR_LIT>'], retdict['<STR_LIT>'] = coordutils.equatorial_to_galactic(<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>']<EOL>)<EOL><DEDENT>if ('<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>']) and<EOL>'<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>']) and<EOL>'<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>'])):<EOL><INDENT>retdict['<STR_LIT>'] = coordutils.total_proper_motion(<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>']<EOL>)<EOL><DEDENT>if ('<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>']) and<EOL>np.isfinite(retdict['<STR_LIT>'])):<EOL><INDENT>retdict['<STR_LIT>'] = coordutils.reduced_proper_motion(<EOL>objectinfo['<STR_LIT>'],<EOL>retdict['<STR_LIT>']<EOL>)<EOL><DEDENT>return retdict<EOL>

Calculates object coordinates features, including:

    - galactic coordinates
    - total proper motion from pmra, pmdecl
    - reduced J proper motion from propermotion and Jmag

    Parameters
    ----------

    objectinfo : dict
        This is an objectinfo dict from a light curve file read into an
        `lcdict`. The format and the minimum keys required are::

            {'ra': the right ascension of the object in decimal degrees,
             'decl': the declination of the object in decimal degrees,
             'pmra': the proper motion in right ascension in mas/yr,
             'pmdecl': the proper motion in declination in mas/yr,
             'jmag': the 2MASS J mag of this object}

    Returns
    -------

    dict
        A dict containing the total proper motion


objectinfo = in_objectinfo.copy()<EOL>outdict = {<EOL>'<STR_LIT>':[],<EOL>'<STR_LIT>':[],<EOL>'<STR_LIT>':[],<EOL>'<STR_LIT>':[],<EOL>'<STR_LIT>':[],<EOL>'<STR_LIT>':[],<EOL>'<STR_LIT>':False<EOL>}<EOL>if ('<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>']) and<EOL>'<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>']) and<EOL>'<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>'])):<EOL><INDENT>if ('<STR_LIT>' not in objectinfo or<EOL>('<STR_LIT>' in objectinfo and objectinfo['<STR_LIT>'] is None) or<EOL>('<STR_LIT>' in objectinfo and not np.isfinite(objectinfo['<STR_LIT>']))):<EOL><INDENT>objectinfo['<STR_LIT>'] = magnitudes.jhk_to_bmag(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'])<EOL>outdict['<STR_LIT>'] = True<EOL><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL><DEDENT>if ('<STR_LIT>' not in objectinfo or<EOL>('<STR_LIT>' in objectinfo and objectinfo['<STR_LIT>'] is None) or<EOL>('<STR_LIT>' in objectinfo and not np.isfinite(objectinfo['<STR_LIT>']))):<EOL><INDENT>objectinfo['<STR_LIT>'] = magnitudes.jhk_to_vmag(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'])<EOL>outdict['<STR_LIT>'] = True<EOL><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL><DEDENT>if ('<STR_LIT>' not in objectinfo or<EOL>('<STR_LIT>' in objectinfo and objectinfo['<STR_LIT>'] is None) or<EOL>('<STR_LIT>' in objectinfo and not np.isfinite(objectinfo['<STR_LIT>']))):<EOL><INDENT>objectinfo['<STR_LIT>'] = magnitudes.jhk_to_sdssu(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'])<EOL>outdict['<STR_LIT>'] = True<EOL><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL><DEDENT>if ('<STR_LIT>' not in objectinfo or<EOL>('<STR_LIT>' in objectinfo and objectinfo['<STR_LIT>'] is None) or<EOL>('<STR_LIT>' in objectinfo and not np.isfinite(objectinfo['<STR_LIT>']))):<EOL><INDENT>objectinfo['<STR_LIT>'] = magnitudes.jhk_to_sdssg(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'])<EOL>outdict['<STR_LIT>'] = True<EOL><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL><DEDENT>if ('<STR_LIT>' not in objectinfo or<EOL>('<STR_LIT>' in objectinfo and objectinfo['<STR_LIT>'] is None) or<EOL>('<STR_LIT>' in objectinfo and not np.isfinite(objectinfo['<STR_LIT>']))):<EOL><INDENT>objectinfo['<STR_LIT>'] = magnitudes.jhk_to_sdssr(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'])<EOL>outdict['<STR_LIT>'] = True<EOL><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL><DEDENT>if ('<STR_LIT>' not in objectinfo or<EOL>('<STR_LIT>' in objectinfo and objectinfo['<STR_LIT>'] is None) or<EOL>('<STR_LIT>' in objectinfo and not np.isfinite(objectinfo['<STR_LIT>']))):<EOL><INDENT>objectinfo['<STR_LIT>'] = magnitudes.jhk_to_sdssi(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'])<EOL>outdict['<STR_LIT>'] = True<EOL><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL><DEDENT>if ('<STR_LIT>' not in objectinfo or<EOL>('<STR_LIT>' in objectinfo and objectinfo['<STR_LIT>'] is None) or<EOL>('<STR_LIT>' in objectinfo and not np.isfinite(objectinfo['<STR_LIT>']))):<EOL><INDENT>objectinfo['<STR_LIT>'] = magnitudes.jhk_to_sdssz(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'])<EOL>outdict['<STR_LIT>'] = True<EOL><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL><DEDENT><DEDENT>if deredden:<EOL><INDENT>try:<EOL><INDENT>extinction = dust.extinction_query(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>verbose=False,<EOL>timeout=dust_timeout)<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGERROR("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>extinction = None<EOL>outdict['<STR_LIT>'] = False<EOL><DEDENT><DEDENT>else:<EOL><INDENT>extinction = None<EOL>outdict['<STR_LIT>'] = False<EOL><DEDENT>if not extinction:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL><DEDENT>our_bandpasses_colors = BANDPASSES_COLORS.copy()<EOL>our_bandpass_list = BANDPASS_LIST[::]<EOL>if custom_bandpasses is not None and isinstance(custom_bandpasses, dict):<EOL><INDENT>our_bandpasses_colors.update(custom_bandpasses)<EOL>for key in custom_bandpasses:<EOL><INDENT>if key not in our_bandpass_list:<EOL><INDENT>our_bandpass_list.append(key)<EOL><DEDENT><DEDENT><DEDENT>for mk in our_bandpass_list:<EOL><INDENT>if (mk in objectinfo and<EOL>objectinfo[mk] is not None and<EOL>np.isfinite(objectinfo[mk])):<EOL><INDENT>thisbandlabel = our_bandpasses_colors[mk]['<STR_LIT:label>']<EOL>thisdustkey = our_bandpasses_colors[mk]['<STR_LIT>']<EOL>outdict[mk] = objectinfo[mk]<EOL>outdict['<STR_LIT>'].append(mk)<EOL>outdict['<STR_LIT>'].append(thisbandlabel)<EOL>if (deredden and extinction):<EOL><INDENT>outdict['<STR_LIT>'] = True<EOL>if (thisdustkey is not None and<EOL>isinstance(thisdustkey, str) and<EOL>thisdustkey in extinction['<STR_LIT>'] and<EOL>np.isfinite(extinction['<STR_LIT>'][thisdustkey]['<STR_LIT>'])):<EOL><INDENT>outdict['<STR_LIT>' % mk] = (<EOL>extinction['<STR_LIT>'][thisdustkey]['<STR_LIT>']<EOL>)<EOL><DEDENT>elif (thisdustkey is not None and<EOL>isinstance(thisdustkey, float)):<EOL><INDENT>outdict['<STR_LIT>' % mk] = thisdustkey<EOL><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>' % mk] = <NUM_LIT:0.0><EOL><DEDENT>outdict['<STR_LIT>' % mk] = (<EOL>outdict[mk] - outdict['<STR_LIT>' % mk]<EOL>)<EOL>outdict['<STR_LIT>'].append('<STR_LIT>' % mk)<EOL>outdict['<STR_LIT>'].append(<EOL>thisbandlabel<EOL>)<EOL>for colorspec in BANDPASSES_COLORS[mk]['<STR_LIT>']:<EOL><INDENT>if colorspec[<NUM_LIT:0>] not in outdict:<EOL><INDENT>colorkey, colorlabel = colorspec<EOL>band1, band2 = colorkey.split('<STR_LIT:->')<EOL>if ('<STR_LIT>' % band1 in outdict and<EOL>'<STR_LIT>' % band2 in outdict and<EOL>np.isfinite(outdict['<STR_LIT>' % band1]) and<EOL>np.isfinite(outdict['<STR_LIT>' % band2])):<EOL><INDENT>outdict[colorkey] = (<EOL>outdict['<STR_LIT>' % band1] -<EOL>outdict['<STR_LIT>' % band2]<EOL>)<EOL>outdict['<STR_LIT>'].append(colorkey)<EOL>outdict['<STR_LIT>'].append(colorlabel)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>outdict['<STR_LIT>'] = False<EOL>outdict['<STR_LIT>' % mk] = <NUM_LIT:0.0><EOL>outdict['<STR_LIT>' % mk] = np.nan<EOL>for colorspec in our_bandpasses_colors[mk]['<STR_LIT>']:<EOL><INDENT>if colorspec[<NUM_LIT:0>] not in outdict:<EOL><INDENT>colorkey, colorlabel = colorspec<EOL>band1, band2 = colorkey.split('<STR_LIT:->')<EOL>if (band1 in outdict and<EOL>band2 in outdict and<EOL>outdict[band1] is not None and<EOL>outdict[band2] is not None and<EOL>np.isfinite(outdict[band1]) and<EOL>np.isfinite(outdict[band2])):<EOL><INDENT>outdict[colorkey] = (<EOL>outdict[band1] -<EOL>outdict[band2]<EOL>)<EOL>outdict['<STR_LIT>'].append(colorkey)<EOL>outdict['<STR_LIT>'].append(colorlabel)<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>outdict[mk] = np.nan<EOL><DEDENT><DEDENT>return outdict<EOL>

Stellar colors and dereddened stellar colors using 2MASS DUST API:

    http://irsa.ipac.caltech.edu/applications/DUST/docs/dustProgramInterface.html

    Parameters
    ----------

    in_objectinfo : dict
        This is a dict that contains the object's magnitudes and positions. This
        requires at least 'ra', and 'decl' as keys which correspond to the right
        ascension and declination of the object, and one or more of the
        following keys for object magnitudes::

            'umag'  -> U mag             -> colors: U-B, U-V, U-g
            'bmag'  -> B mag             -> colors: U-B, B-V
            'vmag'  -> V mag             -> colors: U-V, B-V, V-R, V-I, V-K
            'rmag'  -> R mag             -> colors: V-R, R-I
            'imag'  -> I mag             -> colors: g-I, V-I, R-I, B-I
            'jmag'  -> 2MASS J mag       -> colors: J-H, J-K, g-J, i-J
            'hmag'  -> 2MASS H mag       -> colors: J-H, H-K
            'kmag'  -> 2MASS Ks mag      -> colors: g-Ks, H-Ks, J-Ks, V-Ks
            'sdssu' -> SDSS u mag        -> colors: u-g, u-V
            'sdssg' -> SDSS g mag        -> colors: g-r, g-i, g-K, u-g, U-g, g-J
            'sdssr' -> SDSS r mag        -> colors: r-i, g-r
            'sdssi' -> SDSS i mag        -> colors: r-i, i-z, g-i, i-J, i-W1
            'sdssz' -> SDSS z mag        -> colors: i-z, z-W2, g-z
            'ujmag' -> UKIRT J mag       -> colors: J-H, H-K, J-K, g-J, i-J
            'uhmag' -> UKIRT H mag       -> colors: J-H, H-K
            'ukmag' -> UKIRT K mag       -> colors: g-K, H-K, J-K, V-K
            'irac1' -> Spitzer IRAC1 mag -> colors: i-I1, I1-I2
            'irac2' -> Spitzer IRAC2 mag -> colors: I1-I2, I2-I3
            'irac3' -> Spitzer IRAC3 mag -> colors: I2-I3
            'irac4' -> Spitzer IRAC4 mag -> colors: I3-I4
            'wise1' -> WISE W1 mag       -> colors: i-W1, W1-W2
            'wise2' -> WISE W2 mag       -> colors: W1-W2, W2-W3
            'wise3' -> WISE W3 mag       -> colors: W2-W3
            'wise4' -> WISE W4 mag       -> colors: W3-W4

        These are basically taken from the available reddening bandpasses from
        the 2MASS DUST service. If B, V, u, g, r, i, z aren't provided but 2MASS
        J, H, Ks are all provided, the former will be calculated using the 2MASS
        JHKs -> BVugriz conversion functions in :py:mod:`astrobase.magnitudes`.

    deredden : bool
        If True, will make sure all colors use dereddened mags where possible.

    custom_bandpasses : dict
        This is a dict used to define any custom bandpasses in the
        `in_objectinfo` dict you want to make this function aware of and
        generate colors for. Use the format below for this dict::

            {
            '<bandpass_key_1>':{'dustkey':'<twomass_dust_key_1>',
                                'label':'<band_label_1>'
                                'colors':[['<bandkey1>-<bandkey2>',
                                           '<BAND1> - <BAND2>'],
                                          ['<bandkey3>-<bandkey4>',
                                           '<BAND3> - <BAND4>']]},
            .
            ...
            .
            '<bandpass_key_N>':{'dustkey':'<twomass_dust_key_N>',
                                'label':'<band_label_N>'
                                'colors':[['<bandkey1>-<bandkey2>',
                                           '<BAND1> - <BAND2>'],
                                          ['<bandkey3>-<bandkey4>',
                                           '<BAND3> - <BAND4>']]},
            }

        Where:

        `bandpass_key` is a key to use to refer to this bandpass in the
        `objectinfo` dict, e.g. 'sdssg' for SDSS g band

        `twomass_dust_key` is the key to use in the 2MASS DUST result table for
        reddening per band-pass. For example, given the following DUST result
        table (using http://irsa.ipac.caltech.edu/applications/DUST/)::

            |Filter_name|LamEff |A_over_E_B_V_SandF|A_SandF|A_over_E_B_V_SFD|A_SFD|
            |char       |float  |float             |float  |float           |float|
            |           |microns|                  |mags   |                |mags |
             CTIO U       0.3734              4.107   0.209            4.968 0.253
             CTIO B       0.4309              3.641   0.186            4.325 0.221
             CTIO V       0.5517              2.682   0.137            3.240 0.165
            .
            .
            ...

        The `twomass_dust_key` for 'vmag' would be 'CTIO V'. If you want to
        skip DUST lookup and want to pass in a specific reddening magnitude
        for your bandpass, use a float for the value of
        `twomass_dust_key`. If you want to skip DUST lookup entirely for
        this bandpass, use None for the value of `twomass_dust_key`.

        `band_label` is the label to use for this bandpass, e.g. 'W1' for
        WISE-1 band, 'u' for SDSS u, etc.

        The 'colors' list contains color definitions for all colors you want
        to generate using this bandpass. this list contains elements of the
        form::

            ['<bandkey1>-<bandkey2>','<BAND1> - <BAND2>']

        where the the first item is the bandpass keys making up this color,
        and the second item is the label for this color to be used by the
        frontends. An example::

            ['sdssu-sdssg','u - g']

    dust_timeout : float
        The timeout to use when contacting the 2MASS DUST web service.

    Returns
    -------

    dict
        An `objectinfo` dict with all of the generated colors, dereddened
        magnitude,s dereddened colors, as specified in the input args is
        returned.


<EOL>if np.isfinite(ri_color) and np.isfinite(iz_color):<EOL><INDENT>obj_sti = <NUM_LIT>*ri_color + <NUM_LIT>*(iz_color + <NUM_LIT>)<EOL>obj_sts = -<NUM_LIT>*ri_color + <NUM_LIT>*(iz_color + <NUM_LIT>)<EOL><DEDENT>else:<EOL><INDENT>obj_sti = np.nan<EOL>obj_sts = np.nan<EOL><DEDENT>if (np.isfinite(obj_sti) and np.isfinite(obj_sts) and<EOL>(obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT>if ((obj_sti > <NUM_LIT>) and (obj_sti < <NUM_LIT>)):<EOL><INDENT>m_class = '<STR_LIT>'<EOL><DEDENT><DEDENT>else:<EOL><INDENT>m_class = None<EOL><DEDENT>return m_class, obj_sti, obj_sts<EOL>

This calculates the M-dwarf subtype given SDSS `r-i` and `i-z` colors.

    Parameters
    ----------

    ri_color : float
        The SDSS `r-i` color of the object.

    iz_color : float
        The SDSS `i-z` color of the object.

    Returns
    -------

    (subtype, index1, index2) : tuple
        `subtype`: if the star appears to be an M dwarf, will return an int
        between 0 and 9 indicating its subtype, e.g. will return 4 for an M4
        dwarf. If the object isn't an M dwarf, will return None

        `index1`, `index2`: the M-dwarf color locus value and spread of this
        object calculated from the `r-i` and `i-z` colors.


possible_classes = []<EOL>if not colorfeatures:<EOL><INDENT>return possible_classes<EOL><DEDENT>if not pmfeatures:<EOL><INDENT>return possible_classes<EOL><DEDENT>if ( ('<STR_LIT>' in colorfeatures) and<EOL>(colorfeatures['<STR_LIT>'] is not None) and<EOL>(np.isfinite(colorfeatures['<STR_LIT>'])) ):<EOL><INDENT>u = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>u = np.nan<EOL><DEDENT>if ( ('<STR_LIT>' in colorfeatures) and<EOL>(colorfeatures['<STR_LIT>'] is not None) and<EOL>(np.isfinite(colorfeatures['<STR_LIT>'])) ):<EOL><INDENT>g = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>g = np.nan<EOL><DEDENT>if ( ('<STR_LIT>' in colorfeatures) and<EOL>(colorfeatures['<STR_LIT>'] is not None) and<EOL>(np.isfinite(colorfeatures['<STR_LIT>'])) ):<EOL><INDENT>r = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>r = np.nan<EOL><DEDENT>if ( ('<STR_LIT>' in colorfeatures) and<EOL>(colorfeatures['<STR_LIT>'] is not None) and<EOL>(np.isfinite(colorfeatures['<STR_LIT>'])) ):<EOL><INDENT>i = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>i = np.nan<EOL><DEDENT>if ( ('<STR_LIT>' in colorfeatures) and<EOL>(colorfeatures['<STR_LIT>'] is not None) and<EOL>(np.isfinite(colorfeatures['<STR_LIT>'])) ):<EOL><INDENT>z = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>z = np.nan<EOL><DEDENT>if ( ('<STR_LIT>' in colorfeatures) and<EOL>(colorfeatures['<STR_LIT>'] is not None) and<EOL>(np.isfinite(colorfeatures['<STR_LIT>'])) ):<EOL><INDENT>j = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>j = np.nan<EOL><DEDENT>if ( ('<STR_LIT>' in colorfeatures) and<EOL>(colorfeatures['<STR_LIT>'] is not None) and<EOL>(np.isfinite(colorfeatures['<STR_LIT>'])) ):<EOL><INDENT>h = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>h = np.nan<EOL><DEDENT>if ( ('<STR_LIT>' in colorfeatures) and<EOL>(colorfeatures['<STR_LIT>'] is not None) and<EOL>(np.isfinite(colorfeatures['<STR_LIT>'])) ):<EOL><INDENT>k = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>k = np.nan<EOL><DEDENT>if '<STR_LIT>' in colorfeatures and colorfeatures['<STR_LIT>'] is not None:<EOL><INDENT>um = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>um = np.nan<EOL><DEDENT>if '<STR_LIT>' in colorfeatures and colorfeatures['<STR_LIT>'] is not None:<EOL><INDENT>gm = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>gm = np.nan<EOL><DEDENT>if '<STR_LIT>' in colorfeatures and colorfeatures['<STR_LIT>'] is not None:<EOL><INDENT>rm = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>rm = np.nan<EOL><DEDENT>if '<STR_LIT>' in colorfeatures and colorfeatures['<STR_LIT>'] is not None:<EOL><INDENT>im = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>im = np.nan<EOL><DEDENT>if '<STR_LIT>' in colorfeatures and colorfeatures['<STR_LIT>'] is not None:<EOL><INDENT>zm = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>zm = np.nan<EOL><DEDENT>if '<STR_LIT>' in colorfeatures and colorfeatures['<STR_LIT>'] is not None:<EOL><INDENT>jm = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>jm = np.nan<EOL><DEDENT>if '<STR_LIT>' in colorfeatures and colorfeatures['<STR_LIT>'] is not None:<EOL><INDENT>hm = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>hm = np.nan<EOL><DEDENT>if '<STR_LIT>' in colorfeatures and colorfeatures['<STR_LIT>'] is not None:<EOL><INDENT>km = colorfeatures['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>km = np.nan<EOL><DEDENT>rpmj = pmfeatures['<STR_LIT>'] if np.isfinite(pmfeatures['<STR_LIT>']) else None<EOL>if (np.isfinite(u) and np.isfinite(g) and<EOL>np.isfinite(r) and np.isfinite(i) and<EOL>np.isfinite(z)):<EOL><INDENT>v_color = <NUM_LIT>*(u-g)-<NUM_LIT>*(g-r)+<NUM_LIT>*(r-i)+<NUM_LIT>*(i-z)<EOL><DEDENT>else:<EOL><INDENT>v_color = np.nan<EOL><DEDENT>if (np.isfinite(u) and np.isfinite(g) and np.isfinite(r)):<EOL><INDENT>p1_color = <NUM_LIT>*(u-g)+<NUM_LIT>*(g-r)-<NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>p1_color = np.nan<EOL><DEDENT>if (np.isfinite(u) and np.isfinite(g) and<EOL>np.isfinite(r) and np.isfinite(i)):<EOL><INDENT>l_color = -<NUM_LIT>*u + <NUM_LIT>*g - <NUM_LIT>*r - <NUM_LIT>*i + <NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>l_color = np.nan<EOL><DEDENT>if (np.isfinite(u) and np.isfinite(g) and np.isfinite(r)):<EOL><INDENT>s_color = -<NUM_LIT>*u + <NUM_LIT>*g - <NUM_LIT>*r + <NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>s_color = np.nan<EOL><DEDENT>if (np.isfinite(u) and np.isfinite(g) and np.isfinite(r)):<EOL><INDENT>d_ug = (u-g) + <NUM_LIT>*(g-r) - <NUM_LIT><EOL>d_gr = <NUM_LIT>*(u-g) - (g-r) - <NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>d_ug, d_gr = np.nan, np.nan<EOL><DEDENT>m_subtype, m_sti, m_sts = mdwarf_subtype_from_sdsscolor(r-i, i-z)<EOL>if m_subtype and rpmj and rpmj > <NUM_LIT:1.0>:<EOL><INDENT>possible_classes.append('<STR_LIT:d>' + m_subtype)<EOL><DEDENT>if ( np.isfinite(u) and np.isfinite(g) and np.isfinite(r) and<EOL>((g-r) < -<NUM_LIT>) and ((g-r) > -<NUM_LIT:1.0>) and<EOL>((u-g) < <NUM_LIT>) and ((u-g) > -<NUM_LIT:1>) and<EOL>((u-g+<NUM_LIT:2>*(g-r)) < -<NUM_LIT:0.1>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( np.isfinite(u) and np.isfinite(g) and np.isfinite(r) and<EOL>((u-g) < <NUM_LIT>) and ((u-g) > <NUM_LIT>) and<EOL>((g-r) < <NUM_LIT>) and ((g-r) > -<NUM_LIT:0.5>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(p1_color) and np.isfinite(p1_color) and<EOL>np.isfinite(u) and np.isfinite(g) and np.isfinite(r) ) and<EOL>(p1_color < -<NUM_LIT>) and (p1_color > -<NUM_LIT>) and<EOL>((u-g) < <NUM_LIT>) and ((u-g) > <NUM_LIT>) and<EOL>((g-r) < <NUM_LIT>) and ((g-r) > <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(u) and np.isfinite(g) and np.isfinite(r) and<EOL>np.isfinite(l_color)) and<EOL>((g-r) < <NUM_LIT>) and ((g-r) > -<NUM_LIT:0.5>) and<EOL>((u-g) < <NUM_LIT>) and ((u-g) > <NUM_LIT>) and<EOL>(l_color > <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(p1_color) and np.isfinite(s_color)) and<EOL>(-<NUM_LIT:0.1> < p1_color < <NUM_LIT>) and (s_color > <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(g) and np.isfinite(g) and np.isfinite(r)) and<EOL>((g-r) < <NUM_LIT>) and ((g-r) > <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(g) and np.isfinite(r)) and<EOL>((g-r) < <NUM_LIT>) and ((g-r) > <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(u) and np.isfinite(g) and<EOL>np.isfinite(r) and np.isfinite(i) and<EOL>np.isfinite(l_color)) and<EOL>((g-r) > <NUM_LIT>) and ((g-r) < <NUM_LIT>) and<EOL>(l_color > <NUM_LIT>) and ((u-g) > <NUM_LIT>) and ((u-g) < <NUM_LIT>) and<EOL>((r-i) > <NUM_LIT>) and ((r-i) < <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(u) and np.isfinite(g) and<EOL>np.isfinite(r) and np.isfinite(s_color)) and<EOL>((u-g) < <NUM_LIT>) and ((u-g) > <NUM_LIT>) and<EOL>((g-r) < <NUM_LIT>) and ((g-r) > <NUM_LIT>) and<EOL>(s_color < -<NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(g) and np.isfinite(r)) and<EOL>((g-r) < <NUM_LIT>) and ((g-r) > <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(g) and np.isfinite(r) and np.isfinite(i)) and<EOL>((g-r) > <NUM_LIT>) and ((r-i) < <NUM_LIT>) and ((r-i) > <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(j) and np.isfinite(h) and np.isfinite(k) and<EOL>np.isfinite(g) and np.isfinite(i)) and<EOL>((j-k) > <NUM_LIT>) and<EOL>((j-h) < (<NUM_LIT>*(j-k) + <NUM_LIT>)) and<EOL>((j-h) > (<NUM_LIT>*(j-k) + <NUM_LIT>)) and<EOL>((g-i) > (<NUM_LIT>*(i-k) - <NUM_LIT>)) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(um) and np.isfinite(gm) and<EOL>np.isfinite(rm) and np.isfinite(im)) and<EOL>((um-gm) < <NUM_LIT>) and ((gm-rm) > -<NUM_LIT>) and<EOL>((gm-rm) < <NUM_LIT>) and ((rm-im) > <NUM_LIT:0.5>) and<EOL>((rm-im) < <NUM_LIT>) and<EOL>((gm-rm) > (-<NUM_LIT>*(rm-im)+<NUM_LIT>)) and<EOL>((gm-rm) < (<NUM_LIT>*(rm-im)+<NUM_LIT:0.5>)) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(um) and np.isfinite(gm) and np.isfinite(rm) and<EOL>np.isfinite(im) and np.isfinite(zm)) and<EOL>(zm < <NUM_LIT>) and (um > <NUM_LIT>) and (gm > <NUM_LIT>) and<EOL>(rm > <NUM_LIT>) and ((im - zm) > <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(u) and np.isfinite(g) and np.isfinite(r) and<EOL>np.isfinite(i) and np.isfinite(z) and np.isfinite(d_ug) and<EOL>np.isfinite(d_gr)) and<EOL>((u-g) > <NUM_LIT>) and ((u-g) < <NUM_LIT>) and<EOL>(d_ug > -<NUM_LIT>) and (d_ug < <NUM_LIT>) and<EOL>(d_gr > <NUM_LIT>) and (d_gr < <NUM_LIT>) and<EOL>((r-i) > -<NUM_LIT>) and ((r-i) < <NUM_LIT>) and<EOL>((i-z) > -<NUM_LIT>) and ((i-z) < <NUM_LIT>) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>if ( (np.isfinite(u) and np.isfinite(g) and np.isfinite(r)) and<EOL>( (((u-g) > -<NUM_LIT:0.1>) and ((u-g) < <NUM_LIT>) and<EOL>((g-r) > -<NUM_LIT>) and ((g-r) < <NUM_LIT:0.5>)) or<EOL>((u-g) > (<NUM_LIT>*(g-r) + <NUM_LIT>)) ) ):<EOL><INDENT>possible_classes.append('<STR_LIT>')<EOL><DEDENT>return {'<STR_LIT>':possible_classes,<EOL>'<STR_LIT>':v_color,<EOL>'<STR_LIT>':p1_color,<EOL>'<STR_LIT>':s_color,<EOL>'<STR_LIT>':l_color,<EOL>'<STR_LIT>':d_ug,<EOL>'<STR_LIT>':d_gr,<EOL>'<STR_LIT>':m_sti,<EOL>'<STR_LIT>':m_sts}<EOL>

This calculates rough star type classifications based on star colors
    in the ugrizJHK bands.

    Uses the output from `color_features` and `coord_features`. By default,
    `color_features` will use dereddened colors, as are expected by most
    relations here.

    Based on the color cuts from:

    - SDSS SEGUE (Yanny+ 2009)
    - SDSS QSO catalog (Schneider+ 2007)
    - SDSS RR Lyrae catalog (Sesar+ 2011)
    - SDSS M-dwarf catalog (West+ 2008)
    - Helmi+ 2003
    - Bochanski+ 2014

    Parameters
    ----------

    colorfeatures : dict
        This is the dict produced by the `color_features` function.

    pmfeatures : dict
        This is the dict produced by the `coord_features` function.

    Returns
    -------

    dict
        A dict containing all of the possible classes this object can belong to
        as a list in the `color_classes` key, and values of the various color
        indices used to arrive to that conclusion as the other keys.


<EOL>if ('<STR_LIT>' in objectinfo and '<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and objectinfo['<STR_LIT>'] is not None and<EOL>(isinstance(lclist_kdtree, cKDTree) or<EOL>isinstance(lclist_kdtree, KDTree))):<EOL><INDENT>ra, decl = objectinfo['<STR_LIT>'], objectinfo['<STR_LIT>']<EOL>cosdecl = np.cos(np.radians(decl))<EOL>sindecl = np.sin(np.radians(decl))<EOL>cosra = np.cos(np.radians(ra))<EOL>sinra = np.sin(np.radians(ra))<EOL>xyzdist = <NUM_LIT> * np.sin(np.radians(neighbor_radius_arcsec/<NUM_LIT>)/<NUM_LIT>)<EOL>kdt_dist, kdt_ind = lclist_kdtree.query(<EOL>[cosra*cosdecl,<EOL>sinra*cosdecl,<EOL>sindecl],<EOL>k=<NUM_LIT:100>,<EOL>distance_upper_bound=xyzdist<EOL>)<EOL>finite_distind = (np.isfinite(kdt_dist)) & (kdt_dist > <NUM_LIT:0>)<EOL>finite_dists = kdt_dist[finite_distind]<EOL>nbrindices = kdt_ind[finite_distind]<EOL>n_neighbors = finite_dists.size<EOL>if n_neighbors > <NUM_LIT:0>:<EOL><INDENT>closest_dist = finite_dists.min()<EOL>closest_dist_arcsec = (<EOL>np.degrees(<NUM_LIT>*np.arcsin(closest_dist/<NUM_LIT>))*<NUM_LIT><EOL>)<EOL>closest_dist_nbrind = nbrindices[finite_dists == finite_dists.min()]<EOL>resultdict = {<EOL>'<STR_LIT>':n_neighbors,<EOL>'<STR_LIT>':nbrindices,<EOL>'<STR_LIT>':np.degrees(<NUM_LIT>*np.arcsin(finite_dists/<NUM_LIT>))*<NUM_LIT>,<EOL>'<STR_LIT>':closest_dist_arcsec,<EOL>'<STR_LIT>':closest_dist_nbrind,<EOL>'<STR_LIT>':neighbor_radius_arcsec,<EOL>}<EOL><DEDENT>else:<EOL><INDENT>resultdict = {<EOL>'<STR_LIT>':<NUM_LIT:0>,<EOL>'<STR_LIT>':np.array([]),<EOL>'<STR_LIT>':np.array([]),<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.array([]),<EOL>'<STR_LIT>':neighbor_radius_arcsec,<EOL>}<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGWARNING("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>resultdict = {<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.array([]),<EOL>'<STR_LIT>':np.array([]),<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.array([]),<EOL>'<STR_LIT>':neighbor_radius_arcsec,<EOL>}<EOL><DEDENT>if ('<STR_LIT>' in objectinfo and '<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and objectinfo['<STR_LIT>'] is not None):<EOL><INDENT>gaia_result = gaia.objectlist_conesearch(<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>neighbor_radius_arcsec,<EOL>verbose=verbose,<EOL>timeout=gaia_submit_timeout,<EOL>maxtimeout=gaia_max_timeout,<EOL>maxtries=gaia_submit_tries,<EOL>gaia_mirror=gaia_mirror,<EOL>complete_query_later=complete_query_later<EOL>)<EOL>if gaia_result:<EOL><INDENT>gaia_objlistf = gaia_result['<STR_LIT:result>']<EOL>with gzip.open(gaia_objlistf,'<STR_LIT:rb>') as infd:<EOL><INDENT>try:<EOL><INDENT>gaia_objlist = np.genfromtxt(<EOL>infd,<EOL>names=True,<EOL>delimiter='<STR_LIT:U+002C>',<EOL>dtype='<STR_LIT>',<EOL>usecols=(<NUM_LIT:0>,<NUM_LIT:1>,<NUM_LIT:2>,<NUM_LIT:3>,<NUM_LIT:4>,<NUM_LIT:5>,<NUM_LIT:6>,<NUM_LIT:7>,<NUM_LIT:8>,<NUM_LIT:9>,<NUM_LIT:10>,<NUM_LIT:11>,<NUM_LIT:12>)<EOL>)<EOL><DEDENT>except Exception as e:<EOL><INDENT>gaia_objlist = []<EOL><DEDENT><DEDENT>gaia_objlist = np.atleast_1d(gaia_objlist)<EOL>if gaia_objlist.size > <NUM_LIT:0>:<EOL><INDENT>stampres = skyview.get_stamp(objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'])<EOL>if (stampres and<EOL>'<STR_LIT>' in stampres and<EOL>stampres['<STR_LIT>'] is not None and<EOL>os.path.exists(stampres['<STR_LIT>'])):<EOL><INDENT>stampwcs = WCS(stampres['<STR_LIT>'])<EOL>gaia_xypos = stampwcs.all_world2pix(<EOL>np.column_stack((gaia_objlist['<STR_LIT>'],<EOL>gaia_objlist['<STR_LIT>'])),<EOL><NUM_LIT:1><EOL>)<EOL><DEDENT>else:<EOL><INDENT>gaia_xypos = None<EOL><DEDENT>if gaia_objlist['<STR_LIT>'][<NUM_LIT:0>] < gaia_matchdist_arcsec:<EOL><INDENT>if gaia_objlist.size > <NUM_LIT:1>:<EOL><INDENT>gaia_nneighbors = gaia_objlist[<NUM_LIT:1>:].size<EOL>gaia_status = (<EOL>'<STR_LIT>' %<EOL>gaia_nneighbors<EOL>)<EOL>gaia_ids = gaia_objlist['<STR_LIT>']<EOL>gaia_mags = gaia_objlist['<STR_LIT>']<EOL>gaia_parallaxes = gaia_objlist['<STR_LIT>']<EOL>gaia_parallax_errs = gaia_objlist['<STR_LIT>']<EOL>gaia_pmra = gaia_objlist['<STR_LIT>']<EOL>gaia_pmra_err = gaia_objlist['<STR_LIT>']<EOL>gaia_pmdecl = gaia_objlist['<STR_LIT>']<EOL>gaia_pmdecl_err = gaia_objlist['<STR_LIT>']<EOL>gaia_absolute_mags = magnitudes.absolute_gaia_magnitude(<EOL>gaia_mags, gaia_parallaxes<EOL>)<EOL>if ('<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>'])):<EOL><INDENT>gaiak_colors = gaia_mags - objectinfo['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>gaiak_colors = None<EOL><DEDENT>gaia_dists = gaia_objlist['<STR_LIT>']<EOL>gaia_closest_distarcsec = gaia_objlist['<STR_LIT>'][<NUM_LIT:1>]<EOL>gaia_closest_gmagdiff = (<EOL>gaia_objlist['<STR_LIT>'][<NUM_LIT:0>] -<EOL>gaia_objlist['<STR_LIT>'][<NUM_LIT:1>]<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>' % (objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>']))<EOL>gaia_nneighbors = <NUM_LIT:0><EOL>gaia_status = (<EOL>'<STR_LIT>'<EOL>)<EOL>gaia_ids = gaia_objlist['<STR_LIT>']<EOL>gaia_mags = gaia_objlist['<STR_LIT>']<EOL>gaia_parallaxes = gaia_objlist['<STR_LIT>']<EOL>gaia_parallax_errs = gaia_objlist['<STR_LIT>']<EOL>gaia_pmra = gaia_objlist['<STR_LIT>']<EOL>gaia_pmra_err = gaia_objlist['<STR_LIT>']<EOL>gaia_pmdecl = gaia_objlist['<STR_LIT>']<EOL>gaia_pmdecl_err = gaia_objlist['<STR_LIT>']<EOL>gaia_absolute_mags = magnitudes.absolute_gaia_magnitude(<EOL>gaia_mags, gaia_parallaxes<EOL>)<EOL>if ('<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>'])):<EOL><INDENT>gaiak_colors = gaia_mags - objectinfo['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>gaiak_colors = None<EOL><DEDENT>gaia_dists = gaia_objlist['<STR_LIT>']<EOL>gaia_closest_distarcsec = np.nan<EOL>gaia_closest_gmagdiff = np.nan<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(gaia_matchdist_arcsec,<EOL>objectinfo['<STR_LIT>'], objectinfo['<STR_LIT>'],<EOL>gaia_objlist['<STR_LIT>'][<NUM_LIT:0>]))<EOL>gaia_status = ('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(gaia_matchdist_arcsec,<EOL>gaia_objlist['<STR_LIT>'][<NUM_LIT:0>]))<EOL>gaia_nneighbors = np.nan<EOL>gaia_ids = gaia_objlist['<STR_LIT>']<EOL>gaia_mags = gaia_objlist['<STR_LIT>']<EOL>gaia_parallaxes = gaia_objlist['<STR_LIT>']<EOL>gaia_parallax_errs = gaia_objlist['<STR_LIT>']<EOL>gaia_pmra = gaia_objlist['<STR_LIT>']<EOL>gaia_pmra_err = gaia_objlist['<STR_LIT>']<EOL>gaia_pmdecl = gaia_objlist['<STR_LIT>']<EOL>gaia_pmdecl_err = gaia_objlist['<STR_LIT>']<EOL>gaia_absolute_mags = magnitudes.absolute_gaia_magnitude(<EOL>gaia_mags, gaia_parallaxes<EOL>)<EOL>if ('<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and<EOL>np.isfinite(objectinfo['<STR_LIT>'])):<EOL><INDENT>gaiak_colors = gaia_mags - objectinfo['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>gaiak_colors = None<EOL><DEDENT>gaia_dists = gaia_objlist['<STR_LIT>']<EOL>gaia_closest_distarcsec = np.nan<EOL>gaia_closest_gmagdiff = np.nan<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>gaia_status = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL>gaia_nneighbors = np.nan<EOL>gaia_ids = None<EOL>gaia_mags = None<EOL>gaia_xypos = None<EOL>gaia_parallaxes = None<EOL>gaia_parallax_errs = None<EOL>gaia_pmra = None<EOL>gaia_pmra_err = None<EOL>gaia_pmdecl = None<EOL>gaia_pmdecl_err = None<EOL>gaia_absolute_mags = None<EOL>gaiak_colors = None<EOL>gaia_dists = None<EOL>gaia_closest_distarcsec = np.nan<EOL>gaia_closest_gmagdiff = np.nan<EOL><DEDENT>resultdict.update(<EOL>{'<STR_LIT>':gaia_status,<EOL>'<STR_LIT>':gaia_nneighbors,<EOL>'<STR_LIT>':gaia_ids,<EOL>'<STR_LIT>':gaia_xypos,<EOL>'<STR_LIT>':gaia_mags,<EOL>'<STR_LIT>':gaia_parallaxes,<EOL>'<STR_LIT>':gaia_parallax_errs,<EOL>'<STR_LIT>':gaia_pmra,<EOL>'<STR_LIT>':gaia_pmra_err,<EOL>'<STR_LIT>':gaia_pmdecl,<EOL>'<STR_LIT>':gaia_pmdecl_err,<EOL>'<STR_LIT>':gaia_absolute_mags,<EOL>'<STR_LIT>':gaiak_colors,<EOL>'<STR_LIT>':gaia_dists,<EOL>'<STR_LIT>':gaia_closest_distarcsec,<EOL>'<STR_LIT>':gaia_closest_gmagdiff}<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' % (objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>']))<EOL>resultdict.update(<EOL>{'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan}<EOL>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGERROR("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL>resultdict.update(<EOL>{'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':np.nan,<EOL>'<STR_LIT>':np.nan}<EOL>)<EOL><DEDENT>if ('<STR_LIT>' in objectinfo and '<STR_LIT>' in objectinfo and<EOL>objectinfo['<STR_LIT>'] is not None and objectinfo['<STR_LIT>'] is not None and<EOL>search_simbad):<EOL><INDENT>simbad_result = simbad.objectnames_conesearch(<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>neighbor_radius_arcsec,<EOL>verbose=verbose,<EOL>timeout=gaia_submit_timeout,<EOL>maxtimeout=gaia_max_timeout,<EOL>maxtries=gaia_submit_tries,<EOL>complete_query_later=complete_query_later<EOL>)<EOL><DEDENT>else:<EOL><INDENT>simbad_result = None<EOL><DEDENT>if (simbad_result and<EOL>simbad_result['<STR_LIT:result>'] and<EOL>os.path.exists(simbad_result['<STR_LIT:result>'])):<EOL><INDENT>with gzip.open(simbad_result['<STR_LIT:result>'],'<STR_LIT:rb>') as infd:<EOL><INDENT>try:<EOL><INDENT>simbad_objectnames = np.genfromtxt(<EOL>infd,<EOL>names=True,<EOL>delimiter='<STR_LIT:U+002C>',<EOL>dtype='<STR_LIT>',<EOL>usecols=(<NUM_LIT:0>,<NUM_LIT:1>,<NUM_LIT:2>,<NUM_LIT:3>,<NUM_LIT:4>,<NUM_LIT:5>,<NUM_LIT:6>,<NUM_LIT:7>,<NUM_LIT:8>),<EOL>comments='<STR_LIT:?>',<EOL>)<EOL><DEDENT>except Exception as e:<EOL><INDENT>simbad_objectnames = []<EOL><DEDENT>simbad_objectnames = np.atleast_1d(simbad_objectnames)<EOL>if simbad_objectnames.size > <NUM_LIT:0>:<EOL><INDENT>simbad_mainid = simbad_objectnames['<STR_LIT>'].tolist()<EOL>simbad_allids = simbad_objectnames['<STR_LIT>'].tolist()<EOL>simbad_objtype = simbad_objectnames['<STR_LIT>'].tolist()<EOL>simbad_distarcsec = simbad_objectnames['<STR_LIT>'].tolist()<EOL>simbad_nmatches = len(simbad_mainid)<EOL>simbad_mainid = [x.replace('<STR_LIT:">','<STR_LIT>') for x in simbad_mainid]<EOL>simbad_allids = [x.replace('<STR_LIT:">','<STR_LIT>') for x in simbad_allids]<EOL>simbad_objtype = [x.replace('<STR_LIT:">','<STR_LIT>') for x in simbad_objtype]<EOL>resultdict.update({<EOL>'<STR_LIT>':simbad_nmatches,<EOL>'<STR_LIT>':simbad_mainid,<EOL>'<STR_LIT>':simbad_objtype,<EOL>'<STR_LIT>':simbad_allids,<EOL>'<STR_LIT>':simbad_distarcsec<EOL>})<EOL>if simbad_nmatches > <NUM_LIT:1>:<EOL><INDENT>resultdict['<STR_LIT>'] = (<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT>else:<EOL><INDENT>resultdict['<STR_LIT>'] = '<STR_LIT>'<EOL><DEDENT>if simbad_distarcsec[<NUM_LIT:0>] < gaia_matchdist_arcsec:<EOL><INDENT>resultdict.update({<EOL>'<STR_LIT>':simbad_mainid[<NUM_LIT:0>],<EOL>'<STR_LIT>':simbad_objtype[<NUM_LIT:0>],<EOL>'<STR_LIT>':simbad_allids[<NUM_LIT:0>],<EOL>'<STR_LIT>':simbad_distarcsec[<NUM_LIT:0>],<EOL>'<STR_LIT>':'<STR_LIT>'<EOL>})<EOL><DEDENT>else:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(gaia_matchdist_arcsec,<EOL>objectinfo['<STR_LIT>'],<EOL>objectinfo['<STR_LIT>'],<EOL>simbad_mainid[<NUM_LIT:0>],<EOL>simbad_distarcsec[<NUM_LIT:0>]))<EOL>simbad_status = ('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(gaia_matchdist_arcsec,<EOL>simbad_distarcsec[<NUM_LIT:0>]))<EOL>resultdict.update({<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':simbad_status<EOL>})<EOL><DEDENT><DEDENT>else:<EOL><INDENT>resultdict.update({<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>})<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>if search_simbad:<EOL><INDENT>simbad_status = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>simbad_status = '<STR_LIT>'<EOL><DEDENT>resultdict.update({<EOL>'<STR_LIT>':simbad_status,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>'<STR_LIT>':None,<EOL>})<EOL><DEDENT>return resultdict<EOL>

Gets several neighbor, GAIA, and SIMBAD features:

    From the KD-Tree in the given light curve catalog the object is in:
    `lclist_kdtree`:

    - distance to closest neighbor in arcsec
    - total number of all neighbors within 2 x `neighbor_radius_arcsec`

    From the GAIA DR2 catalog:

    - distance to closest neighbor in arcsec
    - total number of all neighbors within 2 x `neighbor_radius_arcsec`
    - gets the parallax for the object and neighbors
    - calculates the absolute GAIA mag and `G-K` color for use in CMDs
    - gets the proper motion in RA/Dec if available

    From the SIMBAD catalog:

    - the name of the object
    - the type of the object

    Parameters
    ----------

    objectinfo : dict
        This is the objectinfo dict from an object's light curve. This must
        contain at least the following keys::

            {'ra': the right ascension of the object,
             'decl': the declination of the object}

    lclist_kdtree : scipy.spatial.cKDTree object
        This is a KD-Tree built on the Cartesian xyz coordinates from (ra, dec)
        of all objects in the same field as this object. It is similar to that
        produced by :py:func:`astrobase.lcproc.catalogs.make_lclist`, and is
        used to carry out the spatial search required to find neighbors for this
        object.

    neighbor_radius_arcsec : float
        The maximum radius in arcseconds around this object to search for
        neighbors in both the light curve catalog and in the GAIA DR2 catalog.

    gaia_matchdist_arcsec : float
        The maximum distance in arcseconds to use for a GAIA cross-match to this
        object.

    verbose : bool
        If True, indicates progress and warns of problems.

    gaia_submit_timeout : float
        Sets the timeout in seconds to use when submitting a request to look up
        the object's information to the GAIA service. Note that if `fast_mode`
        is set, this is ignored.

    gaia_submit_tries : int
        Sets the maximum number of times the GAIA services will be contacted to
        obtain this object's information. If `fast_mode` is set, this is
        ignored, and the services will be contacted only once (meaning that a
        failure to respond will be silently ignored and no GAIA data will be
        added to the checkplot's objectinfo dict).

    gaia_max_timeout : float
        Sets the timeout in seconds to use when waiting for the GAIA service to
        respond to our request for the object's information. Note that if
        `fast_mode` is set, this is ignored.

    gaia_mirror : str
        This sets the GAIA mirror to use. This is a key in the
        `services.gaia.GAIA_URLS` dict which defines the URLs to hit for each
        mirror.

    search_simbad : bool
        If this is True, searches for objects in SIMBAD at this object's
        location and gets the object's SIMBAD main ID, type, and stellar
        classification if available.

    Returns
    -------

    dict
        Returns a dict with neighbor, GAIA, and SIMBAD features.


def stetson_jindex(ftimes, fmags, ferrs, weightbytimediff=False):

ndet = len(fmags)<EOL>if ndet > <NUM_LIT:9>:<EOL><INDENT>medmag = npmedian(fmags)<EOL>delta_prefactor = (ndet/(ndet - <NUM_LIT:1>))<EOL>sigma_i = delta_prefactor*(fmags - medmag)/ferrs<EOL>sigma_j = nproll(sigma_i,<NUM_LIT:1>)<EOL>if weightbytimediff:<EOL><INDENT>difft = npdiff(ftimes)<EOL>deltat = npmedian(difft)<EOL>weights_i = npexp(- difft/deltat )<EOL>products = (weights_i*sigma_i[<NUM_LIT:1>:]*sigma_j[<NUM_LIT:1>:])<EOL><DEDENT>else:<EOL><INDENT>products = (sigma_i*sigma_j)[<NUM_LIT:1>:]<EOL><DEDENT>stetsonj = (<EOL>npsum(npsign(products) * npsqrt(npabs(products)))<EOL>) / ndet<EOL>return stetsonj<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return npnan<EOL><DEDENT>

This calculates the Stetson index for the magseries, based on consecutive
    pairs of observations.

    Based on Nicole Loncke's work for her Planets and Life certificate at
    Princeton in 2014.

    Parameters
    ----------

    ftimes,fmags,ferrs : np.array
        The input mag/flux time-series with all non-finite elements removed.

    weightbytimediff : bool
        If this is True, the Stetson index for any pair of mags will be
        reweighted by the difference in times between them using the scheme in
        Fruth+ 2012 and Zhange+ 2003 (as seen in Sokolovsky+ 2017)::

            w_i = exp(- (t_i+1 - t_i)/ delta_t )

    Returns
    -------

    float
        The calculated Stetson J variability index.


<EOL>if ferrs is None:<EOL><INDENT>ferrs = npfull_like(fmags, <NUM_LIT>)<EOL><DEDENT>ndet = len(fmags)<EOL>if ndet > <NUM_LIT:9>:<EOL><INDENT>medmag = npmedian(fmags)<EOL>delta_prefactor = (ndet/(ndet - <NUM_LIT:1>))<EOL>sigma_i = delta_prefactor*(fmags - medmag)/ferrs<EOL>stetsonk = (<EOL>npsum(npabs(sigma_i))/(npsqrt(npsum(sigma_i*sigma_i))) *<EOL>(ndet**(-<NUM_LIT:0.5>))<EOL>)<EOL>return stetsonk<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return npnan<EOL><DEDENT>

This calculates the Stetson K index (a robust measure of the kurtosis).

    Parameters
    ----------

    fmags,ferrs : np.array
        The input mag/flux time-series to process. Must have no non-finite
        elems.

    Returns
    -------

    float
        The Stetson K variability index.


def lightcurve_moments(ftimes, fmags, ferrs):

ndet = len(fmags)<EOL>if ndet > <NUM_LIT:9>:<EOL><INDENT>series_median = npmedian(fmags)<EOL>series_wmean = (<EOL>npsum(fmags*(<NUM_LIT:1.0>/(ferrs*ferrs)))/npsum(<NUM_LIT:1.0>/(ferrs*ferrs))<EOL>)<EOL>series_mad = npmedian(npabs(fmags - series_median))<EOL>series_stdev = <NUM_LIT>*series_mad<EOL>series_skew = spskew(fmags)<EOL>series_kurtosis = spkurtosis(fmags)<EOL>series_above1std = len(fmags[fmags > (series_median + series_stdev)])<EOL>series_below1std = len(fmags[fmags < (series_median - series_stdev)])<EOL>series_beyond1std = (series_above1std + series_below1std)/float(ndet)<EOL>series_mag_percentiles = nppercentile(<EOL>fmags,<EOL>[<NUM_LIT>,<NUM_LIT:10>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>]<EOL>)<EOL>return {<EOL>'<STR_LIT>':series_median,<EOL>'<STR_LIT>':series_wmean,<EOL>'<STR_LIT>':series_mad,<EOL>'<STR_LIT>':series_stdev,<EOL>'<STR_LIT>':series_skew,<EOL>'<STR_LIT>':series_kurtosis,<EOL>'<STR_LIT>':series_beyond1std,<EOL>'<STR_LIT>':series_mag_percentiles,<EOL>'<STR_LIT>': series_mag_percentiles[<NUM_LIT:8>] - series_mag_percentiles[<NUM_LIT:3>],<EOL>}<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return None<EOL><DEDENT>

This calculates the weighted mean, stdev, median, MAD, percentiles, skew,
    kurtosis, fraction of LC beyond 1-stdev, and IQR.

    Parameters
    ----------

    ftimes,fmags,ferrs : np.array
        The input mag/flux time-series with all non-finite elements removed.

    Returns
    -------

    dict
        A dict with all of the light curve moments calculated.


def lightcurve_flux_measures(ftimes, fmags, ferrs, magsarefluxes=False):

ndet = len(fmags)<EOL>if ndet > <NUM_LIT:9>:<EOL><INDENT>if magsarefluxes:<EOL><INDENT>series_fluxes = fmags<EOL><DEDENT>else:<EOL><INDENT>series_fluxes = <NUM_LIT>**(-<NUM_LIT>*fmags)<EOL><DEDENT>series_flux_median = npmedian(series_fluxes)<EOL>series_flux_percent_amplitude = (<EOL>npmax(npabs(series_fluxes))/series_flux_median<EOL>)<EOL>series_flux_percentiles = nppercentile(<EOL>series_fluxes,<EOL>[<NUM_LIT>,<NUM_LIT:10>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>,<NUM_LIT>]<EOL>)<EOL>series_frat_595 = (<EOL>series_flux_percentiles[-<NUM_LIT:1>] - series_flux_percentiles[<NUM_LIT:0>]<EOL>)<EOL>series_frat_1090 = (<EOL>series_flux_percentiles[-<NUM_LIT:2>] - series_flux_percentiles[<NUM_LIT:1>]<EOL>)<EOL>series_frat_175825 = (<EOL>series_flux_percentiles[-<NUM_LIT:3>] - series_flux_percentiles[<NUM_LIT:2>]<EOL>)<EOL>series_frat_2575 = (<EOL>series_flux_percentiles[-<NUM_LIT:4>] - series_flux_percentiles[<NUM_LIT:3>]<EOL>)<EOL>series_frat_325675 = (<EOL>series_flux_percentiles[-<NUM_LIT:5>] - series_flux_percentiles[<NUM_LIT:4>]<EOL>)<EOL>series_frat_4060 = (<EOL>series_flux_percentiles[-<NUM_LIT:6>] - series_flux_percentiles[<NUM_LIT:5>]<EOL>)<EOL>series_flux_percentile_ratio_mid20 = series_frat_4060/series_frat_595<EOL>series_flux_percentile_ratio_mid35 = series_frat_325675/series_frat_595<EOL>series_flux_percentile_ratio_mid50 = series_frat_2575/series_frat_595<EOL>series_flux_percentile_ratio_mid65 = series_frat_175825/series_frat_595<EOL>series_flux_percentile_ratio_mid80 = series_frat_1090/series_frat_595<EOL>series_percent_difference_flux_percentile = (<EOL>series_frat_595/series_flux_median<EOL>)<EOL>series_percentile_magdiff = -<NUM_LIT>*nplog10(<EOL>series_percent_difference_flux_percentile<EOL>)<EOL>return {<EOL>'<STR_LIT>':series_flux_median,<EOL>'<STR_LIT>':series_flux_percent_amplitude,<EOL>'<STR_LIT>':series_flux_percentiles,<EOL>'<STR_LIT>':series_flux_percentile_ratio_mid20,<EOL>'<STR_LIT>':series_flux_percentile_ratio_mid35,<EOL>'<STR_LIT>':series_flux_percentile_ratio_mid50,<EOL>'<STR_LIT>':series_flux_percentile_ratio_mid65,<EOL>'<STR_LIT>':series_flux_percentile_ratio_mid80,<EOL>'<STR_LIT>':series_percentile_magdiff,<EOL>}<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return None<EOL><DEDENT>

This calculates percentiles and percentile ratios of the flux.

    Parameters
    ----------

    ftimes,fmags,ferrs : np.array
        The input mag/flux time-series with all non-finite elements removed.

    magsarefluxes : bool
        If the `fmags` array actually contains fluxes, will not convert `mags`
        to fluxes before calculating the percentiles.

    Returns
    -------

    dict
        A dict with all of the light curve flux percentiles and percentile
        ratios calculated.


def lightcurve_ptp_measures(ftimes, fmags, ferrs):

ndet = len(fmags)<EOL>if ndet > <NUM_LIT:9>:<EOL><INDENT>timediffs = npdiff(ftimes)<EOL>nzind = npnonzero(timediffs)<EOL>ftimes, fmags, ferrs = ftimes[nzind], fmags[nzind], ferrs[nzind]<EOL>ndet = ftimes.size<EOL>timediffs = npdiff(ftimes)<EOL>p2p_abs_magdiffs = npabs(npdiff(fmags))<EOL>p2p_squared_magdiffs = npdiff(fmags)*npdiff(fmags)<EOL>robstd = npmedian(npabs(fmags - npmedian(fmags)))*<NUM_LIT><EOL>robvar = robstd*robstd<EOL>eta_robust = npmedian(p2p_abs_magdiffs)/robvar<EOL>eta_robust = eta_robust/(ndet - <NUM_LIT:1.0>)<EOL>eta_normal = npsum(p2p_squared_magdiffs)/npvar(fmags)<EOL>eta_normal = eta_normal/(ndet - <NUM_LIT:1.0>)<EOL>timeweights = <NUM_LIT:1.0>/(timediffs*timediffs)<EOL>eta_uneven_normal = (<EOL>(npsum(timeweights*p2p_squared_magdiffs) /<EOL>(npvar(fmags) * npsum(timeweights)) ) *<EOL>npmean(timeweights) *<EOL>(ftimes.max() - ftimes.min())*(ftimes.max() - ftimes.min())<EOL>)<EOL>eta_uneven_robust = (<EOL>(npsum(timeweights*p2p_abs_magdiffs) /<EOL>(robvar * npsum(timeweights)) ) *<EOL>npmedian(timeweights) *<EOL>(ftimes[-<NUM_LIT:1>] - ftimes[<NUM_LIT:0>])*(ftimes[-<NUM_LIT:1>] - ftimes[<NUM_LIT:0>])<EOL>)<EOL>return {<EOL>'<STR_LIT>':eta_normal,<EOL>'<STR_LIT>':eta_robust,<EOL>'<STR_LIT>':eta_uneven_normal,<EOL>'<STR_LIT>':eta_uneven_robust<EOL>}<EOL><DEDENT>else:<EOL><INDENT>return None<EOL><DEDENT>

This calculates various point-to-point measures (`eta` in Kim+ 2014).

    Parameters
    ----------

    ftimes,fmags,ferrs : np.array
        The input mag/flux time-series with all non-finite elements removed.

    Returns
    -------

    dict
        A dict with values of the point-to-point measures, including the `eta`
        variability index (often used as its inverse `inveta` to have the same
        sense as increasing variability index -> more likely a variable star).


def nonperiodic_lightcurve_features(times, mags, errs, magsarefluxes=False):

<EOL>finiteind = npisfinite(times) & npisfinite(mags) & npisfinite(errs)<EOL>ftimes, fmags, ferrs = times[finiteind], mags[finiteind], errs[finiteind]<EOL>nzind = npnonzero(ferrs)<EOL>ftimes, fmags, ferrs = ftimes[nzind], fmags[nzind], ferrs[nzind]<EOL>ndet = len(fmags)<EOL>if ndet > <NUM_LIT:9>:<EOL><INDENT>moments = lightcurve_moments(ftimes, fmags, ferrs)<EOL>fluxmeasures = lightcurve_flux_measures(ftimes, fmags, ferrs,<EOL>magsarefluxes=magsarefluxes)<EOL>ptpmeasures = lightcurve_ptp_measures(ftimes, fmags, ferrs)<EOL>mintime, maxtime = npmin(ftimes), npmax(ftimes)<EOL>timelength = maxtime - mintime<EOL>series_amplitude = <NUM_LIT:0.5>*(npmax(fmags) - npmin(fmags))<EOL>fitcoeffs = nppolyfit(ftimes, fmags, <NUM_LIT:1>, w=<NUM_LIT:1.0>/(ferrs*ferrs))<EOL>series_linear_slope = fitcoeffs[<NUM_LIT:1>]<EOL>rolled_fmags = nproll(fmags,<NUM_LIT:1>)<EOL>series_magratio = (<EOL>(npmax(fmags) - moments['<STR_LIT>']) / (npmax(fmags) - npmin(fmags) )<EOL>)<EOL>measures = {<EOL>'<STR_LIT>':fmags.size,<EOL>'<STR_LIT>':mintime,<EOL>'<STR_LIT>':maxtime,<EOL>'<STR_LIT>':timelength,<EOL>'<STR_LIT>':series_amplitude,<EOL>'<STR_LIT>':ndet/timelength,<EOL>'<STR_LIT>':series_linear_slope,<EOL>'<STR_LIT>':series_magratio,<EOL>}<EOL>if moments:<EOL><INDENT>measures.update(moments)<EOL><DEDENT>if ptpmeasures:<EOL><INDENT>measures.update(ptpmeasures)<EOL><DEDENT>if fluxmeasures:<EOL><INDENT>measures.update(fluxmeasures)<EOL><DEDENT>return measures<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return None<EOL><DEDENT>

This calculates the following nonperiodic features of the light curve,
    listed in Richards, et al. 2011):

    - amplitude
    - beyond1std
    - flux_percentile_ratio_mid20
    - flux_percentile_ratio_mid35
    - flux_percentile_ratio_mid50
    - flux_percentile_ratio_mid65
    - flux_percentile_ratio_mid80
    - linear_trend
    - max_slope
    - median_absolute_deviation
    - median_buffer_range_percentage
    - pair_slope_trend
    - percent_amplitude
    - percent_difference_flux_percentile
    - skew
    - stdev
    - timelength
    - mintime
    - maxtime

    Parameters
    ----------

    times,mags,errs : np.array
        The input mag/flux time-series to process.

    magsarefluxes : bool
        If True, will treat values in `mags` as fluxes instead of magnitudes.

    Returns
    -------

    dict
        A dict containing all of the features listed above.


def gilliland_cdpp(times, mags, errs,<EOL>windowlength=<NUM_LIT>,<EOL>polyorder=<NUM_LIT:2>,<EOL>binsize=<NUM_LIT>,  <EOL>sigclip=<NUM_LIT>,<EOL>magsarefluxes=False,<EOL>**kwargs):

<EOL>if errs is None:<EOL><INDENT>errs = <NUM_LIT>*mags<EOL><DEDENT>find = npisfinite(times) & npisfinite(mags) & npisfinite(errs)<EOL>ftimes = times[find]<EOL>fmags = mags[find]<EOL>ferrs = errs[find]<EOL>if ftimes.size < (<NUM_LIT:3>*windowlength):<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return npnan<EOL><DEDENT>smoothed = savgol_filter(fmags, windowlength, polyorder, **kwargs)<EOL>subtracted = fmags - smoothed<EOL>stimes, smags, serrs = sigclip_magseries(ftimes, subtracted, ferrs,<EOL>magsarefluxes=magsarefluxes)<EOL>binned = time_bin_magseries_with_errs(stimes, smags, serrs,<EOL>binsize=binsize,<EOL>minbinelems=<NUM_LIT:7>)<EOL>bmags = binned['<STR_LIT>']<EOL>cdpp = npstd(bmags) * <NUM_LIT><EOL>return cdpp<EOL>

This calculates the CDPP of a timeseries using the method in the paper:

    Gilliland, R. L., Chaplin, W. J., Dunham, E. W., et al. 2011, ApJS, 197, 6
    (http://adsabs.harvard.edu/abs/2011ApJS..197....6G)

    The steps are:

    - pass the time-series through a Savitsky-Golay filter.

      - we use `scipy.signal.savgol_filter`, `**kwargs` are passed to this.

      - also see: http://scipy.github.io/old-wiki/pages/Cookbook/SavitzkyGolay.

      - the `windowlength` is the number of LC points to use (Kepler uses 2 days
        = (1440 minutes/day / 30 minutes/LC point) x 2 days = 96 -> 97 LC
        points).

      - the `polyorder` is a quadratic by default.

    - subtract the smoothed time-series from the actual light curve.

    - sigma clip the remaining LC.

    - get the binned mag series by averaging over 6.5 hour bins, only retaining
      bins with at least 7 points.

    - the standard deviation of the binned averages is the CDPP.

    - multiply this by 1.168 to correct for over-subtraction of white-noise.

    Parameters
    ----------

    times,mags,errs : np.array
        The input mag/flux time-series to calculate CDPP for.

    windowlength : int
        The smoothing window size to use.

    polyorder : int
        The polynomial order to use in the Savitsky-Golay smoothing.

    binsize : int
        The bin size to use for binning the light curve.

    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.

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

    kwargs : additional kwargs
        These are passed directly to `scipy.signal.savgol_filter`.

    Returns
    -------

    float
        The calculated CDPP value.


def all_nonperiodic_features(times, mags, errs,<EOL>magsarefluxes=False,<EOL>stetson_weightbytimediff=True):

<EOL>finiteind = npisfinite(times) & npisfinite(mags) & npisfinite(errs)<EOL>ftimes, fmags, ferrs = times[finiteind], mags[finiteind], errs[finiteind]<EOL>nzind = npnonzero(ferrs)<EOL>ftimes, fmags, ferrs = ftimes[nzind], fmags[nzind], ferrs[nzind]<EOL>xfeatures = nonperiodic_lightcurve_features(times, mags, errs,<EOL>magsarefluxes=magsarefluxes)<EOL>stetj = stetson_jindex(ftimes, fmags, ferrs,<EOL>weightbytimediff=stetson_weightbytimediff)<EOL>stetk = stetson_kindex(fmags, ferrs)<EOL>xfeatures.update({'<STR_LIT>':stetj,<EOL>'<STR_LIT>':stetk})<EOL>return xfeatures<EOL>

This rolls up the feature functions above and returns a single dict.

    NOTE: this doesn't calculate the CDPP to save time since binning and
    smoothing takes a while for dense light curves.

    Parameters
    ----------

    times,mags,errs : np.array
        The input mag/flux time-series to calculate CDPP for.

    magsarefluxes : bool
        If True, indicates `mags` is actually an array of flux values.

    stetson_weightbytimediff : bool
        If this is True, the Stetson index for any pair of mags will be
        reweighted by the difference in times between them using the scheme in
        Fruth+ 2012 and Zhange+ 2003 (as seen in Sokolovsky+ 2017)::

            w_i = exp(- (t_i+1 - t_i)/ delta_t )

    Returns
    -------

    dict
        Returns a dict with all of the variability features.